Κεφάλαιο 13 Αντισταθμιστική Ανάλυση Περιεχόμενα 13.1 Αντισταθμιστική Ανάλυση... 248 13.2 Μέθοδοι Αντισταθμιστικής Ανάλυσης... 250 13.2.1 Η χρεωπιστωτική μέθοδος... 250 13.2.2 Η ενεργειακή μέθοδος... 251 Ασκήσεις... 252 Βιβλιογραφία... 254 Στο κεφάλαιο αυτό μελετάμε την Αντισταθμιστική Ανάλυση. Σε αντίθεση με τη ανάλυση πολυπλοκότητας στη χειρότερη περίπτωση, που σε πολλές περιπτώσεις μπορεί να υπερεκτιμά το κόστος μιας πράξης, η αντισταθμιστική ανάλυση βασίζεται στον υπολογισμό του μέσου κόστους μιας πράξης μετά από μια ακολουθία πράξεων, συχνά καταλήγοντας σε ακριβέστερες εκτιμήσεις της πολυπλοκότητας των πράξεων. 13.1 Αντισταθμιστική Ανάλυση Ας θεωρήσουμε έναν αλγόριθμο Α ο οποίος χρησιμοποιεί μια δομή δεδομένων Δ. Κατά τη διάρκεια εκτέλεσης του αλγορίθμου Α, η δομή Δ πραγματοποιεί μια ακολουθία από πράξεις. Υπό κάποιες συνθήκες η εκτέλεση μιας τέτοιας πράξης μπορεί να είναι ιδιαίτερα ακριβή. Όμως, κάτι τέτοιο μπορεί να μη συμβαίνει συχνά, οπότε η ανάλυση χειρότερης περίπτωσης υπερεκτιμά το συνολικό κόστος μιας ακολουθίας από τέτοιες πράξεις. Αντίθετα, μπορούμε να θεωρήσουμε το συνολικό κόστος ολόκληρης της ακολουθίας, από το οποίο να υπολογίσουμε το μέσο κόστος μιας τέτοιας πράξης, το οποίο να δίνει πιο αντιπροσωπευτική εκτίμηση του κόστους της πράξης. Για παράδειγμα, ας θεωρήσουμε το πρόβλημα της Εύρεσης-Ένωσης που είδαμε νωρίτερα. Μια λύση που μελετήσαμε βασιζόταν στη χρήση δενδρικών δομών στα οποία εφαρμόζαμε «σταθμισμένη ένωση με συμπίεση διαδρομής» (Στις Εικόνες 13.1 και 13.2 φαίνονται οι εκτελέσεις μίας πράξης ένωσης και μίας εύρεσης, αντίστοιχα.) Εικόνα 13.1: Εκτέλεση της πράξης της ένωσης των στοιχείων 3 και 6 που ανήκουν στα δύο δένδρα στα αριστερά. 248
Εικόνα 13.2: Εκτέλεση της πράξης της εύρεσης του συνόλου που περιέχει το στοιχείο 2. Ο χρόνος χειρότερης περίπτωσης για μια πράξη εύρεσης ή ένωσης είναι ανάλογος του ύψους του δένδρου που αναπαριστά το σύνολο το οποίο περιέχει το στοιχείο που μας ενδιαφέρει, το οποίο για n στοιχεία συνολικά μπορεί να είναι Θ(log n). Όμως, ο συνολικός χρόνος εκτέλεσης m πράξεων εύρεσης-ένωσης αποδεικνύεται ότι είναι O(m α(m, n)), με αποτέλεσμα ο μέσος χρόνος εκτέλεσης μιας τέτοιας πράξης να είναι O(α(m, n)), το οποίο αυξάνεται με ιδιαίτερα αργότερο ρυθμό από ό,τι ο λογάριθμος του n. Συνοψίζοντας, έστω f(n) το κόστος μιας πράξης στη χειρότερη πείπτωση. Τότε ο συνολικός χρόνος για m πράξεις είναι O(m f(n)). Ωστόσο, σε κάποιες περιπτώσεις, η ίδια πράξη μπορεί να έχει διαφορετικό κόστος ανάλογα με τη στιγμή που εκτελείται. Έτσι, αν και το κόστος μιας πράξης στη χειρότερη περίπτωση μπορεί να είναι μεγάλο, το μέσο κόστος ανά πράξη σε οποιαδήποτε ακολουθία πράξεων μπορεί να είναι αρκετά μικρότερο. Στην Αντισταθμιστική Ανάλυση, λαμβάνουμε το αντισταθμιστικό κόστος ανά πράξη, δηλαδή, το μέσο κόστος εκτέλεσης μιας πράξης, όταν εκτελούμε μια ακολουθία πράξεων χειρότερης περίπτωσης. Παράδειγμα 1. Διαχείριση στοίβας. Ας θεωρήσουμε μια στοίβα S στην οποία εκτός από τις λειτουργίες ώθησης S.push(x) και απώθησης S.pop( ) έχουμε και μια λειτουργία πολλαπλών απωθήσεων S. multpop(k) η οποία αφαιρεί από τη στοίβα S τα k πρώτα στοιχεία στην κορυφή της. Δεν ειναι δύσκολο να παρατηρήσει κανείς ότι ο χρόνος χειρότερης περίπτωσης για την εκτέλεση μιας πράξης ώθησης ή απώθησης είναι Θ(1), ενώ η εκτέλεση μιας πράξης πολλαπλής απώθησης ενδέχεται να απαιτήσει έως και Θ(k) χρόνο. Τότε, όμως, ο συνολικός χρόνος εκτέλεσης μιας ακολουθίας πράξεων στη στοίβα S μπορεί να είναι Θ(N k), καθώς οι περισσότερες από αυτές τις πράξεις μπορεί να είναι πολλαπλές απωθήσεις και καθεμία από αυτές να απαιτήσει Θ(k) χρόνο. Όμως, με πιο προσεκτική ανάλυση μπορούμε να παρατηρήσουμε ότι ο συνολικός χρόνος για τις N πράξεις είναι Ο(), οπότε το αντισταθμιστικό κόστος, δηλαδή ο μέσος χρόνος ανά πράξη, είναι μόνο Ο(1). Παράδειγμα 2. Επαύξηση δυαδικού μετρητή. Έστω ένας δυαδικός μετρητής C με k δυαδικά ψηφία. Μια πράξη επαύξησης θέτει την τιμή C του μετρητή ίση με C + 1 (mod 2 k ). Ο χρόνος για μία επαύξηση είναι ίσος με το πλήθος των δυαδικών ψηφίων τα οποία αλλάζουν τιμή. Στη χειρότερη περίπτωση ο χρόνος αυτός μπορεί να είναι Θ(k), οπότε ο συνολικός χρόνος για επαυξήσεις μπορεί να είναι Θ(N k). Και στην περίπτωση αυτή, με πιο προσεκτική ανάλυση μπορούμε να δείξουμε ότι ο συνολικός χρόνος για επαυξήσεις (ξεκινώντας με μηδενισμένο μετρητή) είναι Θ(N). Συνεπώς, το αντισταθμιστικό κόστος ανά πράξη είναι μόνο Ο(1). Αρκεί να παρατηρήσουμε ότι το 1ο ψηφίο από το τέλος αλλάζει με κάθε επαύξηση, το 2ο αλλάζει με κάθε δεύτερη επαύξηση, το 3ο με κάθε τέταρτη επαύξηση κ.ο.κ. Σε μια ακολουθία επαυξήσεων το -οστό ψηφίο από το τέλος αλλάζει συνολικά 2 1 φορές, oπότε το συνολικό πλήθος αλλαγών είναι 249
k 2 1 < 2N. Δηλαδή, ο συνολικός χρόνος για επαυξήσεις είναι Ο(). 13.2 Μέθοδοι Αντισταθμιστικής Ανάλυσης Υπάρχουν 3 μέθοδοι αντισταθμιστικής ανάλυσης: Αθροιστική μέθοδος Χρεωπιστωτική μέθοδος Ενεργειακή μέθοδος Στην ανάλυση της επαύξησης του δυαδικού μετρητή χρησιμοποιήσαμε την αθροιστική μέθοδο. Είναι σημαντικό να παρατηρήσουμε ότι σε αντίθεση με την αθροιστική μέθοδο, η χρεωπιστωτική μέθοδος και η ενεργειακή μέθοδος μπορούν να αποδώσουν διαφορετικό αντισταθμιστικό κόστος σε διαφορετικούς τύπους πράξεων. 13.2.1 Η χρεωπιστωτική μέθοδος Σύμφωνα με την χρεωπιστωτική μέθοδο (γνωστή και ως μέθοδος του τραπεζίτη) αποδίδουμε σε κάθε πράξη έναν αριθμό από πιστώσεις (credts). Οι πιστώσεις αυτές χρησιμοποιούνται, για να αποπληρωθούν οι πράξεις. Όταν μια πράξη κοστίζει λιγότερο από την αντίστοιχη πίστωση, τότε το υπόλοιπο αποθηκεύεται σε κάποια αντικείμενα της δομής. Όταν μια πράξη κοστίζει περισσότερο από την αντίστοιχη πίστωση, τότε η υπολειπόμενη χρέωση καλύπτεται από αποθηκευμένες πιστώσεις. Αν οι πιστώσεις που αποδώσαμε στις πράξεις αρκούν, για να αποπληρώσουν οποιαδήποτε ακολουθία πράξεων, τότε το αντισταθμιστικό κόστος μιας πράξης είναι ίσο με τον αριθμό των πιστώσεων που της αποδώσαμε. Ας επιστρέψουμε στο πρόβλημα της διαχείρισης λίστας. Υπενθυμίζουμε ότι το κόστος μιας ώθησης και μιας απώθησης είναι σταθερό, ενώ το κόστος μιας πολλαπλής απώθησης είναι mn{k, S }. Ας θεωρήσουμε ότι αναθέτουμε 2 μονάδες πίστωσης για κάθε ώθηση και 0 μονάδες πίστωσης σε κάθε απλή και πολλαπλή απώθηση. Πρέπει να δείξουμε ότι οι πιστώσεις αρκούν, για να αποπληρώσουν οποιαδήποτε ακολουθία πράξεων. Για κάθε ώθηση, η μία μονάδα πίστωσης πληρώνει για την εκτέλεση της ώθησης, ενώ η δεύτερη αποθηκεύεται στο στοιχείο που ωθήθηκε. Σε κάθε απλή η πολλαπλή απώθηση, η απομάκρυνση των αντικειμένων που απωθούνται απόπληρώνεται από τη μία μονάδα πίστωσης που είναι αποθηκευμένη σε κάθε ένα από αυτά τα αντικείμενα. Άρα, οι πιστώσεις που αποδόθηκαν επαρκούν για οποιαδήποτε ακολουθία πράξεων και, άρα,ο συνολικός χρόνος για την εκτέλεση πράξεων είναι Ο(). Με παρόμοιο τρόπο μπορούμε να δείξουμε ότι ο συνολικός χρόνος που απαιτείται για επαυξήσεις ενός δυαδικού μετρητή ξεκινώντας από το 0 είναι Ο(). Σημειώνουμε ότι η αλλαγή ενός δυαδικού ψηφίου απαιτεί σταθερό χρόνο. Ας θεωρήσουμε ότι αναθέτουμε 2 μονάδες πίστωσης σε κάθε αλλαγή ενός δυαδικού ψηφίου από 0 σε 1 και 0 μονάδες πίστωσης σε κάθε αλλαγή ενός δυαδικού ψηφίου από 1 σε 0. Συνεπώς, για κάθε αλλαγή από 0 σε 1, μία μονάδα πίστωσης χρησιμοποιείται για την αλλαγή αυτή, ενώ η δεύτερη μονάδα αποθηκεύεται 250
στο 1. Άρα, δεδομένου ότι ο δυαδικός μετρητής ξεκινά από την τιμή 0, σε κάθε στιγμή κάθε δυαδικό ψηφίου που είναι 1 φέρει μία μονάδα πίστωσης. Αυτή η μονάδα αρκεί για την αποπληρωμή τυχόν αλλαγής του δυαδικού ψηφίου ξανά σε 0. Για παράδειγμα, ας θεωρήσουμε ότι ο μετρητής έχει τη δυαδική τιμή 00101111. Η τιμή του μετρητή μετά από μία επαύξηση είναι 00110000. Συνολικά εχουν αλλάξει 5 δυαδικά ψηφία και, άρα, το κόστος της επαύξησης είναι 5. Αυτό αποπληρώνεται από τις 4 αποθηκευμένες μονάδες πίστωσης στα 4 δεξιότερα δυαδικά ψηφία της τιμής 00101111, που είναι 1 (και γίνονται 0) και από τη μία από τις 2 μονάδες πίστωσης λόγω της αλλαγής του 5ου από το τέλος δυαδικού ψηφίου από 0 σε 1. Η δεύτερη μονάδα αποθηκεύεται στο 1 (που είναι 5ο από το τέλος). 13.2.2 Η ενεργειακή μέθοδος Σύμφωνα με την ενεργειακή μέθοδο (γνωστή και ως μέθοδος του φυσικού) αποδίδουμε στη δομή δεδομένων D μια συνάρτηση δυναμικού ή «δυναμικής ενέργειας» (potental functon), που συνήθως συμβολίζεται με Φ(D) και λαμβάνει πραγματικές τιμές. Έστω D 0 η αρχική δομή δεδομένων και D η δομή μετά την -οστή πράξη. Επίσης, έστω c το κόστος της -οστής πράξης. Το αντισταθμιστικό κόστος της -οστής πράξης είναι c = c + Φ(D ) Φ(D 1 ). Τότε το συνολικό αντισταθμιστικό κόστος μετά από πράξεις είναι: ĉ = (c + Φ(D ) Φ(D 1 )) = ( c ) + Φ(D N ) Φ(D 0 ). Θέλουμε Φ(D N ) Φ(D 0 ) έτσι ώστε c ĉ. Το αντισταθμιστικό κόστος c = c + Φ(D ) Φ(D 1 ) της -οστής πράξης συνεπάγεται ότι: Αν Φ(D ) Φ(D 1 ) > 0, τότε η δομή συγκεντρώνει δυναμικό και c > c. Αν Φ(D ) Φ(D 1 ) < 0, τότε η δομή χάνει δυναμικό και c < c. Δηλαδή, το κόστος μιας ακριβής πράξης αποπληρώνεται από τη διαφορά δυναμικού. Σημειώνουμε, επίσης, ότι, επειδή θέλουμε Φ(D N ) Φ(D 0 ) για οποιοδήποτε πλήθος πράξεων, απαιτούμε να ισχύει ότι Φ(D ) Φ(D 0 ) για κάθε = 1, 2,. Για το πρόβλημα της διαχείρισης στοίβας, επιλέγουμε Φ(S) = πλήθος αντικειμένων στη στοίβα S. Για αρχικά κενή στοίβα S 0 έχουμε Φ(S 0 ) = 0, το οποίο συνεπάγεται ότι για κάθε ακέραιο 0, Φ(S ) Φ(S 0 ) = 0, που με τη σειρά του συνεπάγεται ότι j=1 c j j=1 ĉ j για κάθε 0. Επομένως, το συνολικό αντισταθιστικό κόστος αποτελεί άνω φράγμα του συνολικού πραγματικού κόστους. Μένει να υπολογίσουμε το αντισταθμιστικό κόστος c για καθεμία από τις 3 πράξεις της στοίβας. Έστω ότι η -οστή πράξη είναι ώθηση (push). Έχουμε ότι c = 1 και Φ(S ) = Φ(S 1 ) + 1, επομένως c = c + Φ(S ) Φ(S 1 ) = 2. Έστω ότι η -οστή πράξη είναι (απλή) απώθηση (pop). Έχουμε ότι c = 1 και Φ(S ) = Φ(S -1) - 1, επομένως c = c + Φ(S ) Φ(S 1 ) = 0. Έστω ότι η -οστή πράξη είναι πολλαπλή απώθηση (multpop). Έχουμε ότι c = mn{k, S } και Φ(S ) = Φ(S 1 ) mn{k, S }, επομένως c = c + Φ(S ) Φ(S 1 ) = 0. 251
Άρα, ο συνολικός χρόνος για την εκτέλεση N πράξεων είναι Ο(). Για το πρόβλημα της επαύξησης δυαδικού μετρητή, επιλέγουμε Φ(D) = πλήθος ψηφίων ίσων με 1 στη δυαδική τιμή D του μετρητή. Για αρχικά μηδενισμένο μετρητή, έχουμε Φ(D 0 ) = 0 το οποίο συνεπάγεται ότι για κάθε ακέραιο 0, Φ(D ) Φ(D 0 ) = 0, που με τη σειρά του συνεπάγεται ότι j=1 c j j=1 ĉ j για κάθε 0. Επομένως, και σε αυτήν την περίπτωση το συνολικό αντισταθιστικό κόστος αποτελεί άνω φράγμα του συνολικού πραγματικού κόστους. Μένει να υπολογίσουμε το αντισταθμιστικό κόστος c για μία επαύξηση της τιμής του μετρητή. Έστω Φ(D 1 ) = b 1 και Φ(D ) = b. Επίσης, έστω ότι η -οστή πράξη μηδενίζει t δυαδικά ψηφία. Έχουμε c t + 1 και b b 1 t + 1, επομένως c = c + Φ(D ) Φ(D 1 ) t + 1 + b b 1 2. Εάν έχουμε Φ(D 0 ) = b 0 και Φ(D N ) = b N, τότε c = (ĉ (Φ(D N ) Φ(D 0 ))) 2 N b N + b 0 2 N + k. Επομένως, αν πραγματοποιήσουμε N = Ω(k) επαυξήσεις τότε ο συνολικός χρόνος που αυτές απαιτούν είναι = Ο() ανεξάρτητα από την αρχική τιμή του μετρητή. c Ασκήσεις 13.1 Θέλουμε να κατασκευάσουμε μια δομή δεδομένων που να υποστηρίζει δυαδική αναζήτηση αλλά και την αποδοτική εισαγωγή νέων στοιχείων. Θυμηθείτε ότι για τη δυαδική αναζήτηση ενός στοιχείου x σε ένα ταξινομημένο πίνακα Α[1: n] συγκρίνουμε το x με το μεσαίο στοιχείο A[m], όπου m = n+1 : (α) αν x = A[m], τότε το στοιχείο έχει βρεθεί, (β) αν 2 x < A[m], τότε ψάχνουμε αναδρομικά τον υποπίνακα Α[1: m 1] και (γ), αν x > A[m], τότε ψάχνουμε αναδρομικά τον υποπίνακα A[m + 1: n]. Ωστόσο, η εισαγωγή ενός νέου στοιχείου y στο διατεταγμένο πίνακα Α δεν είναι αποδοτική, ακόμα και αν ο πίνακας έχει κενές θέσεις στο τέλος (όπως θα συνέβαινε με μία υλοποίηση με δυναμικό πίνακα). Π.χ. αν Α = [2, 5, 19, 22, 35, 48, 81, 95, 101, 110, 134, 149, 256, κενό] και y = 1, τότε όλα τα στοιχεία του Α πρέπει να μετακινηθούν μία θέση δεξιά, με αποτέλεσμα η εισαγωγή να γίνεται σε Ο(n) χρόνο. Για αυτό το λόγο προτείνουμε την ακόλουθη δομή. Έστω k = lg(n + 1), ο αριθμός των bts που χρειάζονται για τη δυαδική αναπαράσταση n k 1, n k 2,, n 1, n 0 του n. Π.χ. για n = 13 έχουμε k = lg(n + 1) = lg 14 = 4 και n = 13 = 1101. Η δομή αποτελείται από k διατεταγμένους πίνακες A, 0 k 1. Αν n = 0, τότε ο A είναι κενός, διαφορετικά (όταν n = 1) ο A περιέχει 2 διατεταγμένα στοιχεία. Π.χ. για το παραπάνω παράδειγμα με n = 13 θα μπορούσαμε να έχουμε τους πίνακες A 0 = [35], A 1 = [ ] (κενός πίνακας), A 2 = [2, 48, 81, 149] και A 3 = [5, 19, 22, 95, 101, 110, 134, 256]. Προσέξτε ότι τα στοιχεία ενός πίνακα είναι διατεταγμένα αλλά δεν υπάρχει κάποια συγκεκριμένη σχέση μεταξύ των στοιχείων διαφορετικών πινάκων. α) Δώστε ένα αλγόριθμο αναζήτησης σε αυτή τη δομή. Ποιος είναι ο χρόνος εκτέλεσης χειρότερης περίπτωσης; 252
β) Περιγράψτε έναν αλγόριθμο εισαγωγής ενός νέου στοιχείου στη δομή μας. Αναλύστε το χρόνο εκτέλεσης χειρότερης περίπτωσης καθώς και τον αντισταθμιστικό χρόνο εκτέλεσης της εισαγωγής. γ) Μελετήστε τρόπους αποδοτικής υλοποίησης της διαδικασίας διαγραφής ενός στοιχείου από τη δομή. Υποθέστε ότι δεν υπάρχουν διπλά στοιχεία αποθηκευμένα στη δομή. 13.2 Έχουμε δει ότι ο αντισταθμιστικός χρόνος επαύξησης (πρόσθεσης με το 1) ενός δυαδικού μετρητή b k 1, b k 2,, b 1, b 0 με k bts είναι Ο(1), παρόλο που στη χειρότερη περίπτωση μια επαύξηση χρειάζεται Ο(k) χρόνο. Σε αυτήν την άσκηση θα δούμε πως μπορούμε να κάνουμε επαύξηση του μετρητή σε Ο(1) χρόνο χειρότερης περίπτωσης (δηλαδή κάθε επαύξηση θα γίνεται σε σταθερό αριθμό βημάτων). Η ιδέα βασίζεται στη χρήση ενός πλεονάζοντος αριθμητικού συστήματος: επιτρέπουμε κάποια bts να λάβουν την τιμή 2 με ελεγχόμενο, όμως, τρόπο. Ο αριθμός που αναπαριστά μια τέτοια ακολουθία b k 1, b k 2,, b 1, b 0 σε αυτό το σύστημα υπολογίζεται με τον τύπο k 1 =0 b 2, όπως και στην κανονική δυαδική αναπαράσταση, μόνο που τώρα η ίδια τιμή μπορεί να αντιστοιχεί σε περισσότερες ακολουθίες. Π.χ. 9 = 1 2 3 + 0 2 2 + 0 2 1 + 1 2 0 = 1001 αλλά, επίσης, 9 = 1 2 2 + 2 2 1 + 1 2 0 = 121 και 9 = 2 2 2 + 0 2 1 + 1 2 0 = 201. Για να επιτύχουμε γρήγορη επαύξηση πρέπει να αποτρέψουμε την εμφάνιση διαδοχικών 2 στην ακολουθία b k 1, b k 2,, b 1, b 0, οπότε πρέπει να θέσουμε κάποιους κανόνες. Θα χρειαστούμε μερικούς χρήσιμους ορισμούς : Μια ακολουθία στο πλεονάζον αριθμητικό σύστημα είναι κανονική, εάν τα 2 και τα 0 εναλλάσσονται (δηλαδή ανάμεσα από διαδοχικά 2 μεσολαβεί κάποιο 0 και αντιστρόφως). Π.χ. η 2012 είναι κανονική αλλά όχι και η 2120. Όταν το τελευταίο ψηφίο που δεν είναι 1 έχει τιμή 0, τότε λέμε ότι η ακολουθία έχει εκτεθειμένο 0. Π.χ. η ακολουθία 2001 έχει εκτεθειμένο 0 (αλλά δεν είναι κανονική), όπως και η 20201 (η οποία είναι κανονική). Όταν το τελευταίο ψηφίο που δεν είναι 1 έχει τιμή 2, τότε λέμε ότι η ακολουθία έχει εκτεθειμένο 2. Π.χ. η ακολουθία 2102 έχει εκτεθειμένο 2 (και είναι κανονική). Παρατηρήστε ότι ακόμα και με κανονικές ακολουθίες υπάρχει πλεονασμός, π.χ. 18 = 1202 = 1210. Εξηγήστε πώς μπορούμε να επιτύχουμε επαύξηση μιας κανονικής ακολουθίας σε Ο(1) χρόνο χειρότερης περίπτωσης. Tο αποτέλεσμα της επαύξησης πρέπει να είναι κανονική ακολουθία έτσι ώστε να μπορούμε να συνεχίσουμε τις επαυξήσεις. Υπόδειξη: Η προβληματική περίπτωση είναι όταν η ακολουθία μας έχει εκτεθειμένο 2. Πριν γίνει η επαύξηση, πρέπει να μετατραπεί σε ακολουθία με εκτεθειμένο 0 σε Ο(1) χρόνο. Για να επιτευχθεί αυτό, πρέπει να γνωρίζουμε τη θέση του τελευταίου 2. Αυτό γίνεται εύκολα, αν διατηρούμε τις θέσεις των 2 σε μια στοίβα (πίνακα) με το τελευταίο 2 να βρίσκεται στην κορυφή της. 13.3 Θέλουμε να αναλύσουμε την απόδοση μιας δομής δεδομένων που χειρίζεται διατεταγμένες λίστες ακεραίων από το σύνολο {1,2,3,, n} και υποστηρίζει την πράξη της συγχώνευσης δύο λιστών. Αρχικά, κάθε ακέραιος αποτελεί μια ξεχωριστή λίστα. Η πράξη συγχώνευση(α,β) δημιουργεί μια νέα λίστα C με τα στοιχεία των λιστών Α και Β. Μετά τη συγχώνευση οι δύο λίστες Α και Β έχουν καταστραφεί. Για παράδειγμα, αν έχουμε Α = 253
2, 5, 8, 12,21 και Β = 1, 15, 18, 22, 34, 55, τότε η συγχώνευσή τους δίνει μια νέα λίστα C = 1, 2, 5, 8, 12, 15, 18, 21, 22, 34, 55. Για να λύσουμε το παραπάνω πρόβλημα, αποθηκεύουμε κάθε λίστα σε μια δομή δεδομένων η οποία εκτελεί όλες τις παρακάτω πράξεις σε χρόνο f(n). ελάχιστο(a): Επιστρέφει το ελάχιστο στοιχείο της λίστας Α. αναζήτηση(a,x): Βρίσκει τη θέση του ακέραιου x στη λίστα Α. διαχωρισμός(a,x): Χωρίζει τη λίστα A στη θέση x. Επιστρέφει δύο νέες λίστες B και C όπου η Β περιέχει τους ακέραιους της Α που είναι x και η C περιέχει τους ακέραιους της Α που είναι > x. ένωση(α,β): Προϋποθέτει ότι όλοι οι ακέραιοι της λίστας A είναι μικρότεροι από τους ακέραιους της λίστας Β. Επιστρέφει μια νέα λίστα C με την ένωση των Α και B. α) Δείξτε πώς υλοποιείται η πράξη συγχώνευση(α,β) συνδυάζοντας τις παραπάνω πράξεις. Ποιος είναι ο χρόνος εκτέλεσης της; β) Τώρα θέλουμε να δείξουμε ότι ο αντισταθμιστικός χρόνος της συγχώνευσης είναι O(f(n) log n), ξεκινώντας από n λίστες με ένα ακέραιο η κάθε μια. Για το σκοπό αυτό θα ορίσουμε το δυναμικό φ(a j ) ενός ακέραιου a j ως εξής. Έστω ότι ο a j ανήκει στη λίστα Α = a 1,, a j 1, a j, a j+1,, a k. Αν το a j είναι το μοναδικό στοιχείο της λίστας, τότε φ(a j ) = 2 log n. Διαφορετικά, έχουμε τις ακόλουθες περιπτώσεις. Αν το a j είναι το πρώτο στοιχείο της λίστας (j = 1), τότε φ(a j ) = log n + log(a j+1 a j ). Αν το a j είναι το τελευταίο στοιχείο της λίστας (j = k) τότε φ(a j ) = log(a j a j 1 ) + log n. Διαφορετικά (1 < j < k) έχουμε φ(a j ) = log(a j a j 1 ) + log(a j+1 a j ). Το ολικό δυναμικό Φ της δομής είναι το άθροισμα των επιμέρους δυναμικών φ(a j ). Αρχικά, αφού κάθε λίστα έχει μόνο ένα στοιχείο, έχουμε Φ = 2n log n. Στη συνέχεια, κάθε πράξη συγχώνευσης έχει ως αποτέλεσμα τη μείωση του δυναμικού. Με τη βοήθεια της παραπάνω συνάρτησης δείξτε ότι σε οποιαδήποτε ακολουθία m συγχωνεύσεων θα γίνουν το πολύ O(m log n) πράξεις αναζήτησης, διαχωρισμού και ένωσης. Καταλήξτε στο συμπέρασμα ότι ο αντισταθμιστικός χρόνος της συγχώνευσης είναι O(f(n) log n). Βιβλιογραφία Cormen, T., Leserson, C., Rvest, R., & Stan, C. (2001). Introducton to Algorthms. MIT Press (2nd edton). Mehlhorn, K., & Sanders, P. (2008). Algorthms and Data Structures: The Basc Toolbox. Sprnger-Verlag. Tarjan, R. E. (1983). Data Structures and Network Algorthms. Socety for Industral and Appled Mathematcs. Γεωργακόπουλος, Γ. Φ. (2011). Δομές Δεδομένων. Πανεπιστημιακές εκδόσεις Κρήτης. 254