Oto kilka kompromisów można zrobić. Załóżmy, że masz dwa zestawy elementów, S i T, rysowane z wszechświata U. Chcemy określić, czy S≥T. W jednym z podanych przykładów, mamy
S = {1,2,3,4}
T = {3,4,5}
U = {1,2,3,4,5 }
1. posortowanych list (lub zrównoważone drzewo wyszukiwania)
metody zaproponowanej przez większość plakatów. Jeśli masz już posortowane listy lub nie zależy im na czasie ich tworzenia (powiedzmy, nie robisz tak często), to ten algorytm jest w zasadzie liniowym czasem i przestrzenią. Zazwyczaj jest to najlepsza opcja.
(Żeby być fair w stosunku do innych wyborów tutaj, czas i przestrzeń granice powinny faktycznie zawierają czynniki „Log | U |” w odpowiednich miejscach, ale zwykle nie jest to relivant)
Struktury danych: Posortowana lista dla każdego z S i T. Albo zbalansowane drzewo wyszukiwania (np. Drzewo AVL, drzewo czerwono-czarne, B +), które może być iterowane w stałej przestrzeni.
Algorytm: Dla każdego elementu w T, poszukaj S liniowo dla tego elementu. Zapamiętaj miejsce, w którym przerwałeś każde wyszukiwanie i rozpocznij następne wyszukiwanie. Jeśli każde wyszukiwanie powiedzie się, to S≥T.
Czas złożoność: około O ( | S | Logowanie | S | + | T | Logowanie | T | ) tworzyć posortowane list, O ( max (| S |, | T |) ) w celu porównania.
przestrzeni złożoność: około O ( | S | + | t | )
Przykład (C++)
#include <set>
#include <algorithm>
std::set<int> create_S()
{
std::set<int> S;
// note: std::set will put these in order internally
S.insert(3);
S.insert(2);
S.insert(4);
S.insert(1);
return S;
}
std::set<int> create_T()
{
std::set<int> T;
// note std::set will put these in order internally
T.insert(4);
T.insert(3);
T.insert(5);
return T;
}
int main()
{
std::set<int> S=create_S();
std::set<int> T=create_T();
return std::includes(S.begin(),S.end(), T.begin(), T.end());
}
2. Tabele Hash
lepsze średni czas złożoności niż przy posortowanej liście można uzyskać za pomocą tabel mieszających. Ulepszone zachowanie w przypadku dużych zestawów wiąże się z ogólnie niższą wydajnością w przypadku małych zestawów.
Podobnie jak w przypadku list posortowanych, ignoruję złożoność wynikającą z rozmiaru wszechświata.
Struktura danych: Tabela mieszania dla S, wszystko szybko iterowalny T.
algorytmu: Insert każdy element S w swoim hashtable. Następnie dla każdego elementu w T sprawdź, czy znajduje się on w tabeli mieszania.
Czas złożoność: O ( | S | + | T | ) założyć, O ( | T | ) do porównania.
Przestrzeń złożoność: O ( | S | + | T | )
Przykład (C++)
#include <tr1/unordered_set>
std::tr1::unordered_set<int> create_S()
{
std::tr1::unordered_set<int> S;
S.insert(3);
S.insert(2);
S.insert(4);
S.insert(1);
return S;
}
std::tr1::unordered_set<int> create_T()
{
std::tr1::unordered_set<int> T;
T.insert(4);
T.insert(3);
T.insert(5);
return T;
}
bool includes(const std::tr1::unordered_set<int>& S,
const std::tr1::unordered_set<int>& T)
{
for (std::tr1::unordered_set<int>::const_iterator iter=T.begin();
iter!=T.end();
++iter)
{
if (S.find(*iter)==S.end())
{
return false;
}
}
return true;
}
int main()
{
std::tr1::unordered_set<int> S=create_S();
std::tr1::unordered_set<int> T=create_T();
return includes(S,T);
}
3. Bit ustawia
Jeśli urządzenie wszechświat jest szczególnie mały (załóżmy, że możesz mieć tylko elementy 0-32), wtedy bitset jest rozsądnym rozwiązaniem. Czas działania (ponownie, zakładając, że nie zależy Ci na czasie konfiguracji) jest zasadniczo stały. W przypadku, gdy zależy Ci na konfiguracji, wciąż jest to szybsze niż tworzenie posortowanej listy.
Niestety, zestawy bitowe stają się nieporęczne bardzo szybko nawet w przypadku umiarkowanego rozmiaru wszechświata.
Struktura danych: wektor bitowy (zwykle liczba całkowita) dla każdego z S i T. Możemy kodować S = 11110 i T = 00111 w podanym przykładzie.
Algorytm: Oblicz przecięcia obliczając logicznie i z każdego bitu w S z odpowiedniego bitu T. Jeżeli wynik wynosi T, a następnie S≥T.
Czas złożoność: O ( | U | + | S | + | T | ) do konfiguracji O ( | U | ) do porównania.
przestrzeni złożoność: O ( | U | )
Przykład: (C++)
#include <bitset>
// bitset universe always starts at 0, so create size 6 bitsets for demonstration.
// U={0,1,2,3,4,5}
std::bitset<6> create_S()
{
std::bitset<6> S;
// Note: bitsets don't care about order
S.set(3);
S.set(2);
S.set(4);
S.set(1);
return S;
}
std::bitset<6> create_T()
{
std::bitset<6> T;
// Note: bitsets don't care about order
T.set(4);
T.set(3);
T.set(5);
return T;
}
int main()
{
std::bitset<6> S=create_S();
std::bitset<6> T=create_T();
return S & T == T;
}
4. Bloom filters
Wszystkie zalety bitsets prędkość , bez brzydkiego ograniczenia rozmiaru wszechświata. Tylko jedna słabsza strona: czasami (często, jeśli nie jesteś ostrożny) dajesz złą odpowiedź: Jeśli algorytm mówi "nie", to zdecydowanie nie masz włączenia. Jeśli algorytm mówi "tak", możesz lub nie. Lepszą dokładność można uzyskać, wybierając duży rozmiar filtra i dobre funkcje skrótu.
Biorąc pod uwagę, że mogą i będą udzielać błędnych odpowiedzi, filtry Blooma mogą brzmieć jak okropny pomysł. Mają jednak określone zastosowania. Zasadniczo można by użyć filtrów Blooma, aby szybko wykonać wiele testów integracji, a następnie użyć wolniej deterministycznej metody, aby zagwarantować poprawność w razie potrzeby. Powiązany artykuł Wikipedii wspomina niektóre aplikacje korzystające z filtrów Bloom.
Struktura danych: A Bloom filter to fantazyjny bitset. Musisz wcześniej wybrać rozmiar filtra i funkcje mieszania.
Algorytm (schemat): Inicjalizacja bitset na 0. Aby dodać element do filtra bloom mieszania go z każdej funkcji mieszającej i ustawić odpowiedni bit w bitset. Określanie włączenia działa tak samo, jak w przypadku zestawów bitowych.
Czas złożoność: O ( rozmiar filtra)
przestrzeni złożoność: O ( rozmiar filtra)
Prawdopodobieństwo poprawności: Zawsze popraw, jeśli odpowiada "S" s nie obejmują T ". Coś takiego jak 0.6185^(| S | x | T |/( filter rozmiar))) jeśli odpowiada "S zawiera T".W szczególności rozmiar filtra musi być proporcjonalny do iloczynu | S | i | T | dać rozsądne prawdopodobieństwo dokładności.
Kilka różnych języków dostarczy Ci wielu różnych odpowiedzi. – GManNickG
Czy Twoja lista jest zamówiona? – Anna
Co masz na myśli przez "podzbiór"? Na co zwracałaby Twoja operacja podzestawu (1,2,3), (2,1)? –