Σύνοψη Προηγούμενου (1/2) Στοίβες, Ουρές, Ουρές Προτεραιότητας Ορέστης Τελέλης telelis@unipi.gr Τμήμα Ψηφιακών Συστημάτων, Πανεπιστήμιο Πειραιώς Πίνακες Εισαγωγή, σε χρόνο O(1). Αναζήτηση, σε χρόνο O(n). Διαγραφή, σε χρόνο O(n) (απαιτεί αναζήτηση). Αναπαράσταση Υποσυνόλου n συνεχόμενων ακεραίων (π.χ., 0, 1, 2,..., n 1): Εισαγωγή, Διαγραφή, Αναζήτηση σε χρόνο O(1). Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 1 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 2 / 56 Σύνοψη Προηγούμενου (2/2) Σημερινό Μάθημα Ταξινομημένοι Πίνακες Δυαδική Αναζήτηση, σε χρόνο O(log n). Εισαγωγή, σε χρόνο O(n). Απαιτεί: Δυαδική Αναζήτηση για εντοπισμό θέσης εισαγωγής χρόνος: O(log n). Μετακίνηση O(n) στοιχείων κατά μία θέση χρόνος: O(n). Εγγραφή νέου στοιχείου στην κενή θέση που προκύπτει χρόνος: O(1). Διαγραφή, σε χρόνο O(n). Στοίβα Ουρά Υλοποίηση με πίνακα Υλοποίηση με πίνακα «Αναδιπλούμενοι» (κυκλικοί) πίνακες Ουρά Προτεραιότητας (Μη αποδοτική) Υλοποίηση με ταξινομημένο πίνακα Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 3 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 4 / 56
Περιορισμένη Προσπέλαση Πιο Αφηρημένες Δομές Οι στοίβες και οι ουρές ορίζουν μόνο δύο βασικές πράξεις: Εισαγωγή στοιχείου. Απομάκρυνση στοιχείου, που προδιαγράφεται από τη λειτουργία τους. Το απομακρυνόμενο στοιχείο επιβάλλεται από τη διεπαφή τους. Δεν προβλέπεται η διαγραφή/απομάκρυνση στοιχείου της επιλογής μας. Σε αντιδιαστολή με τους πίνακες. Δεν ορίζουν αναζήτηση στοιχείου: Ομως αυτή μπορεί να ενσωματωθεί σε μία υλοποίηση. Οι στοίβες και οι ουρές είναι πιο αφηρημένες δομές από τους πίνακες. Ορίζονται ουσιαστικά από τη διεπαφή (interface) τους. Ο εσωτερικός μηχανισμός υλοποίησης δεν είναι ορατός στο χρήστη. Παράδειγμα. Μία στοίβα ή μία ουρά μπορεί να υλοποιηθεί με: διαχείριση ενός πίνακα, συνδεδεμένη λίστα (επόμενο μάθημα) Και θα είναι αναγκαστικά «γραμμικού τύπου» O(n) χρόνου. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 5 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 6 / 56 Αναλογία με Φυσικό Κόσμο Στοίβες Stacks Στοίβα Ταχυδρομικών επιστολών. Εξέταση των επιστολών από πάνω προς τα κάτω. Στοίβα Πιάτων Πλύσιμο των πιάτων από πάνω προς τα κάτω. Βασικές ενέργειες μιας στοίβας. push: Τοποθέτηση στοιχείου στην κορυφή της στοίβας. pop: Απομάκρυνση στοιχείου από την κορυφή της στοίβας. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 7 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 8 / 56
Στοίβα (Stack) Μερικές Εφαρμογές Στοιβών LIFO (Last In, First Out) δομή δεδομένων. H στοίβα περιορίζει την προσπέλαση στo στοιχείο που εισήχθη πιο πρόσφατα. Η δομή στοίβα μπορεί να υλοποιηθεί με x = top έναν πίνακα και y έναν δείκτη στο στοιχείο της κορυφής της. Ελεγχος ισορροπίας παρενθέσεων και αγκύλων σε μία έκφραση. Συντακτική ανάλυση εκφράσεων, όπως 3 (4 + 5). Βοηθητική δομή για αλγόριθμους εξέτασης κόμβων δέντρου ή αναζητήσεις στις κορυφές ενός γράφου. Αρχιτεκτονική μικροεπεξεργαστών στηρίζεται στη χρήση στοίβας. Υπολογιστές τσέπης. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 9 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 10 / 56 Παράδειγμα Λειτουργιών Στοίβας Υλοποίηση Στοίβας Βασίζεται στη διαχείριση των παρακάτω αντικειμένων: push(10) push(5) pop() push(15) push(7) pop() 10 5 10 10 15 10 7 15 10 15 10 top τύπου int «Δείκτης» στην κορυφή της στοίβας stackarray τύπος πίνακα Πίνακας αποθήκευσης στοιχείων της στοίβας Σημείωση: Είναι βολικό να έχουμε top= 1, για την κενή στοίβα. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 11 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 12 / 56
Υλοποίηση Στοίβας Αντικειμένων (1/3) c l a s s S t a c k { p r i v a t e O b j e c t [ ] s t a c k A r r a y ; p r i v a t e i n t top ; // top of s t a c k p u b l i c S t a c k ( i n t s ) { // c o n s t r u c t o r s t a c k A r r a y = new O b j e c t [ s ] ; // c r e a t e a r r a y top = 1; // no items yet // t r u e i f s t a c k empty ( e l s e : f a l s e ) p u b l i c boolean isempty ( ) { r e t u r n ( top == 1) ; // t r u e i f s t a c k i s f u l l ( e l s e : f a l s e ) p u b l i c boolean i s F u l l ( ) { r e t u r n ( top == s t a c k A r r a y. l e n g t h 1) ; // peek at top of s t a c k p u b l i c O b j e c t peek ( ) { i f (! isempty ( ) ) r e t u r n s t a c k A r r a y [ top ] ; r e t u r n ( n u l l ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 13 / 56 Υλοποίηση Στοίβας Αντικειμένων (2/3) // put data on top p u b l i c boolean push ( O b j e c t data ) { i f (! t h i s. i s F u l l ( ) ) { s t a c k A r r a y [++ top ] = data ; r e t u r n ( t r u e ) ; r e t u r n ( f a l s e ) ; // read data on top, decrement top, r e t u r n data p u b l i c O b j e c t pop ( ) { i f (! t h i s. isempty ( ) ) { O b j e c t data = s t a c k A r r a y [ top ] ; s t a c k A r r a y [ top ] = n u l l ; r e t u r n ( data ) ; r e t u r n ( n u l l ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 14 / 56 Σχόλια Υλοποίηση Στοίβας Αντικειμένων (3/3) Η πράξη peek πλεονάζει θεωρητικά, αλλά βολεύει στην πράξη: Μπορεί να υλοποιηθεί με pop ακολουθούμενη από push: O b j e c t data = s t a c k. pop ( ) ; s t a c k. push ( data ) ; /* do something with data */ Παρατηρήστε τον συνεπή χειρισμό «σφαλμάτων» σε κάθε πράξη. Πράξη Επιστρέφει Περίπτωση push επιστρέφει true/ false για επιτυχή/ανεπιτυχή εισαγωγή pop επιστρέφει null όταν η στοίβα είναι άδεια peek επιστρέφει null όταν η στοίβα είναι άδεια c l a s s StackApp { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { S t a c k s t a c k = new S t a c k ( 1 0 ) ; // make s t a c k s t a c k. push ( new I n t e g e r ( 2 0 ) ) ; // push items s t a c k. push ( new I n t e g e r ( 4 0 ) ) ; s t a c k. push ( new I n t e g e r ( 6 0 ) ) ; s t a c k. push ( new I n t e g e r ( 8 0 ) ) ; while (! s t a c k. isempty ( ) ) { I n t e g e r data = ( I n t e g e r ) s t a c k. pop ( ) ; System. out. p r i n t ( data. i n t V a l u e ( ) ) ; System. out. p r i n t ( ) ; System. out. p r i n t l n ( ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 15 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 16 / 56
Σχόλια Παρατήρηση: για να εισάγουμε ακέραιο χρησιμοποιούμε την κλάση Integer Κλάση της Java για ενθυλάκωση ακεραίου int σε αντικείμενο. Υπάρχουν επίσης οι: Long, Bool, Character, Float, Double, Μία για κάθε βασικό τύπο της γλώσσας. Αυτό εξυπηρετεί κυρίως τη συνέπεια στον χειρισμό «σφαλμάτων»: Εστω ότι αποθηκεύουμε ακεραίους στη στοίβα. Εστω ότι οι peek και pop επιστρέφουν int. Αν όμως η στοίβα είναι άδεια τί πρέπει να επιστρέφουν? Γι αυτό επιλέχθηκε να επιστρέφουν αντικείμενο ή null. Πώς υλοποιούμε στοίβα που επιβάλλει αποθήκευση τύπου ακεραίων? Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 17 / 56 Υλοποίηση Στοίβας Ακεραίων (1/2) c l a s s L o n g S t a c k { p r i v a t e long [ ] s t a c k A r r a y ; p r i v a t e i n t top ; // top of s t a c k p u b l i c L o n g S t a c k ( i n t s ) { // c o n s t r u c t o r s t a c k A r r a y = new long [ s ] ; // c r e a t e a r r a y top = 1; // no items yet // t r u e i f s t a c k empty ( e l s e : f a l s e ) p u b l i c boolean isempty ( ) { r e t u r n ( top == 1) ; // t r u e i f s t a c k i s f u l l ( e l s e : f a l s e ) p u b l i c boolean i s F u l l ( ) { r e t u r n ( top == s t a c k A r r a y. l e n g t h 1) ; // peek at top of s t a c k p u b l i c Long peek ( ) { i f (! isempty ( ) ) r e t u r n ( new Long ( s t a c k A r r a y [ top ] ) ) ; r e t u r n ( n u l l ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 18 / 56 Υλοποίηση Στοίβας Ακεραίων Παράδειγμα Εφαρμογής Στοίβας // put data on top p u b l i c boolean push ( long data ) { i f (! t h i s. i s F u l l ( ) ) { s t a c k A r r a y [++ top ] = data ; r e t u r n ( t r u e ) ; r e t u r n ( f a l s e ) ; Οι μεταγλωττιστές (compilers) χρειάζεται να ελέγχουν εάν υπάρχει ισορροπία στα σύμβολα σε διάφορες εκφράσεις. «(» πρέπει να ταιριαστεί με «)». «[» πρέπει να ταιριαστεί με «]». «/*» πρέπει να ταιριαστεί με «*/», κ.λ.π. // read data on top, decrement top, r e t u r n data p u b l i c Long pop ( ) { i f (! t h i s. isempty ( ) ) r e t u r n ( new Long ( s t a c k A r r a y [ top ]) ) ; r e t u r n ( n u l l ) ; Παραδείγματα μη ταιριασμάτων: a = b + ( c d ) * ( e f ) ; // E x t r a )!!! while ( m < ( n [ 8 ] + a ) { // ) i s m i s s i n g!!! /*......... */ Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 19 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 20 / 56
Αλγόριθμος Balance Checker (1/2) Αλγόριθμος Balance Checker (2/2) p u b l i c s t a t i c boolean c h e c k B a l a n c e ( S t r i n g expr ) { /* i f r i g h t p a r e n t h e s i s ( continued ) : */ S t a c k s t a c k = new S t a c k ( expr. l e n g t h ( ) ) ; // i n i t i a l i z e s t a c k char [ ] c a r r = expr. t o C h a r A r r a y ( ) ; // i n p u t => char a r r a y f o r ( i n t i = 0 ; i < c a r r. l e n g t h ; i + + ) { // f o r each c h a r a c t e r // i f l e f t kind of p a r e n t h e s i s, wrap i t i n // C h a r a c t e r o b j e c t and push i t i n the s t a c k i f ( c a r r [ i ] == ( c a r r [ i ] == [ c a r r [ i ] == { ) s t a c k. push ( new C h a r a c t e r ( c a r r [ i ] ) ) ; // i f popped value matches with read c h a r a c t e r, // as l e f t and r i g h t, c o n t i n u e with next c h a r a c t e r. i f ( ( d a t a V a l u e == { && c a r r [ i ] == ) ( d a t a V a l u e == ( && c a r r [ i ] == ) ) ( d a t a V a l u e == [ && c a r r [ i ] == ] ) ) c o n t i n u e ; e l s e r e t u r n ( f a l s e ) ; // else, not balanced // i f some r i g h t kind of p a r e n t h e s i s : i f ( c a r r [ i ] == ) c a r r [ i ] == ] c a r r [ i ] == ) { C h a r a c t e r data = ( C h a r a c t e r ) s t a c k. pop ( ) ; // pop an o b j e c t i f ( data == n u l l ) r e t u r n ( f a l s e ) ; // none found? char d a t a V a l u e = data. c h a r V a l u e ( ) ; // unwrap value // A l l l e f t k i n d s of p a r e n t h e s i s pushed i n the s t a c k // must have been matched with t h e i r r i g h t mates. i f ( s t a c k. isempty ( ) ) r e t u r n ( t r u e ) ; r e t u r n ( f a l s e ) ; // otherwise, not balanced Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 21 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 22 / 56 Παράδειγμα Εφαρμογής «Balance Checker» Παράδειγμα Εφαρμογής «Balance Checker» S = t[5] + (a (c + b) ) read S, =, t ; [ read [ ; push( [ ) ; // ignored ( ( read ( ; push( ( ) ; S = t[5] + (a (c + b) ) [ read 5 ; // ignored read ] ; pop(); // ] matches with [ ( ( read c, +, b ; // ignored ( read ) ; pop(); // ) matches with ( read + ; ( read ( ; push( ( ) ; // ignored read ) ; pop(); // ) matches with ( ( read a, * ; // ignored Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 23 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 24 / 56
Πολυπλοκότητα Λειτουργιών Στοίβας Τα στοιχεία εισάγονται και ανακτώνται σε σταθερό χρόνο O(1). Είναι ανεξάρτητο του μεγέθους n της στοίβας. Και οι δύο λειτουργίες είναι πολύ αποδοτικές (γρήγορες). Δεν απαιτούνται συγκρίσεις/μετακινήσεις, που εμπεριέχουν κόστος. Δεν προσφέρονται οι δυνατότητες: Στοίβα Βιβλιοθήκης της Java Η Java παρέχει στοίβα στην standard βιβλιοθήκη της: Είναι «γενικευμένος» (generic) τύπος αντικειμένου. Μπορεί να «εξειδικευθεί» για οποιονδήποτε τύπο αντικειμένου. import j a v a. u t i l. S t a c k ; c l a s s StackApp { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { Stack < I n t e g e r > s t = new Stack < I n t e g e r > ( ) ; απευθείας ανάκτησης συγκεκριμένου στοιχείου ανάκτησης του i-οστού στοιχείου Μπορείτε ενδεχομένως να τις υλοποιήσετε: Τότε, ίσως δε χρειάζεστε η αποδοτικότητα μιας στοίβας. Ισως χρειάζεστε πίνακα που κατά περίπτωση λειτουργεί σαν στοίβα. s t. push ( new I n t e g e r ( 2 0 ) ) ; s t. push ( new I n t e g e r ( 4 0 ) ) ; s t. push ( new I n t e g e r ( 6 0 ) ) ; s t. push ( new I n t e g e r ( 8 0 ) ) ; while (! s t. empty ( ) ) System. out. p r i n t ( s t. pop ( ). i n t V a l u e ( ) + ) ; System. out. p r i n t l n ( ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 25 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 26 / 56 Ουρά (Queue) Μία «γραμμή αναμονής» της οποίας το μήκος: Ουρές Queues αυξάνει καθώς εισάγονται στοιχεία στο τέλος της, μικραίνει καθώς απομακρύνονται στοιχεία από την αρχή της. Αντίθετα με τη στοίβα και τα δύο άκρα χρησιμοποιούνται. Δομή Δεδομένων FIFO (First In, First Out): Διατήρηση σχετικής σειράς στοιχείων, ως προς εισαγωγή/απομάκρυνση. Στοιχείο που εισάγεται πριν από άλλο, θα εξαχθεί πιο νωρίς από το άλλο. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 27 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 28 / 56
Αναλογία με Φυσικό Κόσμο Βασικές Λειτουργίες Ουράς Ουρά αναμονής για επιβίβαση σε μέσο μαζικής μεταφοράς. Πακέτα δεδομένων που αναμένουν τη μετάδοσή τους στο Internet. Εισαγωγή στοιχείου Τοποθετείται στο τέλος της ουράς. Ουρά εκτυπωτή με εργασίες εκτύπωσης που αναμένουν επεξεργασία. Ουρά αποθήκευσης χαρακτήρων/συμβόλων που πληκτρολογούνται (π.χ., σε έναν επεξεργαστή κειμένου). Απομάκρυνση στοιχείου Απομακρύνεται από την αρχή της ουράς. z y x = = Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 29 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 30 / 56 Αναπαράσταση Ουράς Παράδειγμα Λειτουργίας Ουράς Συνίσταται στη διαχείριση των ακόλουθων αντικειμένων: τύπου int «δείκτης» στην αρχή της ουράς τύπου int «δείκτης» στο τέλος της ουράς makeempty() insert(a) a qarray τύπος πίνακα πίνακας αποθήκευσης στοιχείων ουράς Παρατηρήσεις: Θέση (στον πίνακα) επόμενης εισαγωγής στοιχείου: +1. Κενή ουρά: = 0, nitems = 0, = 1 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 31 / 56 insert(b) a b remove() remove() b Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 32 / 56
Υλοποίηση Ουράς με Πίνακα Κυκλική Αναπαράσταση Ουράς Μπορεί να υλοποιηθεί χρησιμοποιώντας πίνακα. (απομάκρυνση) Οχι αποδοτική αν μετακινούμε τα στοιχεία μετά από κάθε remove(). Σπατάλη χώρου εάν δεν χρησιμοποιούμε όλα τα κελιά. Ουρά με Κυκλικό Πίνακα Για να αντιμετωπίσουμε το πρόβλημα διαχείρισης χώρου. (εισαγωγή) Μπορούμε να φανταστούμε την ουρά σαν έναν κυκλικό πίνακα. Διατηρούμε (και πάλι) 2 δείκτες: έναν για την αρχή () και έναν για το τέλος της ουράς () Επανορισμός της κατάστασης κενής ουράς: = 0, nitems = 0, = qarray.length 1 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 33 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 34 / 56 Παράδειγμα Λειτουργίας με Κυκλικό Πίνακα (Αναδίπλωση) Λειτουργίες Ουράς Αρχικά: c d e insert ( f ) f c d e remove() f d e remove() f e remove() f Οταν οι δείκτες, που δείχνουν στο τέλος και στην αρχή της ουράς αντίστοιχα φτάσουν στο τέλος του πίνακα. Επανορίζουμε τους δείκτες ώστε να δείχνουν και οι δύο στην αρχή Βασικές Πράξεις insert(item): εισάγει το αντικείμενο item στο τέλος της ουράς. remove(): απομακρύνει/επιστρέφει το στοιχείο στην αρχή της ουράς. Βοηθητικές Λειτουργίες peek(): επιστρέφει το στοιχείο στην αρχή της ουράς. isempty(): ελέγχει εάν η ουρά είναι άδεια. isfull(): ελέγχει εάν η ουρά είναι γεμάτη. size(): αριθμός στοιχείων στην ουρά. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 35 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 36 / 56
Υλοποίηση Ουράς Ακεραίων (1/3) Υλοποίηση Ουράς (2/3) c l a s s LongQueue { p r i v a t e long [ ] qarray ; p r i v a t e i n t f r o n t ; p r i v a t e i n t r e a r ; p r i v a t e i n t nitems ; p u b l i c LongQueue ( i n t s ) { // c o n s t r u c t o r qarray = new long [ s ] ; f r o n t = 0 ; r e a r = 1; nitems = 0 ; p u b l i c boolean isempty ( ) { r e t u r n ( nitems == 0 ) ; p u b l i c boolean i s F u l l ( ) { r e t u r n ( nitems == qarray. l e n g t h ) ; p u b l i c i n t s i z e ( ) { r e t u r n ( nitems ) ; p u b l i c Long peek ( ) { i f (! isempty ( ) ) r e t u r n ( new Long ( qarray [ f r o n t ] ) ) ; r e t u r n ( n u l l ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 37 / 56 p u b l i c boolean i n s e r t ( long j ) { // put items at r e a r i f (! i s F u l l ( ) ) { r e a r = ( r e a r +1) % qarray. l e n g t h ; qarray [ r e a r ] = j ; nitems + + ; r e t u r n ( t r u e ) ; r e t u r n ( f a l s e ) ; p u b l i c Long remove ( ) { // remove from the f r o n t i f (! isempty ( ) ) { Long data = new Long ( qarray [ f r o n t ] ) ; f r o n t = ( f r o n t +1) % qarray. l e n g t h ; nitems ; r e t u r n ( data ) ; r e t u r n ( n u l l ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 38 / 56 Υλοποίηση Ουράς (3/3) με Ελέγχους c l a s s LongQueueApp { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { LongQueue Q = new LongQueue ( 5 ) ; // queue with 5 c e l l s Q. i n s e r t ( 1 0 ) ; Q. i n s e r t ( 2 0 ) ; // I n s e r t 4 items Q. i n s e r t ( 3 0 ) ; Q. i n s e r t ( 4 0 ) ; // Remove 3 items : 10, 20, 30 Q. remove ( ) ; Q. remove ( ) ; Q. remove ( ) ; Q. i n s e r t ( 5 0 ) ; Q. i n s e r t ( 6 0 ) ; // I n s e r t 4 items Q. i n s e r t ( 7 0 ) ; Q. i n s e r t ( 8 0 ) ; // ( wraps around ) while (!Q. isempty ( ) ) { // Remove and d i s p l a y a l l long n = Q. peek ( ) ; // ( 4 0, 50, 60, 70 80) Q. remove ( ) ; System. out. p r i n t ( n ) ; System. out. p r i n t ( ) ; System. out. p r i n t l n ( ) ; // end main // end c l a s s LongQueueApp Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 39 / 56 Πολυπλοκότητα Λειτουργιών Ουράς (σε πλήρη αντιστοιχία με τη στοίβα) Εισαγωγή στην / Απομάκρυνση από την ουρά σε χρόνο O(1). Είναι ανεξάρτητο του μεγέθους n της ουράς. Και οι δύο λειτουργίες είναι πολύ αποδοτικές (γρήγορες). Δεν απαιτούνται συγκρίσεις στοιχείων ή μετακινήσεις στοιχείων, που εμπεριέχουν κόστος. Ομως δεν υπάρχει δυνατότητα: απευθείας ανάκτησης ενός συγκεκριμένου στοιχείου από την ουρά. ανάκτησης του i-οστού στοιχείου. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 40 / 56
Ουρά Βιβλιοθήκης της Java Η Java παρέχει δομή ουράς στην standard βιβλιοθήκη της: Είναι «γενικευμένος» (generic) τύπος ουράς. Μπορεί να «εξειδικευθεί» για οποιονδήποτε τύπο αντικειμένου. Πράξεις εισαγωγής/απομάκρυνσης στην αρχή και στο τέλος της ουράς! import j a v a. u t i l. ArrayDeque ; c l a s s DequeApp { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { ArrayDeque < I n t e g e r > dq = new ArrayDeque < I n t e g e r > ( ) ; dq. a d d L a s t ( new I n t e g e r ( 1 5 ) ) ; dq. a d d F i r s t ( new I n t e g e r ( 2 0 ) ) ; Ουρές Προτεραιότητας Priority Queues System. out. p r i n t l n ( dq. p e e k F i r s t ( ) ) ; System. out. p r i n t l n ( dq. p e e k L a s t ( ) ) ; System. out. p r i n t l n ( dq. r e m o v e F i r s t ( ) ) ; System. out. p r i n t l n ( dq. removelast ( ) ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 41 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 42 / 56 Ουρές Προτεραιότητας: Εισαγωγή Ουρές Προτεραιότητας: Εισαγωγή Είναι πιο εξειδικευμένη δομή από τη στοίβα ή την ουρά. Οπως και στην ουρά, τα στοιχεία αφαιρώνται από την αρχή. Ομως, τα στοιχεία ταξινομούνται (κατά την εισαγωγή) έτσι, ώστε το στοιχείο με το χαμηλότερο (ή το υψηλότερο) κλειδί να βρίσκεται πάντα μπροστά. Τα στοιχεία διευθετούνται στην ουρά με βάση την σημαντικότητά τους. Το μικρότερο (μεγαλύτερο) κλειδί έχει μεγαλύτερη προτεραιότητα. Ο στόχος μας είναι να: προσπελάσουμε το σημαντικότερο στοιχείο στη συλλογή. απομακρύνουμε το στοιχείο από τη συλλογή. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 43 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 44 / 56
Λειτουργίες Υλοποίηση Επιλογές για την υλοποίηση ουράς προτεραιότητας: Ταξινομημένος Πίνακας Μία ουρά προτεραιότητας είναι ένας αφηρημένος τύπος δεδομένων (abstract data type ADT) που προσφέρει μεθόδους που επιτρέπουν: Απομάκρυνση στοιχείου με την ελάχιστη ή μέγιστη τιμή κλειδιού (στοιχείο «στην αρχή» της ουράς). Εισαγωγή. Απομάκρυνση «σημαντικότερου» στοιχείου σε χρόνο O(1). Εισαγωγή στοιχείου σε χρόνο: O(n). - Πρέπει να μετακινηθούν O(n) στοιχεία του πίνακα στη χειρότερη περίπτωση, ώστε να εισαχθεί το νέο στοιχείο στη σωστή θέση. Ποτέ δεν υλοποιούμε ουρές προτεραιότητας με ταξινομημένο πίνακα γίνεται εξαίρεση στη διάλεξη αυτή χάριν συζήτησης των λειτουργιών Σωρός (είδος δένδρου) Διευκολύνει εισαγωγή και απομάκρυνση σε χρόνο O(log n). Αντικείμενο επόμενου μαθήματος. Αυτή είναι η κατ εξοχήν μέθοδος υλοποίησης ουρών προτεραιότητας. Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 45 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 46 / 56 Ουρά Προτεραιότητας με Πίνακα (1/3) Ουρά Προτεραιότητας με Πίνακα (2/3) c l a s s LongPQueue { // Implements a Min PQueue p r i v a t e long [ ] qarray ; // s o r t e d a r r a y : max at qarray [ 0 ] p r i v a t e i n t nitems ; p u b l i c LongPQueue ( i n t s ) { // C o n s t r u c t o r qarray = new long [ s ] ; nitems = 0 ; // t r u e i f pqueue empty ( e l s e : f a l s e ) p u b l i c boolean isempty ( ) { r e t u r n ( nitems == 0 ) ; // t r u e i f pqueue f u l l ( e l s e : f a l s e ) p u b l i c boolean i s F u l l ( ) { r e t u r n ( nitems == qarray. l e n g t h ) ; // take a peek at the minimum element p u b l i c Long peek ( ) { i f ( t h i s. isempty ( ) ) r e t u r n ( n u l l ) ; e l s e r e t u r n ( new Long ( qarray [ nitems 1]) ) ; p u b l i c boolean i n s e r t ( long item ) { // i n s e r t item i n t j ; i f ( t h i s. i s F u l l ( ) ) r e t u r n ( f a l s e ) ; i f ( t h i s. isempty ( ) ) qarray [ nitems ++] = item ; e l s e { f o r ( j = nitems 1 ; j >= 0 ; j ) i f ( item <= qarray [ j ] ) break ; e l s e qarray [ j +1] = qarray [ j ] ; qarray [ j +1] = item ; nitems + + ; r e t u r n ( t r u e ) ; p u b l i c Long remove ( ) { // remove minimum item i f ( t h i s. isempty ( ) ) r e t u r n ( n u l l ) ; r e t u r n ( new Long ( qarray[ nitems ] ) ) ; Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 47 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 48 / 56
Ουρά Προτεραιότητας με Πίνακα (3/3) Ταξινόνηση με Ουρά Προτεραιότητας c l a s s LongPQApp { p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { LongPQueue pq = new LongPQueue ( 5 ) ; pq. i n s e r t ( 3 0 ) ; pq. i n s e r t ( 5 0 ) ; pq. i n s e r t ( 1 0 ) ; pq. i n s e r t ( 4 0 ) ; pq. i n s e r t ( 2 0 ) ; while (! pq. isempty ( ) ) { long item = pq. remove ( ). l o n g V a l u e ( ) ; Παράδειγμα Εισόδου: πίνακας ακεραίων αριθμών. Αλγόριθμος Ταξινόμησης: p u b l i c s t a t i c void pqsort ( long [ ] number ) { LongPQueue pq = new LongPQueue ( number. l e n g t h ) ; f o r ( i n t i = 0 ; i < number. l e n g t h ; i ++) pq. i n s e r t ( number [ i ] ) ; System. out. p r i n t ( item + ) ; // 10, 20, 30, 40, 50 // end while f o r ( i n t i = 0 ; i < number. l e n g t h ; i ++) number [ i ] = pq. remove ( ). l o n g V a l u e ( ) ; System. out. p r i n t l n ( ) ; // end main Πολυπλοκότητα? Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 49 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 50 / 56 Ασκηση 1 Υλοποίηση Ουράς με Δύο Στοίβες Διαθέτουμε δύο αντικείμενα δομής στοίβας, S1, S2. Υποστηρίζουν τις συνήθεις λειτουργίες στοίβας: push, pop, peek, isempty, isfull, size Ασκηση 1 Υλοποίηση Ουράς με Δύο Στοίβες c l a s s Queue { p r i v a t e S t a c k S1 ; p r i v a t e S t a c k S2 ; Ζητούνται υλοποιήσεις των insert και remove «εικονικής» ουράς: μόνο με χρήση των δύο στοιβών S1, S2, σαν αποθηκευτικό μέσο, μόνο με χρήση των λειτουργιών στοίβας (επί των S1, S2). Να δοθούν δύο υλοποιήσεις: 1. Στην πρώτη, η λειτουργία insert να είναι χρόνου O(1). 2. Στη δεύτερη, η λειτουργία remove να είναι χρόνου O(1). p u b l i c Queue ( i n t maxsize ) { S1 = new S t a c k ( maxsize ) ; S2 = new S t a c k ( maxsize ) ; p u b l i c void i n s e r t ( i n t item ) { /* implementation??? */ p u b l i c i n t remove ( ) { /* implementation??? */ Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 51 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 52 / 56
Ασκηση 1 - insert σε χρόνο (1) p u b l i c void i n s e r t ( i n t item ) { S1. push ( item ) ; p u b l i c i n t remove ( ) { while (! S1. isempty ( ) ) // Overturn S1 i n t o S2 S2. push ( S1. pop ( ) ) ; i n t item = S2. pop ( ) ; // Top of S2 was bottom i n S1 // ( was f i r s t i n ) while (! S2. isempty ( ) ) // Restore S1 without item S1. push ( S2. pop ( ) ) ; r e t u r n ( item ) ; // Return f i r s t i n as f i r s t out Πολυπλοκότητα της remove: O(n). Ασκηση 2 Υλοποίηση Στοίβας με Δύο Ουρές Διαθέτουμε δύο αντικείμενα δομής ουράς, Q1, Q2. Υποστηρίζουν τις συνήθεις λειτουργίες ουρών: insert, remove, peekfront, isempty, isfull, size Ζητούνται υλοποιήσεις των push και pop «εικονικής» στοίβας: μόνο με χρήση των δύο ουρών Q1, Q2, σαν αποθηκευτικό μέσο, μόνο με χρήση των λειτουργιών ουράς (επί των Q1, Q2). Να δοθούν δύο υλοποιήσεις: 1. Στην πρώτη, η λειτουργία pop να είναι χρόνου O(1). 2. Στη δεύτερη, η λειτουργία push να είναι χρόνου O(1). Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 53 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 54 / 56 Ασκηση 2 Ασκηση 2 pop σε χρόνο O(1) Υλοποίηση Στοίβας με Δύο Ουρές c l a s s S t a c k { p r i v a t e Queue Q1 ; p r i v a t e Queue Q2 ; p u b l i c S t a c k ( i n t maxsize ) { Q1 = new Queue ( maxsize ) ; Q2 = new Queue ( maxsize ) ; p u b l i c void push ( i n t item ) { /* implementation??? */ p u b l i c i n t pop ( ) { r e t u r n ( Q1. remove ( ) ) ; p u b l i c void push ( i n t item ) { Q2. i n s e r t ( item ) ; // I n s e r t i n Q2 while (! Q1. isempty ( ) ) // Empty Q1 i n t o Q2 Q2. i n s e r t ( Q1. remove ( ) ) ; Queue tempq = Q1 ; // Exchange the queues names Q1 = Q2 ; Q2 = tempq ; p u b l i c i n t pop ( ) { /* implementation??? */ Πολυπλοκότητα της push: O(n). Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 55 / 56 Ο. Τελέλης Πανεπιστήμιο Πειραιώς Δομές Δεδομένων 56 / 56