Δομές Δεδομένων Υλοποίηση Δυαδικού Σωρού σε γλώσσα Java Δημήτρης Μιχαήλ Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο
Σωρός Μεγίστου ως ΑΤΔ Ένας σωρός μεγίστου (max heap) είναι ένας ΑΤΔ που περιλαμβάνει τις εξής λειτουργίες: Εισαγωγή ενός νέου στοιχείου x με μια προτεραιότητα p, INSERT(H,x,p). Εύρεση του στοιχείου με την μεγαλύτερη προτεραιότητα, FINDMAX(H). Διαγραφή του στοιχείου με την μεγαλύτερη προτεραιότητα, DELMAX(H). Επιστροφή του αριθμού των στοιχείων του σωρού, SIZE(H) Έλεγχος άμα ο σωρός είναι άδειος, ISEMPTY(H). Χαροκόπειο Πανεπιστήμιο 2/20
Δυαδικός Σωρός heap-ordered Ένα δέντρο είναι διατεταγμένο σε σωρό αν το κλειδί κάθε κόμβου είναι μεγαλύτερο ή ίσο με τα κλειδιά όλων των παιδιών του. Χαροκόπειο Πανεπιστήμιο 3/20
Δυαδικός Σωρός heap-ordered Ένα δέντρο είναι διατεταγμένο σε σωρό αν το κλειδί κάθε κόμβου είναι μεγαλύτερο ή ίσο με τα κλειδιά όλων των παιδιών του. Δυαδικός Σωρός (binary heap) O σωρός είναι ένα σύνολο κόμβων με κλειδιά τοποθετημένα σε ένα πλήρες δυαδικό δέντρο το οποίο είναι διατεταγμένο σε σωρό και αναπαριστάται ως πίνακας. Χαροκόπειο Πανεπιστήμιο 3/20
Πλήρες Δυαδικό Δέντρο Ορισμός Ένα δυαδικό δέντρο όπου όλα τα επίπεδα, εκτός ίσως του τελευταίου, είναι συμπληρωμένα, το οποίο συμπληρώνεται από τα αριστερά προς τα δεξιά. 1 2 3 4 5 6 7 8 9 Χαροκόπειο Πανεπιστήμιο 4/20
Πλήρες Δυαδικό Δέντρο σε Πίνακα 1 2 3 parent(i) = i/2 left child(i) = 2i right child(i) = 2i + 1 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 Χαροκόπειο Πανεπιστήμιο 5/20
Σωρός διασύνδεση σε Java (IntegerHeap.java) 1 package org. hua. dit. heap ; 2 3 public interface IntegerHeap { 4 5 void insert ( int elem ) ; 6 7 int findmax ( ) ; 8 10 9 void delmax ( ) ; 11 boolean isempty ( ) ; 12 13 int size ( ) ; 14 15 } Χαροκόπειο Πανεπιστήμιο 6/20
Υλοποίηση Δυαδικού Σωρού Αναπαράσταση Δυαδικού Σωρού (ArrayIntegerHeap.java) 1 package org. hua. dit. stack ; 2 3 public class ArrayIntegerHeap implements IntegerHeap { 4 5 private static final int DEFAULT_HEAP_SIZE = 64; 6 7 private int [ ] array ; 8 private int cursize ; Χρησιμοποιούμε έναν πίνακα και μία μεταβλητή που περιέχει τον αριθμό των στοιχείων που υπάρχουν ήδη μέσα στον σωρό. Χαροκόπειο Πανεπιστήμιο 7/20
Υλοποίηση Δυαδικού Σωρού Δημιουργία 10 public ArrayIntegerHeap ( ) { 11 this ( DEFAULT_HEAP_SIZE ) ; 12 } 13 14 public ArrayIntegerHeap ( int size ) { 15 if ( size <= 0) { 16 throw new IllegalArgumentException ( 17 "Heap size must be positive." ) ; 18 } 19 cursize = 0 ; 20 array = new int [ size + 1 ] ; 21 } Ένας constructor με και ένας χωρίς χωρητικότητα. Χαροκόπειο Πανεπιστήμιο 8/20
Υλοποίηση Δυαδικού Σωρού Κάτω-Πάνω Τακτοποίηση 23 private void swap ( int i, int j ) { 24 int tmp = array [ i ] ; 25 array [ i ] = array [ j ] ; 26 array [ j ] = tmp ; 27 } 28 29 / * 30 * f i x bottom up the k t h element assuming t h a t 31 * i t s p r i o r i t y has been increased 32 * / 33 private void fixup ( int k ) { 34 assert k >= 1 && k <= cursize ; 35 36 while ( k > 1 && array [ k / 2] < array [ k ] ) { 37 swap ( k, k / 2 ) ; 38 k /= 2 ; 39 } 40 } Όσο ο κόμβος k έχει πατέρα (k > 1) και το κλειδί του πατέρα είναι μικρότερο, κάνε αντιμετάθεση και επανέλαβε για τον πατέρα. Χαροκόπειο Πανεπιστήμιο 9/20
Υλοποίηση Δυαδικού Σωρού Πάνω-Κάτω Τακτοποίηση 42 / * 43 * f i x top down the k t h element assuming t h a t 44 * i t s p r i o r i t y has been decreased 45 * / 46 private void fixdown ( int k ) { 47 int j ; 48 49 while (2 * k <= cursize ) { 50 j = 2 * k ; 51 if ( j < cursize && array [ j ] < array [ j + 1 ] ) 52 j++; 53 if ( array [ k ] >= array [ j ] ) 54 break ; 55 56 swap ( k, j ) ; 57 k = j ; 58 } 59 } Όσο ο κόμβος k έχει τουλάχιστον ένα παιδί (2k < cursize), βρες το παιδί με το μεγαλύτερο κλειδί j. Εαν το παιδί j έχει μεγαλύτερο κλειδί από τον k, κάνε αντιμετάθεση και επανέλαβε από το παιδί j. Χαροκόπειο Πανεπιστήμιο 10/20
Υλοποίηση Δυαδικού Σωρού Διπλασιασμός Χωρητικότητας 61 private void doublecapacity ( ) { 62 int prevsize = array. length 1 ; 63 int [ ] narray = new int [ prevsize * 2 + 1 ] ; 64 65 / / copy old elements t o new a r r a y 66 for ( int i = 1 ; i <= cursize ; i++) 67 narray [ i ] = array [ i ] ; 68 69 / / place new i n p o s i t i o n 70 array = narray ; 71 } Δημιουργία διπλάσιου πίνακα, αντιγραφή των προηγούμενων κλειδιών και αντικατάσταση του παλιού πινακα με τον καινουριο. Ο garbage collector του JVM θα μαζέψει την μνήνη του παλιού πίνακα. Χαροκόπειο Πανεπιστήμιο 11/20
Υλοποίηση Δυαδικού Σωρού Εισαγωγή Στοιχείου 73 @Override 74 public void insert ( int elem ) { 75 / / make sure t h e r e i s space 76 if ( cursize == array. length 1) { 77 doublecapacity ( ) ; 78 } 79 80 / / add a t the bottom, as a l e a f 81 array[++cursize ] = elem ; 82 83 / / f i x i t s p o s i t i o n 84 fixup ( cursize ) ; 85 } Εαν δεν υπάρχει χώρος για στοιχείο, διπλασιασμός του πίνακα. Αύξηση του cursize κατά ένα, εισαγωγή του νέου στοιχείου στην τελευταία θέση του πίνακα και κάτω-πάνω τακτοποίηση. Χαροκόπειο Πανεπιστήμιο 12/20
Υλοποίηση Δυαδικού Σωρού Έυρεση Στοιχείου με Μέγιστη Προτεραιότητα 87 @Override 88 public int findmax ( ) { 89 if ( isempty ( ) ) { 90 throw new RuntimeException ( "Heap is empty." ) ; 91 } 92 93 / / max i s always i n f i r s t p o s i t i o n 94 return array [ 1 ] ; 95 } Επιστροφή του πρώτου στοιχείου του πίνακα. Χαροκόπειο Πανεπιστήμιο 13/20
Υλοποίηση Δυαδικού Σωρού Διαγραφή Στοιχείου με Μέγιστη Προτεραιότητα 97 @Override 98 public void delmax ( ) { 99 if ( isempty ( ) ) { 100 throw new RuntimeException ( "Heap is empty." ) ; 101 } 102 103 / / swap f i r s t w i t h l a s t 104 swap ( 1, cursize ) ; 105 106 / / d e l e t e l a s t 107 cursize ; 108 109 / / fixdown f i r s t 110 fixdown ( 1 ) ; 111 } Αντιμετάθεση (ή και απλά αντιγραφή) του τελευταίου στοιχείου στην πρώτη θέση του πίνακα. Μείωση των στοιχείων κατά ένα Πάνω-κάτω τακτοποίηση από την ρίζα. Χαροκόπειο Πανεπιστήμιο 14/20
Υλοποίηση Δυαδικού Σωρού isempty, size 113 @Override 114 public boolean isempty ( ) { 115 return cursize <= 0 ; 116 } 117 118 @Override 119 public int size ( ) { 120 return cursize ; 121 } Χαροκόπειο Πανεπιστήμιο 15/20
Πάνω-κάτω τακτοποίηση σωρού λάθος προτεραιότητα πάνω κάτω τακτοποίηση σωστός σωρός σωστός σωρός σωστός σωρός Άμα τα δύο υποδέντρα ενός κόμβου είναι σωροί, τότε με μία εκτέλεση της πάνω-κάτω τακτοποίησης σωρού από αυτόν τον κόμβο παίρνουμε ένα σωρό. Χαροκόπειο Πανεπιστήμιο 16/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Κατασκευή Δυαδικού Σωρού από Πίνακα Έστω ένας πίνακας με n στοιχεία τον οποίο θέλουμε να μετατρέψουμε σε σωρό. Όλα τα φύλλα του δέντρου είναι σωροί. Μπορούμε να φτιάχνουμε και το υπόλοιπο δέντρο με διαδοχικές πάνω-κάτω τακτοποιήσεις. Ξεκινάμε από την μέση του πίνακα και εκτελούμε πάνω-κάτω τακτοποιήσεις για ένα ένα τα στοιχεία μέχρι να φτάσουμε στην ρίζα (το πρώτο στοιχείο του πίνακα). Χαροκόπειο Πανεπιστήμιο 17/20
Υλοποίηση Δυαδικού Σωρού Μετατροπή πίνακα σε δυαδικό σωρό 123 public static ArrayIntegerHeap heapify ( int [ ] array ) { 124 assert array!= null && array. length > 0 ; 125 126 ArrayIntegerHeap h = new ArrayIntegerHeap ( array. length ) ; 127 128 / / copy elements 129 for ( int i = 0 ; i < array. length ; i++) 130 h. array [ i + 1] = array [ i ] ; 131 h. cursize = array. length ; 132 133 / / h e a p i f y 134 for ( int i = array. length / 2 ; i > 0 ; i ) 135 h. fixdown ( i ) ; 136 137 return h ; 138 } 139 } Χαροκόπειο Πανεπιστήμιο 18/20
Χρήση Δυαδικού Σωρού 1 package org. hua. dit. heap ; 2 3 import java. util. Arrays ; 4 import java. util. Random ; 5 6 / * * 7 * Example a p p l i c a t i o n 8 * / 9 public class ExampleApp { 10 11 public static void main (String [ ] args ) { 12 13 System. out. println ( "Constructing a max heap" ) ; 14 15 IntegerHeap h = new ArrayIntegerHeap ( ) ; 16 Random generator = new Random ( ) ; 17 18 for ( int i = 0 ; i < 50; i++) { 19 int e = generator. nextint ( ) % 1000; 20 System. out. println ( "Inserting element " + e + " into max heap" ) ; 21 h. insert ( e ) ; 22 } 23 24 while (! h. isempty ( ) ) { 25 System. out. println ( "Removing element from max heap: " + h. findmax ( ) ) ; 26 h. delmax ( ) ; 27 } Χαροκόπειο Πανεπιστήμιο 19/20
Χρήση Δυαδικού Σωρού 29 System. out. println ( "Generating random array of size 100" ) ; 30 31 int [ ] a = new int [ 1 0 0 ] ; 32 for ( int i = 0 ; i < 100; i++) { 33 a [ i ] = generator. nextint ( ) % 1000; 34 } 35 36 System. out. println ( "Array is " + Arrays. tostring (a ) ) ; 37 38 System. out. println ( "Sorting using HeapSort algorithm." ) ; 39 40 IntegerHeap anotherheap = ArrayIntegerHeap. heapify (a ) ; 41 int [ ] sorted = new int [ 1 0 0 ] ; 42 int i = 0 ; 43 while (! anotherheap. isempty ( ) ) { 44 sorted [ i++] = anotherheap. findmax ( ) ; 45 anotherheap. delmax ( ) ; 46 } 47 System. out. println ( "Sorted array is " + Arrays. tostring (sorted ) ) ; 48 49 System. out. println ( "Done" ) ; 50 } 51 } Χαροκόπειο Πανεπιστήμιο 20/20