Middle
Mi történik ütközés esetén, amikor kulcsot szerezünk egy C++-ban lévő konténerhez?
sobes.tech MI
Válasz az MI-től
Amikor ütközés történik egy C++-ban (például std::unordered_map, std::unordered_set) asszociatív tárolókban a kulcs megszerzésekor, a következő történik:
- A kulcs hash értékét számítják ki.
- A hash alapján meghatározzák a "korsó" (bucket) számát, ahová az elem potenciálisan kerül.
- Ha ebben a korsóban már vannak azonos hash értékű elemek (azaz ütközés történt), akkor a tároló elkezdi végignézni a korsóban lévő elemeket.
- Minden elem esetében összehasonlítja a keresett elem kulcsát az aktuális elem kulcsával az egyenlőség operátor (
operator==) segítségével. - Ha az összehasonlítás eredménye pozitív, megtalálta a keresett elemet.
- Ha az összes elem végignézése után sem talál egyezést, akkor az adott kulcsú elem hiányzik a tárolóból.
Különböző ütközéskezelési stratégiák léteznek:
- Láncolási módszer (Separate Chaining): Minden korsóban egy lista (például egys linked list) tárolja az azonos hash értékű elemeket. Ütközés esetén az új elemet hozzáadják ehhez a listához.
// Egy egyszerű láncolási módszer vázlatos példája struct Node { Key key; Value value; Node* next; }; struct Bucket { Node* head = nullptr; // A korsóban lévő elemek listája }; Bucket buckets[NUM_BUCKETS]; // Ütés/keresés esetén // A listát végignézzük: head -> node1 -> node2 -> ... - Nyitott címzéses módszer (Open Addressing): Minden elem közvetlenül a hash táblában tárolódik. Ütközés esetén a következő szabad helyet keresi a meghatározott stratégia szerint:
- Lineáris zárójel (Linear Probing): Ellenőrzi a következő cellákat (+1, +2, +3 ... az eredeti indextől)
// Egy egyszerű lineáris zárójel vázlatos példája struct Slot { Key key; Value value; bool occupied = false; bool deleted = false; // A törlés utáni helyes kereséshez }; Slot table[TABLE_SIZE]; // Beillesztés/keresés esetén, ha table[hash] foglalt // Ellenőrizzük a table[(hash + 1) % TABLE_SIZE], table[(hash + 2) % TABLE_SIZE], ... - Kvadratikus zárójel (Quadratic Probing): A cellák kvadratikus eltolással ellenőrződnek (+1², +2², +3² ... az eredeti indextől)
- Kettős hash-elés (Double Hashing): A második hash függvény határozza meg a zárójel lépését.
- Lineáris zárójel (Linear Probing): Ellenőrzi a következő cellákat (+1, +2, +3 ... az eredeti indextől)
A C++ szabványos tárolói (std::unordered_map, std::unordered_set) általában a láncolási módszert valósítják meg. Nagy ütközésszám esetén a műveletek (keresés, beszúrás, törlés) hatékonysága romolhat, közelítve a lineáris függést a legrosszabb esetben a "töltött" korsóban lévő elemek számától, de átlagosan közel áll a konstanshoz jó hash függvény esetén.