ΠΛΗ111 οµηµένος Προγραµµατισµός Ανοιξη 2005 Μάθηµα 8 ο Αναζήτηση Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης
Αναζήτηση Αναζήτηση σε ιατεταγµένο Πίνακα υαδική Αναζήτηση Κατακερµατισµός Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 2
Αναζήτηση σε ιατεταγµένο Πίνακα Θεωρούµε πίνακα στοιχείων σε αύξουσα διάταξη Αναζητούµε συγκεκριµένο στοιχείο στον πίνακα Γραµµική αναζήτηση Εξετάζουµε τα στοιχεία ένα ένα ξεκινώντας από το πρώτο Σταµατούµε µόλις βούµε το ζητούµενο ή µεγαλύτερό του 1 3 4 5 17 18 31 33 Κόστος: περίπου n/2 συγκρίσεις Επιτυχηµένη αναζήτηση: (1+2+...+n)/n = n(n+1)/(2n) = (n+1)/2 Αποτυχηµένη αναζήτηση: (1+2+...+n+1)/(n+1) = (n+2)/2 σαν επιτυχηµένη αναζήτηση σε πίνακα µεγέθους n+1 εν αξιοποιούµε πλήρως την αύξουσα διάταξη των στοιχείων Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 3
υαδική Αναζήτηση Θεωρούµε πίνακα στοιχείων σε αύξουσα διάταξη Αναζητούµε συγκεκριµένο στοιχείο στον πίνακα υαδική αναζήτηση Συγκρίνουµε το ζητούµενο µε το µεσαίο στοιχείο του πίνακα Αν είναι ίσα, η αναζήτηση τερµατίζει επιτυχώς Αν το µεσαίο µεγαλύτερο του ζητούµενου, η αναζήτηση συνεχίζεται στο πρώτο µισό του πίνακα Αν το µεσαίο µικρότερο του ζητούµενου, η αναζήτηση συνεχίζεται στο δεύτερο µισό του πίνακα Σε κάθε σύκριση, το εναποµένον µέγεθος του πίνακα µισό Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 4
Παράδειγµα υαδικής Αναζήτησης Υπάρχει το στοιχείο 17 στον πίνακα; 1. Aρχική αναζήτηση στο [0..7] 2. Το µεσαίο στη θέση (0+7)/2=3 έχει τιµή a[3]=5<17 3. Επόµενη αναζήτηση στο διάστηµα [4..7] 4. Το µεσαίο στη θέση (4+7)/2=5 έχει τιµή a[5]=18>17 5. Επόµενη αναζήτηση στο διάστηµα a[4..4] 6. Το µεσαίο στη θέση (4+4)/2=4 έχει τιµή a[4]=17 7. Επιστρέφουµε τη θέση 4 0 1 2 3 4 5 6 7 1 3 4 5 17 18 31 33 Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 5
Αναδροµική υαδική Αναζήτηση int binsearch(int a[], int key, int low, int high) { int mid; if (low > high) return (-1); mid = (low + high)/2; if (key == a[mid]) /* found */ return (mid); if (key < a[mid]) /* lower half */ return binsearch(a, key, low, mid-1); else /* upper half */ return binsearch(a, key, mid+1, high); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 6
Επαναληπτική υαδική Αναζήτηση int binsearch(int a[], int key, int n) { int mid, low, high; low = 0; high = n-1; while (low <= high) { mid = (low + high)/2; if (key == a[mid]) /* found */ return (mid); if (key < a[mid]) /* lower half */ high = mid 1; else /* upper half */ low = mid + 1; return (-1); Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 7
Ανάλυση υαδικής Αναζήτησης Αναλύουµε πολυπλοκότητα χειρότερης περίπτωσης Υπολογίζουµε το πλήθος των συγκρίσεων σε αποτυχηµένη αναζήτηση Θεωρούµε αρχικό διάστηµα µεγέθους 2 n -1 Αποτυχηµένη αναζήτηση οδηγεί σε διάστηµα µεγέθους 2 n-1-1 T(2 n -1) = T(2 n-1-1) + 1, n>1 T(1) = 1 Τ(2 n -1) = T(2 n-1-1) + 1 = T(2 n-2-1) + 2 = T(0) + n = n Άρα T(n) = log 2 (n+1) = Ο(log 2 n) Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 8
Κατακερµατισµός (Hashing) Μέθοδος αποθήκευσης και αναζήτησης σε πίνακα Πίνακας κατακερµατισµού Aποθηκεύει κλειδιά Συνάρτηση κατακερµατισµού Mετατρέπει κάθε κλειδί σε θέση του πίνακα κατακερµατισµού Τέλεια όταν µετατρέπει κάθε κλειδί σε διαφορετική θέση Πρόβληµα Πως επιλέγουµε τη σωστή συνάρτηση κατακερµατισµού Τι γίνεται όταν πολλαπλά κλειδιά αντιστοιχούν στη ίδια θέση (collision resolution) key data h(key) hash table Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 9
Παράδειγµα Κατακερµατισµού #define TABLE_SIZE 15 #define h(s) ((s[0] + s[1]) % TABLE_SIZE) typedef struct node { char *key; int data; node_t; node_t hashtable[table_size]; void install(char *key, int data) { node_t *p = &hashtable[h(key)] if (p->key) fprintf(stderr, collision ); else { p->key = key; p->data = data; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 10
Συνάρτηση Κατακερµατισµού Μετατρέπει το κλειδί σε ακέραιο [0,Μ-1], όπου Μ το µέγεθος του πίνακα κατακερµατισµού Μετατροπή κλειδιού σε ακέραιο Έστω αλφάβητο µε 32 χαρακτήρες A, B, C,, Z Έστω ότι ο i-στός χαρακτήρας αναπαρίσταται µε δυαδικό i Μετατρέπουµε τη συµβολοσειρά-κλειδί στον αντίστοιχο δυαδικό π.χ. Α Κ Ε Υ γίνεται 00001010110010111001 Εναλλακτικά χρησιµοποιούµε το σχήµα Horner π.χ. Α Κ Ε Υ γίνεται 1*32 3 + 11*32 2 + 5*32 1 + 25*32 0 = (((1*32 + 11)*32)+5)*32+25 = 44217 Μετατροπή ακεραίου σε θέση πίνακα: π.χ. h(k)=k mod M Προτιµούµε Μ πρώτο αριθµό για να αξιοποιούµε όλους τους χαρακτήρες του κλειδιού Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 11
Γραµµικός Κατακερµατισµός (Linear Probing) Εισαγωγή στοιχείων σε απλό πίνακα κατακερµατισµού Αν µια θέση του πίνακα είναι κατειλληµένη αναζητούµε κενή θέση στις υπόλοιπες του πίνακα Προσαυξάνουµε την τρέχουσα θέση κατά µία σταθερά i, και εξετάζουµε διαδοχικά τις θέσεις h(key), h(key)+i, h(key)+2i void install(char *key, int data) { int p = h(key); while (hashtable[p].key) p = (p + 1) % M; /* i = 1 */ hashtable[p].key = key; hashtable[p].data = data; Τί γίνεται στην περίπτωση που ο πίνακας είναι γεµάτος ; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 12
Αναζήτηση µε Γραµµικό Κατακερµατισµό int find(char *key) { int try, h; try = h = hash(key); do { if (!hashtable[try].key) return (-1); /* not found */ else if (!strcmp(hashtable[try].key, key)) return (try); /* found */ try = (try + 1) mod M; while (try!= h); return (-2); /* not found and hash table full */ Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 13
Αλυσιδωτός Κατακερµατισµός (Separate Chaining) Κάθε θέση του πίνακα είχνει σε λίστα µε όλα τα αποθηκευµένα στοιχεία της θέση αυτής Κόστος αναζήτησης Ν/Μ, Ν το πλήθος των αποθηκευµένων κλειδιών typedef struct node { char *key; int data; struct node *next; node_t, *nodeptr_t; node_t hashtable[table_size]; κεφαλή λίστας void insert(char *key, int data) { nodeptr_t *p; for (p = &hashtable[h(key)]; *p; p = &((*p)->next)) if (!strcmp((*p)->key, key)) return; /* key found in hash table */ *p = (nodeptr_t) malloc(sizeof(node_t)); (*p)->data = data; (*p)->key = key; (*p)->next = NULL; Ανοιξη 2005 Στέργιος Β. Αναστασιάδης 14