Ο ΑΤΔ Λεξικό Σύνολο στοιχείων με βασικές πράξεις: Δημιουργία Εισαγωγή Διαγραφή Μέλος Υλοποιήσεις Πίνακας με στοιχεία bit (0 ή 1) (bit vector) Λίστα ακολουθιακή (πίνακας) ή συνδεδεμένη
Είναι γνωστό το μέγιστο πλήθος N των στοιχείων του συνόλου; Είναι γνωστή μια αμφιμονοσήμαντη αντιστοιχία των στοιχείων του συνόλου με κάποιο σύνολο {0, 1,..., r}, όπου r ένας θετικός ακέραιος; Η επιλογή μιας υλοποίησης έτσι ώστε οι βασικές πράξεις να εκτελούνται όσο το δυνατόν γρηγορότερα εξαρτάται από τις απαντήσεις στις παραπάνω ερωτήσεις.
Υλοποίηση με bit vector Είναι δυνατή εφόσον είναι γνωστά τα N και r. Τότε οι βασικές πράξεις εκτελούνται σε χρόνο O(1) (ανεξάρτητο από το μέγεθος του συνόλου). Επιπλέον μειονέκτημα: αν r >> 0 τότε η αποθήκευση λίγων στοιχείων του λεξικού σπαταλά πολύ χώρο. Υλοποίηση με ακολουθιακή λίστα Είναι δυνατή εφόσον είναι γνωστό το N. Τότε οι βασικές πράξεις χρειάζονται χρόνο O(Ν).
Υλοποίηση με συνδεδεμένη λίστα Δεν απαιτεί γνώση των N, r. Οι βασικές πράξεις χρειάζονται χρόνο O(N). Παρατήρηση: Στις υλοποιήσεις με ακολουθιακή ή συνδεδεμένη λίστα η χειρότερη περίπτωση (για την οποία η χρονική πολυπλοκότητα είναι O(N)) δεν είναι καθόλου σπάνια. Πιο συγκεκριμένα, αν υποθέσουμε ότι θέλουμε να εκτελέσουμε κάποια βασική πράξη που αφορά ένα τυχαίο στοιχείο ενός δεδομένου λεξικού, τότε η πιθανότητα να χρειαστούμε O(N) χρόνο είναι πολύ μεγάλη.
Κατακερματισμός (Hashing) Εάν δεν είναι γνωστά τα N, r, είναι δυνατή μια υλοποίηση στην οποία οι βασικές πράξεις απαιτούν λίγο χρόνο; Ο στόχος είναι η χρονική πολυπλοκότητα να είναι ανεξάρτητη του N. Με τη μέθοδο του κατακερματισμού χρειαζόμαστε χρόνο O(N) στη χειρότερη περίπτωση, αλλά στις περισσότερες περιπτώσεις ο χρόνος που απαιτείται είναι πολύ μικρότερος. Πιο συγκεκριμένα, μπορούμε να σχεδιάσουμε τη δομή μας έτσι ώστε η πιθανότητα της σπατάλης περισσότερου χρόνου από O(1) να είναι πολύ μικρή.
Δεν απαιτείται η γνώση του r. Κατακερματισμός (Hashing) Ανοιχτός κατακερματισμός (open hashing). Δεν απαιτείται ούτε η γνώση του N. Κλειστός κατακερματισμός (closed hashing). Απαιτείται η γνώση του N. Χρειάζεται η επιλογή μιας συνάρτησης h (συνάρτηση κατακερματισμού) η οποία απεικονίζει τα στοιχεία του συνόλου στο διάστημα των ακεραίων [0, 1,..., Β-1], όπου το B μπορεί (κατ αρχήν) να επιλεγεί αυθαίρετα.
0 1 2.. Β-1 Κατακερματισμός (Hashing) Για την υλοποίηση χρησιμοποιούμε εκτός από την συνάρτηση h, έναν πίνακα και συνδεδεμένες λίστες. Α 10 20 30 2 12 9 19 29 40
Κατακερματισμός (Hashing) Κάθε στιγμή ισχύει η εξής ιδιότητα: Ένα στοιχείο x ανήκει στο λεξικό αν και μόνο αν έχει αποθηκευτεί στην λίστα που δείχνει ο δείκτης A[h(x)]. Για παράδειγμα ας υποθέσουμε ότι το σύνολο αποτελείται από θετικούς ακέραιους. Θεωρείστε τη συνάρτηση h = x mod B και πάρτε B = 10. Τότε η δομή με κάποια στοιχεία είναι αυτή που φαίνεται στο προηγούμενο σχήμα.
Κατακερματισμός (Hashing) Η συνάρτηση h πρέπει να έχει επιπλέον τις εξής ιδιότητες: Να υπολογίζεται γρήγορα (O(1)). Να κατανέμει τα στοιχεία του συνόλου όσο το δυνατόν ομοιόμορφα στις λίστες (δηλαδή να τα κατακερματίζει!). Ας υποθέσουμε ότι η h έχει τις παραπάνω ιδιότητες. Αν επιπλέον μπορούμε να εκτιμήσουμε την τιμή του N και επιλέξουμε B ~ N, τότε το πλήθος των κόμβων κάθε λίστας είναι N/B ~ 1.
Κατακερματισμός (Hashing) Για την εισαγωγή, διαγραφή ή μέλος ενός στοιχείου x θα χρειαστεί να επεξεργαστούμε μόνο την λίστα στην οποία δείχνει ο δείκτης A[h(x)]. Η χρονική πολυπλοκότητα είναι ανάλογη του μεγέθους αυτής της λίστας. Δηλαδή: O(1 + N/B) ~ O(1), αφού N/B ~ 1 Αυτό το είδος κατακερματισμού ονομάζεται ανοιχτός κατακερματισμός (open hashing).
Κατακερματισμός (Hashing) Η μέθοδος στην οποία δεν υπάρχουν οι λίστες, αλλά ένα στοιχείο του συνόλου αποθηκεύεται κατ ευθείαν σε μια θέση του πίνακα καλείται κλειστός κατακερματισμός (closed hashing). Σε αυτή την περίπτωση, είναι δυνατό κατά την προσπάθεια εισαγωγής του στοιχείου x στη θέση A[h(x)], αυτή η θέση να είναι κατειλημμένη. Αυτό μπορεί να συμβεί αν πριν την εισαγωγή του x έχει γίνει η εισαγωγή κάποιου y x τέτοιο ώστε h(x) = h(y). Αυτό το ενδεχόμενο ονομάζεται σύγκρουση (collision).
Κατακερματισμός (Hashing) Για την αντιμετώπιση των συγκρούσεων χρησιμοποιείται η μέθοδος του re-hashing. Σύμφωνα με αυτή τη μέθοδο, αν η θέση A[h(x)] είναι κατειλημμένη, τότε ο αλγόριθμος εισαγωγής δοκιμάζει τη θέση A[h 2 (x)]. Αν η A[h 2 (x)] δεν είναι κενή τότε δοκιμάζει την A[h 3 (x)], κ.ο.κ. Οι συναρτήσεις h i ορίζονται συνήθως σαν συναρτήσεις της h, του i και του x. Το ενδεχόμενο της σύγκρουσης (δηλαδή όταν χρησιμοποιείται closed hashing), έχει σαν συνέπεια η πολυπλοκότητα των βασικών πράξεων να εξαρτάται όχι μόνο από την επιλογή της h αλλά και από το πώς γίνεται rehashing.
Κατακερματισμός (Hashing) Για παράδειγμα θεωρείστε την ακόλουθη μέθοδο που μας δίνει τις συναρτήσεις h i (γραμμικό rehashing): h i (x) = (h(x) + i) mod B Για κάθε x y τέτοια ώστε h(x) = h(y), ισχύει ότι: h i (x) = h i (y), για κάθε i Αυτό έχει σαν συνέπεια η πολυπλοκότητα της εισαγωγής του x να είναι ανάλογη του πλήθους όλων των στοιχείων y τα οποία έχουν εισαχθεί στο λεξικό πριν το x και για τα οποία ισχύει h(x) = h(y).