hash table c programs implement hash table
Denne vejledning forklarer C ++ Hash-tabeller og Hash-kort. Du vil også lære om applikationer og implementering af Hash-tabel i C ++:
Hashing er en teknik, hvor vi kan kortlægge en stor mængde data til en mindre tabel ved hjælp af en 'hash-funktion'.
Ved hjælp af hashing-teknikken kan vi søge i dataene hurtigere og mere effektivt sammenlignet med andre søgeteknikker som lineær og binær søgning.
Lad os forstå hashing-teknikken med et eksempel i denne vejledning.
=> Læs gennem Easy C ++ træningsserien.
Hvad du vil lære:
Hashing i C ++
Lad os tage et eksempel på et universitetsbibliotek, der huser tusinder af bøger. Bøgerne er arrangeret efter emner, afdelinger osv. Men alligevel vil hver sektion have adskillige bøger, som derved gør søgning efter bøger meget vanskelig.
For at overvinde denne vanskelighed tildeler vi således hver bog et unikt nummer eller en nøgle, så vi med det samme kender placeringen af bogen. Dette opnås faktisk gennem hashing.
Fortsætter vi med vores bibliotekseksempel i stedet for at identificere hver bog baseret på dens afdeling, emne, sektion osv., Der kan resultere i en meget lang streng, beregner vi en unik heltalværdi eller nøgle for hver bog i biblioteket ved hjælp af en unik funktion og opbevar disse nøgler i en separat tabel.
Den unikke funktion, der er nævnt ovenfor, kaldes 'Hash-funktionen' og den separate tabel kaldes 'Hash-tabel'. En hash-funktion bruges til at kortlægge den givne værdi til en bestemt unik nøgle i Hash-tabellen. Dette resulterer i hurtigere adgang til elementer. Jo mere effektiv hashing-funktionen er, desto mere effektiv kortlægges hvert element til den unikke nøgle.
Lad os overveje en hash-funktion h (x) der kortlægger værdien “ x ”Ved“ x% 10 ”I arrayet. For de givne data kan vi konstruere en hash-tabel, der indeholder nøgler eller Hash-koder eller Hashes som vist i nedenstående diagram.
I ovenstående diagram kan vi se, at posterne i arrayet kortlægges til deres positioner i hash-tabellen ved hjælp af en hash-funktion.
Således kan vi sige, at hashing implementeres ved hjælp af to trin som nævnt nedenfor:
# 1) Værdien konverteres til en unik heltalstast eller hash ved hjælp af en hash-funktion. Det bruges som et indeks til at gemme det originale element, der falder ind i hash-tabellen.
I ovenstående diagram er værdi 1 i hashtabellen den unikke nøgle til at gemme element 1 fra dataarrayet angivet på LHS i diagrammet.
#to) Elementet fra dataarrayet er gemt i hash-tabellen, hvor det hurtigt kan hentes ved hjælp af hash-nøglen. I ovenstående diagram så vi, at vi har gemt alle elementerne i hash-tabellen efter at have beregnet deres respektive placeringer ved hjælp af en hash-funktion. Vi kan bruge følgende udtryk til at hente hash-værdier og indeksere.
hash = hash_func(key) index = hash % array_size
Hash-funktion
Vi nævnte allerede, at effektiviteten af kortlægning afhænger af effektiviteten af den hash-funktion, vi bruger.
En hash-funktion skal grundlæggende opfylde følgende krav:
- Let at beregne: En hash-funktion skal være let at beregne de unikke nøgler.
- Mindre kollision: Når elementer svarer til de samme nøgleværdier, opstår der en kollision. Der skal være minimale kollisioner så vidt muligt i hash-funktionen, der bruges. Da kollisioner sandsynligvis vil forekomme, er vi nødt til at anvende passende teknikker til opløsning af kollisioner til at tage os af kollisionerne.
- Ensartet distribution: Hash-funktion skal resultere i en ensartet fordeling af data over hash-tabellen og derved forhindre klyngedannelse.
Hash-tabel C ++
Hash-tabel eller et hash-kort er en datastruktur, der gemmer markører til elementerne i det originale dataarray.
I vores bibliotekseksempel vil hashtabellen til biblioteket indeholde markører til hver af bøgerne i biblioteket.
At have poster i hash-tabellen gør det lettere at søge efter et bestemt element i arrayet.
Som allerede set bruger hash-tabellen en hash-funktion til at beregne indekset i en række skovle eller slots, ved hjælp af hvilke den ønskede værdi kan findes.
Overvej et andet eksempel med følgende dataarray:
Antag, at vi har en hash-tabel i størrelse 10 som vist nedenfor:
Lad os nu bruge hash-funktionen nedenfor.
Hash_code = Key_value % size_of_hash_table
Dette svarer til Hash_code = Nøgleværdi% 10
Ved hjælp af ovenstående funktion kortlægger vi nøgleværdierne til placeringerne af hash-tabellen som vist nedenfor.
gratis virtualiseringssoftware til Windows 10
Dataelement | Hash-funktion | Hash_code |
---|---|---|
22 | 22% 10 = 2 | to |
25 | 25% 10 = 5 | 5 |
27 | 27% 10 = 7 | 7 |
46 | 46% 10 = 6 | 6 |
70 | 70% 10 = 0 | 0 |
89 | 89% 10 = 9 | 9 |
31 | 31% 10 = 1 | 1 |
Ved hjælp af ovenstående tabel kan vi repræsentere hash-tabellen som følger.
Så når vi har brug for at få adgang til et element fra hash-tabellen, vil det bare tage O (1) tid at foretage søgningen.
Kollision
Vi beregner normalt hash-koden ved hjælp af hash-funktionen, så vi kan kortlægge nøgleværdien til hash-koden i hash-tabellen. I ovenstående eksempel på dataarrayet, lad os indsætte en værdi 12. I så fald vil hash_code for nøgleværdi 12 være 2. (12% 10 = 2).
Men i hash-tabellen har vi allerede en kortlægning til nøgleværdi 22 for hash_code 2 som vist nedenfor:
Som vist ovenfor har vi den samme hash-kode for to værdier, 12 og 22, dvs. 2. Når en eller flere nøgleværdier svarer til den samme placering, resulterer det i en kollision. Således er hash-kodeplaceringen allerede optaget af en nøgleværdi, og der er en anden nøgleværdi, der skal placeres på den samme placering.
I tilfælde af hashing, selvom vi har en hash-tabel af meget stor størrelse, vil en kollision sandsynligvis være der. Dette skyldes, at vi generelt finder en lille unik værdi for en stor nøgle, hvorfor det er fuldstændigt muligt for en eller flere værdier at have den samme hash-kode til enhver tid.
I betragtning af at en kollision er uundgåelig ved hashing, bør vi altid se efter måder at forhindre eller løse kollisionen på. Der er forskellige teknikker til opløsning af kollision, som vi kan bruge til at løse kollisionen, der opstår under hashing.
Kollisionsteknikker
Følgende er de teknikker, som vi kan bruge til at løse kollision i hash-tabellen.
Separat lænkning (Open Hashing)
Dette er den mest almindelige teknik til kollisionsopløsning. Dette er også kendt som åben hashing og implementeres ved hjælp af en linket liste.
I separat kædeteknik er hver post i hashtabellen en sammenkædet liste. Når nøglen matcher hash-koden, indtastes den i en liste, der svarer til den pågældende hash-kode. Således når to taster har den samme hash-kode, så indtastes begge poster i den linkede liste.
I ovenstående eksempel er Separat lænkning repræsenteret nedenfor.
Ovenstående diagram repræsenterer sammenkædning. Her bruger vi mod (%) -funktionen. Vi ser, at når to nøgleværdier svarer til den samme hash-kode, så forbinder vi disse elementer til den hash-kode ved hjælp af en linket liste.
Hvis tasterne er jævnt fordelt over hash-tabellen, afhænger de gennemsnitlige omkostninger ved at kigge efter den bestemte nøgle af det gennemsnitlige antal nøgler i den sammenkædede liste. Således forbliver separat kæde effektiv, selv når der er en stigning i antallet af poster end slots.
Det værste tilfælde for separat kæde er, når alle taster svarer til den samme hash-kode og således kun indsættes i en sammenkædet liste. Derfor skal vi slå op for alle poster i hash-tabellen og omkostningerne, der er proportionale med antallet af nøgler i tabellen.
Lineær sondering (åben adressering / lukket hasj)
I åben adressering eller lineær sonderingsteknik lagres alle posteringer i selve hash-tabellen. Når nøgleværdi kortlægges til en hash-kode, og den position, der er peget på med hash-kode, ikke er besat, indsættes nøgleværdien på det sted.
Hvis positionen allerede er optaget, indsættes nøgleværdien ved hjælp af en sonderingssekvens i den næste position, der ikke er besat i hash-tabellen.
For lineær sondering kan hash-funktionen ændre sig som vist nedenfor:
hash = hash% hashTableSize
hash = (hash + 1)% hashTableSize
hash = (hash + 2)% hashTableSize
hash = (hash + 3)% hashTableSize
Vi ser, at i tilfælde af lineær sondering er intervallet mellem slots eller successive sonder konstant, dvs. 1.
I ovenstående diagram ser vi det i 0thplacering vi indtaster 10 ved hjælp af hash-funktionen “hash = hash% hash_tableSize”.
Nu svarer elementet 70 også til placering 0 i hash-tabellen. Men den placering er allerede optaget. Derfor ved hjælp af lineær sondering finder vi den næste placering, der er 1. Da denne placering ikke er besat, placerer vi nøglen 70 på denne placering som vist ved hjælp af en pil.
Den resulterende Hash-tabel er vist nedenfor.
Lineær sondering kan lide under problemet med 'Primary Clustering', hvor der er en chance for, at de kontinuerlige celler kan blive optaget, og sandsynligheden for at indsætte et nyt element bliver reduceret.
Også hvis to elementer får den samme værdi ved den første hash-funktion, følger begge disse elementer den samme probesekvens.
Kvadratisk sondering
Kvadratisk sondering er den samme som lineær sondering, hvor den eneste forskel er det interval, der bruges til sondering. Som navnet antyder, bruger denne teknik ikke-lineær eller kvadratisk afstand til at besætte slots, når der opstår en kollision i stedet for lineær afstand.
I kvadratisk sondering beregnes intervallet mellem slots ved at tilføje en vilkårlig polynomværdi til det allerede hashede indeks. Denne teknik reducerer primær klyngedannelse i væsentlig grad, men forbedres ikke ved sekundær klyngedannelse.
Dobbelt hash
Den dobbelte hashing-teknik svarer til lineær sondering. Den eneste forskel mellem dobbelt hashing og lineær sondering er, at i dobbelt hashing-teknik beregnes det interval, der anvendes til sondering, ved hjælp af to hash-funktioner. Da vi anvender hash-funktionen på nøglen efter hinanden, eliminerer den såvel primær klyngedannelse som sekundær klyngedannelse.
Forskellen mellem lænkning (åben hash) og lineær sondering (åben adressering)
Lænkning (åben hash) | Lineær sondering (åben adressering) |
---|---|
Nøgleværdier kan gemmes uden for tabellen ved hjælp af en separat sammenkædet liste. | Nøgleværdier bør kun gemmes inde i tabellen. |
Antallet af elementer i hash-tabellen kan overstige størrelsen på hash-tabellen. | Antallet af elementer, der findes i hash-tabellen, overstiger ikke antallet af indekser i hash-tabellen. |
Sletning er effektiv i kædeteknik. | Sletning kan være besværlig. Kan undgås, hvis det ikke kræves. |
Da der opretholdes en separat sammenkædet liste for hvert sted, er det plads, der er taget stort. | Da alle poster er placeret i den samme tabel, er plads, der er taget mindre. |
C ++ Hash-tabelimplementering
Vi kan implementere hashing ved hjælp af arrays eller sammenkædede lister til at programmere hash-tabellerne. I C ++ har vi også en funktion kaldet “hash map”, som er en struktur, der ligner en hash-tabel, men hver post er et nøgleværdipar. I C ++ kaldes det hash-kort eller blot et kort. Hash-kort i C ++ er normalt ikke ordnet.
Der er en overskrift defineret i Standard Template Library (STL) af C ++, som implementerer kortets funktionalitet. Vi har dækket STL-kort i detaljer i vores vejledning om STL.
Den følgende implementering er til hashing ved hjælp af de linkede lister som datastruktur for hash-tabellen. Vi bruger også 'Chains' som en teknik til sammenstødsopløsning i denne implementering.
#include #include using namespace std; class Hashing { int hash_bucket; // No. of buckets // Pointer to an array containing buckets list *hashtable; public: Hashing(int V); // Constructor // inserts a key into hash table void insert_key(int val); // deletes a key from hash table void delete_key(int key); // hash function to map values to key int hashFunction(int x) { return (x % hash_bucket); } void displayHash(); }; Hashing::Hashing(int b) { this->hash_bucket = b; hashtable = new list (hash_bucket); } //insert to hash table void Hashing::insert_key(int key) { int index = hashFunction(key); hashtable(index).push_back(key); } void Hashing::delete_key(int key) { // get the hash index for key int index = hashFunction(key); // find the key in (inex)th list list :: iterator i; for (i = hashtable(index).begin(); i != hashtable(index).end(); i++) { if (*i == key) break; } // if key is found in hash table, remove it if (i != hashtable(index).end()) hashtable(index).erase(i); } // display the hash table void Hashing::displayHash() { for (int i = 0; i ' << x; cout << endl; } } // main program int main() { // array that contains keys to be mapped int hash_array() = {11,12,21, 14, 15}; int n = sizeof(hash_array)/sizeof(hash_array(0)); Hashing h(7); // Number of buckets = 7 //insert the keys into the hash table for (int i = 0; i < n; i++) h.insert_key(hash_array(i)); // display the Hash table cout<<'Hash table created:'< Produktion:
Hash-tabel oprettet:
0 -> 21 -> 14
1 -> 15
to
3
4 -> 11
5 -> 12
6
Hash-tabel efter sletning af nøgle 12:
0 -> 21 -> 14
1 -> 15
to
3
4 -> 11
5
6
Outputtet viser en hash-tabel, der er oprettet i størrelse 7. Vi bruger chaining til at løse kollision. Vi viser hash-tabellen efter at have slettet en af tasterne.
Anvendelser af Hashing
# 1) Bekræftelse af adgangskoder: Bekræftelse af adgangskoder udføres normalt ved hjælp af kryptografiske hashfunktioner. Når adgangskoden indtastes, beregner systemet kodeordets hash og sendes derefter til serveren til verifikation. På serveren gemmes hashværdierne for de originale adgangskoder.
# 2) Datastrukturer: Forskellige datastrukturer som unordered_set og unordered_map i C ++, ordbøger i python eller C #, HashSet og hash-kort i Java bruger alle nøgleværdipar, hvor nøgler er unikke værdier. Værdierne kan være de samme for forskellige taster. Hashing bruges til at implementere disse datastrukturer.
# 3) Beskedfordøjelse: Dette er endnu en applikation, der bruger en kryptografisk hash. I fordøjelser af meddelelser beregner vi en hash til data, der sendes og modtages eller endog filer, og sammenligner dem med de gemte værdier for at sikre, at der ikke manipuleres med datafilerne. Den mest almindelige algoritme her er “SHA 256”.
# 4) Compiler-drift: Når kompilatoren kompilerer et program, gemmes nøgleordene til programmeringssprog forskelligt fra de andre identifikationer. Compileren bruger en hash-tabel til lagring af disse nøgleord.
# 5) Databaseindeksering: Hash-tabeller bruges til databaseindeksering og diskbaserede datastrukturer.
# 6) Associerede arrays: Associerede arrays er arrays, hvis indekser er af en anden datatype end heltal-lignende strenge eller andre objekttyper. Hash-tabeller kan bruges til implementering af associerende arrays.
Konklusion
Hashing er den mest anvendte datastruktur, da det tager konstant tid O (1) for indsættelse, sletning og søgning. Hashing implementeres for det meste ved hjælp af en hash-funktion, der beregner en unik mindre nøgleværdi til store dataindgange. Vi kan implementere hashing ved hjælp af arrays og linkede lister.
Når en eller flere dataposter svarer til de samme værdier af nøgler, resulterer det i en kollision. Vi har set forskellige teknikker til opløsning af kollision, herunder lineær sondering, kæde osv. Vi har også set implementeringen af hashing i C ++.
Afslutningsvis kan vi sige, at hashing er langt den mest effektive datastruktur i programmeringsverdenen.
=> Se efter hele C ++ træningsserien her.
Anbefalet læsning
- Sådan skriver du komplekse forretningslogiske testscenarier ved hjælp af beslutningstabellen
- Field Validation Table (FVT): En testdesignteknik til feltvalidering
- QTP-tutorial # 15 - Brug af tekstområde, tabel og sidekontrolpunkter i QTP
- KORT I STL
- Alt om routere: Typer routere, routingtabel og IP-routing
- Top 40 bedste MySQL-interviewspørgsmål og -svar (2021 spørgsmål)
- Top 90 SQL-spørgsmål og svar (LATEST)
- Unix Utilities-programmer Kommandoer: Hvilken, Man, Find Su, Sudo (del D)