Dynamiczne doskonałe mieszanie

W informatyce dynamiczne doskonałe mieszanie jest techniką programistyczną służącą do rozwiązywania kolizji w strukturze danych tablicy skrótów . Technika ta, choć zapytania , wstawić i usunąć duży zestaw elementów. wymaga więcej pamięci niż jej odpowiedniki z tablicą skrótów, jest przydatna w sytuacjach, w których należy wykonać szybkie

Detale

Sprawa statyczna

Schemat FKS

Problem optymalnego mieszania statycznego został po raz pierwszy ogólnie rozwiązany przez Fredmana, Komlósa i Szemerédiego. W swoim artykule z 1984 roku szczegółowo opisują dwupoziomowy schemat tablicy mieszającej, w którym każdy segment tablicy mieszającej (pierwszego poziomu) odpowiada oddzielnej tabeli mieszającej drugiego poziomu. Klucze są haszowane dwukrotnie — pierwsza wartość skrótu jest odwzorowywana na określony segment w tabeli skrótów pierwszego poziomu; druga wartość skrótu podaje pozycję tego wpisu w tabeli skrótów drugiego poziomu tego zasobnika. Gwarantuje się, że tabela drugiego poziomu będzie wolna od kolizji (tj. doskonałego haszowania ) po zbudowaniu. W konsekwencji gwarantowany jest koszt wyszukiwania na poziomie O(1) w najgorszym przypadku .

W przypadku statycznym otrzymujemy z wyprzedzeniem zestaw zawierający w sumie x wpisów, z których każdy ma unikalny klucz. Fredman, Komlós i Szemerédi wybierają tabelę skrótów pierwszego poziomu z wiaderkami o rozmiarze .

Aby skonstruować, x wpisów jest rozdzielanych na s segmentów przez funkcję haszującą najwyższego poziomu, gdzie . dla każdego zasobnika z k wpisami przydzielana jest tabela drugiego poziomu ze a jej funkcja skrótu jest wybierana losowo z uniwersalnego zestawu funkcji skrótu , tak aby była bezkolizyjna (tj. doskonała funkcja skrótu ) i przechowywana obok tablicy skrótów. Jeśli losowo wybrana funkcja mieszająca tworzy tabelę z kolizjami, nowa funkcja mieszająca jest wybierana losowo, dopóki nie będzie można zagwarantować bezkolizyjnej tabeli. Wreszcie, przy bezkolizyjnym mieszaniu, k wpisów jest mieszanych w tabeli drugiego poziomu.

Kwadratowy rozmiar przestrzeni zapewnia, że ​​losowe tworzenie tabeli z kolizjami i niezależne od rozmiaru k zapewniając liniowy zamortyzowany czas budowy. Chociaż każda tabela drugiego poziomu wymaga przestrzeni skrótów pierwszego poziomu są rozmieszczone , struktura jako całość zajmuje oczekiwaną ponieważ rozmiary wiader są małe z dużym prawdopodobieństwem .

Funkcja skrótu pierwszego poziomu jest specjalnie dobrana tak, aby dla określonego zestawu x unikalnych wartości kluczy całkowita przestrzeń T używana przez wszystkie tabele skrótów drugiego poziomu oczekiwała miejsca , a dokładniej . Fredman, Komlós i Szemerédi wykazali, że biorąc pod uwagę uniwersalną rodzinę funkcji mieszających, co najmniej połowa z tych funkcji ma tę właściwość.

Przypadek dynamiczny

Dietzfelbinger i in. przedstawić algorytm dynamicznego słownika dodawany przyrostowo do słownika, zapytania o członkostwo zawsze działają w stałym czasie, a zatem w najgorszym przypadku całkowity wymagany O liniowy i oczekiwany zamortyzowany czas wstawiania i usuwania ( stały czas

W dynamicznym przypadku, gdy klucz jest wstawiany do tablicy skrótów, jeśli jego wpis w odpowiedniej podtabeli jest zajęty, wówczas mówi się, że zachodzi kolizja i podtabela jest odbudowywana na podstawie nowej całkowitej liczby wpisów i losowo wybranej funkcji skrótu. Ponieważ współczynnik obciążenia tabeli drugiego poziomu jest utrzymywany na niskim poziomie rzadka, a oczekiwany zamortyzowany koszt wstawiania wynosi . Podobnie, zamortyzowany oczekiwany koszt usunięcia wynosi .

Ponadto ostateczne rozmiary tabeli najwyższego poziomu lub którejkolwiek z podtabel są niepoznawalne w przypadku dynamicznym. Jedną z metod zachowania oczekiwanej w tabeli jest wywołanie pełnej rekonstrukcji, gdy nastąpi wystarczająca liczba Zgodnie z wynikami Dietzfelbingera i in., o ile całkowita liczba wstawień lub usunięć przekracza liczbę elementów w czasie ostatniej konstrukcji, zamortyzowany oczekiwany koszt wstawiania i usuwania pozostaje O ( 1 ) { z uwzględnieniem pełnego ponownego mieszania.

Implementacja dynamicznego doskonałego mieszania przez Dietzfelbingera i in. używa tych koncepcji, a także leniwego usuwania i jest pokazany w pseudokodzie poniżej.

Implementacja pseudokodu

Znajdź

    
     
        
 funkcja  Locate(  x  )  to  j  := h(  x  )  jeśli  (pozycja h  j  (  x  ) podtabeli  T  j  zawiera  x  (nie usunięte))  return  (  x  jest w  S  )  koniec jeśli  inaczej  return  (  x  nie jest w  S  )  koniec inny  koniec 

Wstawić

Podczas wstawiania nowego wpisu x w punkcie j następuje zwiększenie globalnego licznika operacji count .

Jeśli x istnieje w j , ale jest oznaczone jako usunięte, to znak jest usuwany.

Jeśli x istnieje w j lub odbudowywana w podtabeli Tj i nie mieszającą hj jest oznaczone jako usunięte, to mówi się, że zachodzi kolizja, a tabela drugiego poziomu Tj zasobnika j jest z inną losowo wybraną funkcją .

    
    
        
        
        
            
                 
                         
                
            
            
                 
                         
                
                
            
        
    
 funkcja  Insert(  x  )  to  liczba  =  liczba  + 1;  if  (  count  >  M  ) FullRehash(  x  );  koniec jeśli  jeszcze  j  = h(  x  );  if  (Pozycja h  j  (x) podtabeli  T  j  zawiera  x  )  if  (  x  jest zaznaczone jako usunięte) usuń znacznik usuwania;  koniec, jeśli  koniec, jeśli  inaczej  b  j  =  b  j  + 1;  if  (  b  j  <=  m  j  )  jeśli  pozycja h  j  (  x  ) z  T  j  jest pusta przechowuj  x  na pozycji h  j  (  x  ) z  T  j  ;  end if  else  Umieść wszystkie niezaznaczone elementy  T  j  na liście  L  j  ; Dołącz   x  do listy  L  j  ;  b  j  = długość  L  j  ;  powtórz  h  j  = losowo wybrana funkcja w  H  sj  ;  dopóki  h  j  nie jest iniekcyjne na elementach  L  j  ;  dla  wszystkich  y  na liście  L  j  zapisz  y  na pozycji h  j  (  y  ) z  T  j  ;  koniec dla  końca else  koniec, jeśli  jeszcze  m  j  = 2 * max{1,  m  j  };  s  jot  = 2 *  m  jot  * (  m  jot  - 1);  jeśli  suma wszystkich s  j  ≤ 32 *  M  2  /  s  (  M  ) + 4 *  M  Przydziel  s  j  komórek dla  T  j  ; Umieść wszystkie niezaznaczone elementy   T  j  na liście  L  j  ; Dołącz   x  do listy  L  j  ;  b  j  = długość  L  j  ;  powtórz  h  j  = losowo wybrana funkcja w  H  sj  ;  dopóki  h  j  nie jest iniekcyjne na elementach  L  j  ;  dla  wszystkich  y  na liście  L  j  zapisz  y  na pozycji h  j  (  y  ) z  T  j  ;  koniec za  koniec, jeśli  jeszcze  FullRehash(  x  );  koniec inny  koniec inny  koniec inny  koniec inny  koniec 

Usuwać

Usunięcie x oznacza po prostu flagę x jako usuniętą bez usuwania i zwiększa liczbę przyrostów . W przypadku zarówno wstawiania, jak i usuwania, jeśli liczba osiągnie próg M , cała tablica jest odbudowywana, gdzie M jest pewną stałą wielokrotnością rozmiaru S na początku nowej fazy . Tutaj faza odnosi się do czasu między pełnymi przebudowami. Zauważ, że tutaj -1 w „Delete( x )” jest reprezentacją elementu, który nie znajduje się w zbiorze wszystkich możliwych elementów U .

    
     
        
    
 funkcja  Usuń(  x  )  to  liczba  =  liczba  + 1;  j  = godz(  x  );  jeżeli  pozycja h  j  (  x  ) podtabeli  Tj  zawiera  x  oznaczamy  x  jako usunięte;  zakończ, jeśli  w przeciwnym razie  wróć  (x nie jest członkiem S);  koniec else  if  (  count  >=  M  ) FullRehash(-1);  koniec, jeśli  koniec 

Pełna przebudowa

Pełne przebudowanie tablicy S rozpoczyna się najpierw od usunięcia wszystkich elementów oznaczonych jako usunięte, a następnie ustawienia następnej wartości progowej M na pewną stałą wielokrotność rozmiaru S . Funkcja mieszająca, która dzieli S na podzbiory s ( M ), gdzie rozmiar podzbioru j wynosi s j , jest wybierana losowo, dopóki:

Wreszcie, dla każdej podtabeli Tj Tj funkcja , mieszająca hj hj jest wstrzyknięta wielokrotnie losowo wybierana spośród Hsj zostanie na elementy . Oczekiwany czas pełnej przebudowy tablicy S o rozmiarze n to O( n ).

    
    
     
             
    
 funkcja  FullRehash(  x  )  to  Umieść wszystkie niezaznaczone elementy  T  na liście  L  ;  jeśli  (  x  jest w  U  ) dołącz  x  do  L  ;  koniec if  liczba  = długość listy  L  ;  M  = (1 +  do  ) * max {  liczba  , 4};  powtórz  h = losowo wybrana funkcja w  Hs  (M)  ;  dla  wszystkich  j  <  s  (  M  ) utwórz listę  L  j  dla h (  x  ) =  j  ;  b  j  = długość  L  j  ;  m  jot  = 2 *  b  jot  ;  s  jot  = 2 *  m  jot  * (  m  jot  - 1);  koniec  suma wszystkich s  j  ≤ 32 *  M  2  /  s  (  M  ) + 4 *  M  dla  wszystkich  j  <  s  (  M  ) Przydziel miejsce  s  j  dla podtabeli  T  j  ;  powtórz  h  j  = losowo wybrana funkcja w  H  sj  ;  dopóki  h  j  nie jest iniekcyjne na elementach listy  L  j  ;  koniec dla  wszystkich  x  na  liście  L  j  przechowuj  x  na pozycji h  j  (  x  ) z  T  j  ;  koniec za  koniec 

Zobacz też