Εργαστήριο 8 Σωρός (Hap) Εισαγωγή Ενα δυαδικό δέντρο ϐάθους N ονοµάζεται πλήρες (compt), όταν έχει όλους τους κόµβους του επιπέδου N συµπληρωµένους. Ενα δυαδικό δέντρο ϐάθους N ονοµάζεται σχεδόν πλήρες ( amost compt), όταν έχει όλους τους κόµβους του επιπέδου N 1 συµπληρωµένους και οι κόµβοι που υπάρχουν στο N-οστό επίπεδο είναι τοποθετηµένοι όσο το δυνατόν πιο αριστερά. Η τοποθέτηση των κόµβων σε ένα σχεδόν πλήρες δυαδικό δέντρο είναι τέτοια που µας επιτρέπει να αριθµήσουµε µε ένα συστηµατικό τρόπο τους κόµβους αυτούς. Αυτή η συστηµατική αρίθµηση (από πάνω προς τα κάτω και από αριστερά προς τα δεξιά κάνει δυνατή την αναπαράσταση ενός σχεδόν πλήρους δυαδικού δέντρου µε τη ϐοήθεια ενός απλού γραµµικού πίνακα, όπως ϕαίνεται στο σχήµα 8.1. (Θεωρούµε ότι το στοιχείο µε ενδείκτη 0 του πίνακα δεν χρησιµοποιείται). Η ϱίζα του σωρού ϐρίσκεται στη ϑέση aay[1] ενώ το αριστερό και δεξιό παιδί ενός στοιχείου στη ϑέση i ϐρίσκονται στις ϑέσεις 2i και 2i + 1 αντίστοιχα. Ο γονέας του κόµβου j είναι ο j/2 (ακέραια διαίρεση). Το εργαστήριο ασχολείται µε την κατασκευή κώδικα για σωρούς (Hap) και ειδικότερα δυαδικούς σωρούς. Ο δυαδικός σωρός είναι µια δοµή δεδοµένων η οποία µπορεί να ϑεωρηθεί ώς ένα δυαδικό δένδρο µε δύο επιπλέον ιδιότητες: Ολα τα επίπεδα του δένδρου εκτός ίσως από το χαµηλότερο είναι πλήρη και αν το τελευταίο επίπεδο δεν είναι πλήρες τότε οι κόµβοι εισάγονται από αριστερά προς τα δεξιά. Τα δεδοµένα κάθε κόµβου είναι µεγαλύτερα ( max hap) (σχήµα 8.2β ) ή µικρότερα (min hap)(σχήµα 8.2α ) από αυτά των παιδιών του. Οι ϐασικές πράξεις που ορίζονται για τη δοµή δεδοµένων σωρός, είναι η πράξη της εισαγωγής και η πράξη της διαγραφής ενός στοιχείου. Εισαγωγή στοιχείου (inst) Η πράξη της εισαγωγής ϕροντίζει ώστε ο σωρός που προκύπτει να έχει το µικρότερο (ή µεγαλύτερο για maxhap) στοιχείο του πάντοτε στην ϱίζα του δέντρου (κορυφή του σωρού). Στο επόµενο σχήµα ϕαίνεται µία σειρά από διαδοχικές πράξεις εισαγωγής στοιχείων οι οποίες δηµιουργούν ένα σωρό. MinHap 1. Οταν εισάγουµε ένα καινούργιο στοιχείο στο σωρό αυτό τοποθετείται στην επόµενη διαθέσιµη ϑέση στο τελευταίο επίπεδο (τελευταία ϑέση του πίνακα). 34
1 D 2 3 A C 4 5 6 7 B F E G 8 9 10 H I J D A C B F E G H I J 1 2 3 4 5 6 7 8 9 10 Σχήµα 8.1: Αναπαράσταση σχεδόν πλήρους δυαδικού δέντρου µε πίνακα (α ) Min Hap (ϐ ) Max Hap Σχήµα 8.2 2. Αν η τιµή του στοιχείου δεν παραβιάζει την ιδιότητα του σωρού (δηλαδή η τιµή του είναι µεγαλύτερη από αυτή του γονέα του) τότε το στοιχείο µένει στη ϑέση του. 3. Σε διαφορετική περίπτωση παιδί και γονέας ανταλλάσσουν ϑέσεις. Αυτή η διαδικασία συνεχίζεται µέχρι το καινούργιο στοιχείο να ϐρει µια ϑέση τέτοια ώστε να ικανοποιείται η ιδιότητα του σωρού. Ετσι κάθε στοιχείο που εισάγεται στο σωρό ϑα πρέπει να διασχίσει ένα µονοπάτι από το ϕύλλο στο οποίο ϐρισκόταν αρχικά µέχρι κάποιον κατάλληλο εσωτερικό κόµβο. Στη χειρότερη περίπτωση το µονοπάτι ϑα είναι ως τη ϱίζα του δέντρου. Η διαδικασία αυτή ονοµάζεται pcoat up ή shift up (σχήµα 8.3). 35
Αντί για διαδοχικά swap, είναι πιό αποδοτικό να χρησιµοποιήσουµε µία τρύπα (έναν άδειο κόµβο), ο οποίος ϑα κάνει τη διαδικασία pcoat up. Στο σηµείο που ϑα σταµατήσει η τρύπα (ικανοποιείται η ιδιότητα του σωρού) ϑα εισάγουµε το στοιχείο (σχήµα 8.4). Ψευδοκώδικας για την εισαγωγή νέου στοιχείου στο (minhap). if (hap is fu ) tminat cuntsiz=cuntsiz+1 ho=cuntsiz whi (ho>1 and x<aay[ho/2]) aay[ho]=aay[ho/2] ho=ho/2 nd whi aay[ho]=x 21 Inst 21 Pcoat up Pcoat up 21 21 Σχήµα 8.3: ιαδικασία εισαγωγής στοιχείων σε ένα σωρό (min Hap) ιαγραφή στοιχείου (mov) Η πράξη διαγραφής αφαιρεί πάντοτε το στοιχείο που ϐρίσκεται στην κορυφή και ϕροντίζει να αναδιατάσσει το σωρό, έτσι ώστε το αµέσως µικρότερο (ή µεγαλύτερο για maxhap) στοιχείο να ϐρεθεί στην κορυφή του σωρού. Η ϱίζα του σωρού εξάγεται και ο σωρός τακτοποιείται ως εξής (σχήµα 8.5): 36
p p < p ho p > Σχήµα 8.4: Εισαγωγή στοιχείου σε min Hap µε τη χρήση τρύπας p Η ϱίζα ανταλλάσσεται µε το τελευταίο ϕύλλο. Η νέα ϱίζα συγκρίνεται µε κάθε παιδί της και αν ένα από αυτά είναι µικρότερο από τη ϱίζα, τότε το ανταλλάσουµε µε αυτή. Συνεχίζουµε τις συγκρίσεις/ανταλλαγές µε τα παιδιά της νέας ϱίζας µέχρι να ϕθάσει σε ένα επίπεδο του δένδρου όπου ϑα είναι µεγαλύτερη από τα αντίστοιχα παιδιά Η διαδικασία ονοµάζεται pcoat down ή shift down. Οπως και στη διαδικασία της εισαγωγής είναι προτιµότερο αντι για διαδοχικά swap, να χρησι- µοποιήσουµς µια τρύπα (έναν άδειο κόµβο) για τη διαδικασία pcoat down (σχήµα 8.6): ηµιουργείται µια τρύπα στη ϱίζα, διαγράφοντας το στοιχείο της ϱίζας Αντιγράφουµε το τελευταίο στοιχείο σε µια προσωρινή µεταβλητή και διαγράφουµε το τελευταίο στοιχείο. Οσο δεν ισχύει η ιδιότητα του σωρού µετακινούµε την τρύπα προς τα κάτω. Στο σηµείου που ϑα σταµατήσει η τρύπα (ικανοποιείται η συνθήκη του σωρού), εισάγουµε το στοιχείο από την προσωρινή µεταβλητή. Hap.java pubic intfac Hap xtnds DataStuctu { //inst itm x in th hap pubic void inst ( Compaab x ) ; // tun and mov th smast itm pubic Compaab dtmin ( ) thows StuctuEmptyExcption ; // tun th smast itm pubic Compaab findmin ( ) thows StuctuEmptyExcption ; } 37
Dt min mnt dt ast nod 21 23 21 23 Rpac by vau of ast nod Pcoat down 21 Pcoat down 23 21 23 Σχήµα 8.5: ιαγραφή στοιχείου από min Hap Ασκηση 8.1 Χρησιµοποιώντας το Hap intfac κατασκευάστε µία κλάση AayMinHap, η οποία ϑα υ- λοποιεί ένα min Hap χρησιµοποιώντας ως αποθηκευτικό χώρο έναν πίνακα. Η ϱίζα του σωρού ϑα ϐρίσκεται στη ϑέση 1 του πίνακα (σχήµα 8.1). Κατασκευάστε τρείς δοµητές: 1. έναν dfaut, pubic AayMinHap( ) 2. και δύο παραµετρικούς pubic AayMinHap( int capacity ) pubic AayMinHap( Compaab [ ] itms ) Σε κάθε κλάση, που δηµιουργείτε καλό είναι να υλοποιείτε και µια µέθοδο pubic Sting tosting(), ώστε να είναι πιό εύκολες οι εκτυπώσεις και τελικά η δοκιµή του κώδικα, που γράφετε. Ασκηση 8.2 Να γράψετε µέθοδο pubic Compaab[ ] HapSot(Compaab[ ] inaay) η οποία να παίρνει ως είσοδο έναν πίνακα και να τον επιστρέφει ταξινοµηµένο µε τη µέθοδο HapSot Για τη µετατροπή ενός πίνακα σε σωρό µπορείτε να χρησιµοποιήσετε τον αλγόριθµο HapBottomUp (σχήµα 8.7, σχήµα 8.8) 38
< min(, ) > > > < Σχήµα 8.6: ιαγραφή στοιχείου από min Hap µε τη χρήση τρύπας 1. Stat at th v containing th ast non-af nod (i.., aay[n/2], wh n is th aay siz). 2. Mak th subt ootd at th ast non-af nod into a hap by invoking pcoatdown. 3. Mov in th cunt v fom ight to ft, making ach subt, ootd at ach ncountd nod, into a hap by invoking pcoatdown. 4. If th vs a not finishd, mov to a ow v thn go to stp 3. 5. Stop. 65 32 26 At ach stag convt th highightd t into a MinHap by pcoating down stating at th oot of th highightd t. 65 32 26 65 26 32 26 26 65 32 65 32 Σχήµα 8.7: Μετατροπή πίνακα σε min Hap 39
Σχήµα 8.8: Αλγόριθµος BottomUp 40