Tablica haszująca to niezwykła struktura danych. Pozwala ona na odnajdowanie elementów w niej zawartych (np. string’ów) ze złożonością obliczeniową równą O(c). Stąd też bierze się jej największa zaleta – szybkość szukania. Pewnie wielu z Was zadaje sobie pytanie, czym jest ów złożoność obliczeniowa? Wytłumaczę to najprościej jak potrafię. Jest to ilość zasobów (czas procesora, itp.), które musimy użyć w celu rozwiązania naszego problemu.
tablica haszująca w teorii
Podstawę stanowi zwykła tablica. Aby móc efektywnie z niej korzystać musimy dodatkowo zaimplementować 3 algorytmy:
- funkcja numeryzacji klucza
- funkcja mieszająca
- funkcja usuwania kolizji
funkcja numeryzacji klucza – zazwyczaj element, który chcemy umieścić w naszej strukturze danych jest ciągiem znaków, a niektóre języki programowania (Pascal,C) oferują wyłącznie tablice o indeksach numerycznych. Funkcja ta zajmuję się więc odwzorowaniem string’a na integer’a (z dużą wrażliwością na każdy bit wejścia).
funkcja mieszająca – dzięki niej integer zostaje „skrócony” do takiej postaci, w której może być indeksem naszej tablicy. Jest to ważne tam, gdzie rozmiar tablicy jest np. z góry narzucony.
funkcja usuwania kolizji – w sytuacji w której dla dwóch różnych string’ów, otrzymujemy ten sam numer indeksu, pod którym mają one zostać umieszczone, potrzebny nam jest ostatni algorytm. Dba on o odpowiednią obsługę takich sytuacji.
tablica haszująca w praktyce
Prześledźmy nasze algorytmy i ich funkcję na przykładzie string’a „piekna pogoda„.
1. Etap pierwszy – numeryzacja klucza
Tutaj nasz string dostaje swoją reprezentację numeryczną – np. 312432543.
2. Etap drugi – funkcja mieszająca
Nasza tablica może przechować 32 elementy. Stąd też dla wartości 312432543 musimy uzyskać liczbę z przedziału od 0 do 31. Zakładamy, że będzie to 18. Pod tym indeksem umieszczamy nasz string „piekna pogoda”.
3.Etap trzeci – usuwanie kolizji
Jeśli się zdarzy sytuacja, że dla string’a „super dzionek” indeksem jest też 18, to musimy zadbać o to. aby nasze dane nie zostały utracone. Jednym z rozwiązań jest dodatkowa tablica, pod każdym z indeksów tablicy pierwotnej. Daje to następujący rezultat:
tablica[18][0] -> „piekna pogoda”
tablica[18][1] -> „super dzionek”
tablica haszująca w PHP
Na szczęście implementacja tablicy mieszającej w PHP jest bardzo prosta. Popatrzmy na kod klasy:
class HashTable {
public $hash_table;
public function __construct () {
$this->hash_table = array();
}
public function AddElement ($string) {
if ($this->hash_table[md5($string)][0] !== NULL)
$this->hash_table[md5($string)][count($this->hash_table[md5($string)])] = $string;
else
$this->hash_table[md5($string)][0] = $string;
return TRUE;
}
public function DeleteElement ($string) {
if ($this->hash_table[md5($string)][0] !== NULL) {
$size = count($this->hash_table[md5($string)]);
for ($i=0;$i<$size;$i++)
if ($this->hash_table[md5($string)][$i] === $string) {
unset($this->hash_table[md5($string)][$i]);
return TRUE;
}
}
return FALSE;
}
public function ElementExists ($string) {
if ($this->hash_table[md5($string)][0] !== NULL)
foreach ($this->hash_table[md5($string)] as $value)
if ($value === $string)
return TRUE;
return FALSE;
}
}
$hash = new HashTable();
$hash->AddElement('a');
$hash->AddElement('dsa');
$hash->AddElement('adasasd');
$hash->DeleteElement('dsa');
var_dump ($hash);
var_dump ($hash->ElementExists('dsa'));
Pewnie ciężko znaleźć w tym kodzie odseparowane od siebie trzy algorytmy, o których tak dużo pisałem. To prawda, nie widać ich na pierwszy rzut oka. Dlaczego? Ponieważ w PHP mamy dostęp do tablic asocjacyjnych. Stąd brak funkcji numeryzacji klucza. Funkcję mieszającą stanowi md5(). Jak wiecie istnieje małe prawdopodobieństwo, iż znajdą się dwa ciągi znaków o tym samym md5, stąd też funkcja usuwania kolizji polega na przechowywaniu elementów o tym samym 32 bajtowym „skrócie” w dodatkowej tablicy.
uwagi końcowe
Moja implementacja stanowi tylko przykład. Możecie zrezygnować z usuwania kolizji, dodać obsługę wyjątków, na co tylko macie ochotę. Nasuwa się jeszcze jedno pytanie? Gdzie używać? Sprawdzanie dostępności nicków przy rejestracji user’ów jest jedną z możliwości. Mam nadzieję, że ułatwiłem Wam w choć małym stopniu zrozumienie tego zagadnienia.
Chcesz wiedzieć więcej?
Złożoność obliczeniowa:
http://www.ds5.agh.edu.pl/~evolic/badania_op/teoria/ogolnie01.html
http://pl.wikipedia.org/wiki/Z%C5%82o%C5%BCono%C5%9B%C4%87_obliczeniowa
Funkcja numeryzacji klucza:
Poczytaj o metodach
- składanie zygzakowe
- składanie cykliczne z sumowaniem arytmetycznym
Funkcja mieszająca:
Poczytaj o
- metoda randomizacji
- metoda środka kwadratu
- metoda dzielenia
- metoda mnożenia
Funkcja usuwania kolizji:
Poczytaj o
- usuwaniu konfliktów bez obszaru nadmiarowego
- usuwaniu konfliktów z obszarem nadmiarowym
5 Odpowiedzi : “tablica haszująca w PHP”


Czy tablice wbudowane w PHP nie są już czasem tablicami haszującymi?
Moim skromnym zdaniem, tablica asocjacyjna dostępna w PHP po prostu ułatwia stworzenie tablicy haszującej, stanowi bowiem podwaliny do pełnej implementacji wszystkich trzech algorytmów (numeryzacja klucza, usuwanie kolizji, funkcja mieszająca).
Chodzi mi o to, że tablice wbudowane w PHP zostały zaimplemetnowane jako tablice haszujące. Nie wiem czy to wiarygodne źródło, ale jakiś człowiek na tej stronie też tak o tym pisze:
http://stackoverflow.com/questions/3134296/hash-tables-vs-associative-arrays-php
Kod który pokazałeś jest dobry do celów dydaktycznych, ale chyba lepiej go nie używać w produkcji, bo to masło maślane.
Kod, jak trafnie zauważyłeś ma cel czysto dydaktyczny. Tablica haszująca w tym przypadku to zaimplementowana struktura danych, w oparciu o typ danych dostępny w PHP – tablicę asocjacyjną.
Tablica asocjacyjna może być tworzona w oparciu o tablicę haszującą, ale nie musi. Jak jest w PHP, nie sprawdzałem, więc nie wiem. Należałoby zrobić research, zaczynając tutaj: http://pl2.php.net/manual/en/language.types.array.php
No i ok.