Napisany paź-22-2008

tablica haszująca w PHP

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

Tagi : , , , ,

Napisz komentarz