2009-05-08 25 views
37

Jak utworzyć mapę Hashmap w C od podstaw? Jakie byłyby parametry brane pod uwagę i jak byś przetestował listę niedziałającą, jaka to jest dobra? Jak w przypadku testów porównawczych, które należy uruchomić, zanim powiesz, że twoja mapa skrótu jest kompletna.Wdrażanie HashMap

Odpowiedz

50

Dobrze jeśli znasz podstawy za nimi, to nie powinno być zbyt trudne.

Generalnie tworzy się tablicę o nazwie "bucket", która zawiera klucz i wartość, z opcjonalnym wskaźnikiem do utworzenia listy połączonej.

Po uzyskaniu dostępu do tabeli skrótów za pomocą klucza, przetwarzany jest klucz z niestandardową funkcją mieszającą, która zwraca liczbę całkowitą. Następnie bierzesz moduł wyniku i jest to lokalizacja twojego indeksu tablicy lub "wiadra". Następnie sprawdzasz klucz odhaczony za pomocą zapisanego klucza, a jeśli pasuje, to znalazłeś właściwe miejsce.

W przeciwnym razie wystąpiła "kolizja" i musi ona przeszukiwać listę połączoną i porównywać klucze do momentu dopasowania. (zauważ, że niektóre implementacje używają drzewa binarnego zamiast listy połączonej do kolizji).

Sprawdź to realizację szybko tabeli hash:

http://attractivechaos.awardspace.com/khash.h.html

+2

Oprócz LL i drzew, możesz mieć mapę mieszającą na wiadro, które wykorzystuje inny skrót do obsługi kolizji. – sudo

5

Najlepsze podejście zależy od oczekiwanej dystrybucji kluczy i liczby kolizji . Jeśli spodziewamy się stosunkowo niewielu kolizji, to naprawdę nie ma znaczenia, która metoda jest używana. Jeśli spodziewana jest duża liczba kolizji, oczekiwane jest, które z nich będą zależne od kosztu ponownego przeprogramowania lub od manipulowania rozszerzalną strukturą danych zasobnika.

Ale tutaj jest przykład kodu źródłowego An Hashmap Implementation in C

+1

W późniejszym poście mówi, że musimy obsłużyć również kolizji. Ponadto implementacja mieszania ma table_size, która jest jak poprawiona. Jeśli chcemy dynamicznie zwiększać rozmiar niedziałającego, bez wiedzy programisty o jego wykonaniu. Czy możesz coś zasugerować? – Thunderboltz

+1

Zmiana rozmiaru przestrzeni kluczy oznacza zmianę funkcji skrótu lub co najmniej parametrów funkcji i ponowne wprowadzenie wszystkich wpisów. Każda mapa o różnej wielkości wymaga innego zestawu funkcji mieszających w celu utrzymania pożądanej dystrybucji kluczy. – TStamper

+4

Link jest teraz uszkodzony –

1

istnieją inne mechanizmy do obsługi przepełnienia niż prosty poglądach połączonej listy wpisów, które np przelewowych marnuje dużo pamięci.

Który z używanych mechanizmów zależy między innymi od tego, czy można wybrać funkcję skrótu i ​​czy można wybrać więcej niż jeden (aby zaimplementować np. Podwójne haszowanie do obsługi kolizji); jeśli spodziewasz się często dodawać elementy lub jeśli mapa jest statyczna po wypełnieniu; jeśli zamierzasz usunąć przedmioty lub nie; ...

Najlepszym sposobem wdrożenia tego jest najpierw przemyślenie wszystkich tych parametrów, a następnie nie kodowanie go samemu, ale wybór dojrzałej istniejącej implementacji. Google ma kilka dobrych wdrożeń - np. http://code.google.com/p/google-sparsehash/

+3

O ile dotyczy to algorytmów, sparsehash jest implementacją hashmap w C++. Jeśli szukasz czystych przedwzmacniaczy z przedwzmacniaczem C, szukaj gdzie indziej. –

3

Głównym celem hashmap jest przechowywanie zestawu danych i zapewnienie na nim niemal stałych wyszukiwań czasu przy użyciu unikalnego klucza. Istnieją dwa style wdrożenia hashmap:

  • Oddzielna łańcuchowym: jeden z tablicą wiader (związany listy)
  • Otwarte adresowania: pojedyncza tablica przydzielane z dodatkową przestrzeń tak kolizje indeks może być rozwiązany przez umieszczenie wejście w sąsiednim gnieździe.

Oddzielne łańcuchowanie jest preferowane, jeśli mieszania może mieć słaba funkcja skrótu, nie jest pożądane wstępne przydzielenie pamięci dla potencjalnie nieużywanych gniazd lub pozycje mogą mieć zmienny rozmiar. Ten typ mieszańca może nadal działać względnie wydajnie, nawet gdy współczynnik obciążenia przekracza 1,0.Oczywiście w każdym wpisie jest wymagana dodatkowa pamięć do przechowywania powiązanych wskaźników listy.

Hashmy z adresowaniem otwartym mają potencjalne zalety wydajnościowe, gdy współczynnik obciążenia jest utrzymywany poniżej pewnego progu (zwykle około 0,7) i używana jest dość dobra funkcja skrótu. Dzieje się tak dlatego, że unikają potencjalnych pomyłek pamięci podręcznej i wielu niewielkich alokacji pamięci skojarzonych z listą połączoną i wykonują wszystkie operacje w sąsiadującej, wstępnie przydzielonej tablicy. Iteracja przez wszystkie elementy jest również tańsza. Połów jest hashmap za pomocą otwartego adresowania musi być ponownie przydzielony do większego rozmiaru i ponownie zmagazynowany, aby utrzymać idealny współczynnik obciążenia, lub napotykają znaczącą karę wykonania. Ich współczynnik obciążenia nie może przekroczyć 1,0.

Niektóre kluczowe wskaźniki wydajności, aby ocenić podczas tworzenia hashmap obejmowałyby:

  • Maksymalny współczynnik obciążenia
  • Średnia liczba kolizji na wstawienie
  • Dystrybucja kolizji: nierównej dystrybucji (klastrów) może wskazywać biedny funkcja skrótu.
  • Względny czas dla różnych operacji: wstaw, pobierz, usuń istniejące i nieistniejące wpisy.

Oto elastyczna implementacja systemu operacyjnego. Użyłem otwartego adresowania i liniowego sondowania do rozwiązywania kolizji.

https://github.com/DavidLeeds/hashmap