Π. ΚΡΗΤΗΣ, ΤΜΗΜΑ ΕΠΙΣΤΗΜΗΣ ΥΠΟΛΟΓΙΣΤΩΝ ΗΥ 380, «ΑΛΓΟΡΙΘΜΟΙ & ΠΟΛΥΠΛΟΚΟΤΗΤΑ» Φ 06: ΧΡΗΣΗ ΔΟΜΩΝ ΔΕΔΟΜΕΝΩΝ Η «μάχη» για καλούς αλγορίθμους έχει σε αδρές γραμμές 4 επίπεδα: Υπάρχει αλγόριθμος; Υπάρχει «δραστικός» αλγόριθμος; Υπάρχει ταχύτερος; («επιτάχυνση») Έχουμε βρεί τον βέλτιστο; Προσπαθούμε να διακριτοποιήσουμε το πρόβλημα, να περιορίσουμε δηλαδή την αναζήτηση λύσης σε ένα χώρο με πεπερασμένου πλήθους λύσεις, κάθε μία με πεπερασμένη περιγραφή. Προσπαθούμε να αποφύγουμε εκθετικές λύσεις τύπου «2 Ν», και επιδιώκουμε «πολυωνυμικές» πλοκές, τύπου «Ν κ» (όπου Ν το πλήθος των δεδομένων). Προσπαθούμε να βελτιώσουμε την ταχύτητα του αλγορίθμου μας (λ.χ. Ν 2 ΝlogN, N 3 N 2.81 ή και να βρούμε μια εντελώς καινούργια ιδέα και λύση...... ή να δείξουμε ότι έχουμε ήδη λύσει το εκάστοτε πρόβλημά μας κατά τον (ασυμπτωτικά) καλύτερο δυνατό τρόπο. Το κυριότερο εργαλείο για την βελτίωση (ή «επιτάχυνση») ενός δεδομένου αλγορίθμου είναι οι δομές δεδομένων. To χρονικό κόστος των αλγορίθμων προέρχεται από τις «επαναληπτικές» εντολές, δηλαδή από ενέργειες (= εντολές), που επαναλαμβάνονται πολλές φορές. Οι «δομές δεδομένων» έχουν επινοηθεί για αυτόν ακριβώς τον σκοπό: πρόκειται για δεδομένα οργανωμένα κατά τρόπο ώστε ορισμένες συχνά επαναλαμβανόμενες ενέργειες και ερωτήματα που αφορούν σε αυτά να γίνονται κατά τον ταχύτερο δυνατόν τρόπο. Θα πρέπει να έχετε υπόψι σας το εξής βασικό ρεπερτόριο από ήδη γνωστές δομές δεδομένων: 5 ΘΕΜΕΛΙΑΚΕΣ ΔΟΜΕΣ ΔΕΔΟΜΕΝΩΝ ΓΕΝΙΚΕΣ ΜΕΘΟΔΟΙ SetUp Κατασκευάζει μια κενή δομή του τύπου που ζητείται. NotEmpty: ΝΑΙ/ΟΧΙ Διαγιγνώσκει εάν η δομή είναι κενή στοιχείων. ΣΤΟΙΒΑ (STACK) Push(σ) Top: σ Pop: σ Αποθέτει ένα στοιχείο στην κορυφή μιας στοίβας. Δεικνύει το κορυφαίο στοιχείο. Ανασύρει από την στοίβα το κορυφαίο (= πιο «πρόσφατο») στοιχείο. ΟΥΡΑ ΑΝΑΜΟΝΗΣ (QUEUE) EnQueue(σ) Head: σ DeQeue: σ Αποθέτει ένα στοιχείο στο τέλος μιας ουράς. Δεικνύει το στοιχείο στην κεφαλή της ουράς. Αποσύρει από την ουρά το πρώτο (= πιο «παλαιό») στοιχείο. ΟΥΡΑ ΠΡΟΤΕΡΑΙΟΤΗΤΑΣ (PRIORITY QUEUE) ΕΥΡΕΤΗΡΙΟ (DIRECTORY) Insert(σ, π) Εισάγει στοιχείο σ στην ουρά, με προτεραιότητα π. FindMin: σ DeleteMin: σ Διαγράφει το στοιχείο πρώτης προτεραιότητας Union Ενώνει δύο ουρές προτεραιότητας σε μία. Promote(σ, π ) Insert(σ) Δεικνύει το στοιχείο «πρώτης» προτεραιότητας, (εδώ: με minimum π). Προσδίδει στο στοιχείο σ νέα και υψηλότερη προτεραιότητα π. Εισάγει στη δομή το σ (μέλος μιας ολικής διάταξης στοιχείων). Find(σ): ΝΑΙ/ΟΧΙ Εντοπίζει (ή όχι) στη δομή το στοιχείο σ. Delete(σ) Διαγράφει το στοιχείο σ. ΚΛΑΣΕΙΣ ΙΣΟΔΥΝΑΜΙΑΣ (DISJOINT SET UNION) Make class(σ) Δημιουργεί ένα νέο (μονο)σύνολο με το στοιχείο σ. Find class(σ): δ Δεικνύει το σύνολο που περιέχει το σ. Union class(α, β) Ενώνει τα δύο σύνολα που περιέχουν τα α και β σε ένα νέο σύνολο. Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 1/8
Δομές παραδείγματα χρήσης Η θεμελιακή ικανότητα που πρέπει να αναπτύξετε είναι να μπορείτε, δεδομένης της περιγραφής ενός αλγορίθμου ή ενός απλού αλγοριθμικού προβλήματος, να μπορείτε να διαπιστώνετε ποιές είναι εκείνες οι ενέργειες και ερωτήματα που επανέρχονται συνέχεια (και επί ποίου συνόλου δεδομένων) ώστε να είστε σε θέση να διαγιγνώσκεται τί είδους «δομή δεδομένων» ταιριάζει στον αλγόριθμο αυτή. Αυτή η δομή μπορεί να είναι είτε μια ήδη γνωστή, είτε μια κάποια παραλλαγή μιας ήδη γνωστής, είτε και μία εντελώς νέου ειδους. Το καλύτερο που έχουμε να κάνουμε εδώ είναι να δώσουμε μια σειρά από χαρακτηριστικά παραδείγματα: Παράδειγμα 1 ο ΣΤΟΙΒΑ (STACK) (Το παραλείπουμε εδώ: οι στοίβες χρησιμοποιούνται για την υλοποίηση των αναδρομικών συναρτήσεων και διαδικασιών, και έτσι υλοποιούνται κατά κόρο στα γλωσσο μεταφραστικά συστήματα.) Παράδειγμα 2 ο ΟΥΡΑ (QUEUE) Έχουμε ένα αμφίδρομο γράφημα, δηλαδή Ν «κόμβους» όπου και κάθε κόμβος έχει ένα πλήθος από γειτονικά στοιχεία. Θελουμε αρχίζοντας από έναν δεδομένο αφετηριακό κόμβο να κατασκευάσουμε τα «επίπεδα» αυτόυ γραφήματος: στο 1 ο βάζουμε τους γειτονικούς του αφετηριακού κόμβου, στο 2 ο τους γειτονικούς των γειτονικών (όσους δεν έχουμε ήδη συμπεριλάβει στο 1 ο ) κοκ. Η διαδικασία αυτή είναι προφανές ότι μπορεί να γίνει «εύκολα». Τι είδους δομή δεδομένων χρειαζόμαστε για την κάνουμε «γρήγορα»; Το σύνολο που χειριζόμαστε είναι ο κόμβοι. Εξετάζοντας έναν κόμβο, εξετάζουμε όλους τους γειτονικούς τους, και όσους εξ αυτών δεν έχουμε ήδη επισκεφθεί πρέπει να τους αποθηκεύσουμε κάπου «προς μελλοντική εξέταση» διότι αποτελούν το επόμενο επίπεδο. Χρειαζόμαστε προφανώς μια λειτουργία εισαγωγής για να καταχωρίζουμε τα στοιχεία. Χρειαζόμαστε προφανώς μια λειτουργία λήψης στοιχείου για να λαμβάνουμε το εκάστοτε επόμενο προς εξέταση, Και επειδή τα «προς μελλοντική εξέταση» εξέταση στοιχεία πρέπει να εξεταστούν μετά από όλα όσα είναι ήδη «τώρα» προς εξέταση, αυτά πρέπει να καταχωριστούν «μετά» από όλα όσα έχουμε ήδη αποθηκευμένα (για να είμαστε ασφαλείς). Εχουμε επομεένως μια «ουρά» αναμονής, όπου από εξετάζουμε τον 1 ο της ουράς, και ότι νέο στοιχείο έρχεται προστίθεται στο τέλος αυτής. Συμπέρασμα: χρειαζόμαστε μια ΟΥΡΑ, με λειτουργίες EnQueue (βάλε στο τέλος), και DeQueue (βρες το 1 ο και πάρε το από την ουρά). Ενδεικτικός ψευδοκώδικας : // Q: η δομή της ουράς (αναμονής) { Για όλους του κόμβους κ { Επίπεδο[κ] 0 } Επίπεδο[αφετηρία] 1 Q.SETUP Q.ENQUEUE(αφετηρία) Εφόσον Q.NOTEMPTY { κ Q.DEQUEUE Για όλους τους γειτονικούς γ του κ { Εάν Επίπεδο(γ)=0 τότε { Επίπεδο[γ] Επίπεδο[κ]+1, Q.ENQUEUE(γ) } } } } Παράδειγμα 3 ο ΟΥΡΑ ΠΡΟΤΕΡΑΙΟΤΗΤΑΣ (PRIORITY QUEUE) Έχουμε Ν στοιχεία {ακ: κ = 1...Ν}, και θέλουμε να τα ταξινομήσουμε βρίσκοντας κάθε φορά τον ελάχιστο από αυτούς. Τί είδους δομή όμως θα μας βοηθούσε να το κάνουμε αυτό γρήγορα; Το σύνολο που χειριζόμαστε είναι τα Ν στοιχεία, και. Το ερώτημα που επανέρχεται είναι να βρίσκουμε το ελάχιστο από αυτά, και να το αφαιρούμε. Χρειαζόμαστε προφανώς μια λειτουργία εισαγωγής για να κατασκευάσουμε την δομή. Και στη συνέχεια χρειαζόμαστε την δυνατότητα εντοπισμού του ελαχίστου και της διαγραφής του. Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 2/8
Συμπέρασμα: χρειαζόμαστε μια ΟΥΡΑ ΠΡΟΤΕΡΑΙΟΤΗΤΑΣ, (insert, find min, delete min). Πρόκειται για το «αρχετυπικό» παράδειγμα δομής δεδομένων και ιστορικώς ενός από τα πρώτα. Ενδεικτικός ψευδοκώδικας : // PQ: η δομή της ουράς (προτεραιότητας) { Q.SETUP Για κ =1 έως Ν { Q.INSERT(T[k], T[k]) Για κ =1 έως Ν { T[k] PQ.FINDMIN, PQ.DELETEMIN } } Παράδειγμα 4 ο ΕΥΡΕΤΗΡΙΟ (DIRECTORY) Μας δίδονται Ν ξένα μεταξύ τους διαστήματα Ικ = (ακ, βκ), και θα μας δίδεται μια ακολουθία σημείων σ, με ζητούμενο να εντοπίζουμε σε ποιό διάστημα είναι το εκάστοτε σ. Τί είδους δομή όμως θα μας βοηθούσε να κάνουμε αυτή την εξέταση (πιο) γρήγορα; Προσέχουμε ότι τα διαστήματα διατάσσονται αφού είναι ξένα: ισχύει Ικ < Ιλ, εάν βκ < αλ. Το ίδιο ισχύει και για τα σημεία ως προς τα διαστήματα (αν θεωρήσουμε το σ ως διάστημα [σ, σ]): εάν σ < ακ τότε σ < Ικ. εάν σ > βκ τότε σ > Ικ. και εάν ακ σ βκ τότε σ = Ικ (δηλαδή αναφέρουμε ότι σ Ικ). Εμφανίζεται λοιπόν η ανάγκη καταχώρισης ενός συνόλου διατάξιμων στοπιχείων (εδώ: διαστημάτων ως προς την διάταξη <, και η επαναλαμβανόμενος εντοπισμός (find) ενός οποιουδήποτε στοιχείου (εδώ [σ, σ]). Συμπέρασμα: χρειαζόμαστε ένα ΕΥΡΕΤΗΡΙΟ (insert, find) (το οποίο θα μπορούσε να είναι και στατικό, (όχι δυναμικό), αφού δεν έχουμε εδώ διαγραφές, (delete)). Ενδεικτικός ψευδοκώδικας : // D: η δομή του ευρετηρίου (ως προς την διάταξη < που περιγράφεται παραπάνω) { D.SETUP Για όλα τα διαστήματα Ι κ { D.INSERT(Ι κ )} Για όλα τα διδόμενα σημεία σ { Διάστημα-του-σ D.FIND( [σ,σ] )} } Παράδειγμα 5 ο (ΕΠΑΥΞΗΜΕΝΗ) ΟΥΡΑ ΠΡΟΤΕΡΑΙΟΤΗΤΑΣ (PRIORITY QUEUE) Έχουμε ένα αμφίδρομο γράφημα, δηλαδή Ν «κόμβους» όπου κάθε κόμβος έχει ένα πλήθος από γειτονικά στοιχεία. Το πλήθος αυτό το ονομάζουμε βαθμό του κόμβου. Θέλουμε να «απαλείφουμε» τον κόμβο με τον ελάχιστο βαθμό, και να το κάνουμε αυτό επαναληπτικά έως ότου εξετάσουμε όλους τους κόμβους: όσο υπάρχουν κόμβοι, διάγραψε τον ελαχιστοβάθμιο κόμβο (και φυσικά όσες ακμές προσπίπτουν σ αυτόν). (Το «ξήλωμα» αυτό χρησιμεύει στο να βρούμε εκείνο το υποσύνολο κόμβων που έχει μεταξύ τους το μέγιστο μέσο βαθμό αλλά αυτό δεν μας ενδιαφέρει εδώ.) Η διαδικασία αυτή είναι προφανές ότι μπορεί να γίνει «εύκολα». Τι είδους δομή δεδομένων θα μας βοηθούσε όμως να την κάνουμε «γρήγορα»; Το σύνολο που χειριζόμαστε είναι ο κόμβοι, και για κάθε κόμβο η κρίσιμη πληροφορία είναι ο βαθμός του. Το ερώτημα που επανέρχεται είναι να βρίσκουμε εκείνον με τον ελάχιστο βαθμό. Χρειαζόμαστε προφανώς μια λειτουργία εισαγωγής για να κατασκευάσουμε την όποια δομή, Και μια λειτουργία εντοπισμού του ελαχίστου. Επειδή στη συνέχεια δεν θέλουμε να λάβουμε υπόψι μας αυτόν τον κόμβο χρειαζόμαστε μια λειτουργία διαγραφής (ιδίως του εκάστοτε ελαχίστου). Η αφαίρεση όμως ενός κόμβου μειώνει (κατά 1) τον βαθμό των γειτονικών του, άρα χρειαζόμαστε και μια λειτουργία μείωσης του βαθμού (δηλαδή αύξησης της προτεραιότητας). Συμπέρασμα: χρειαζόμαστε μια ΟΥΡΑ ΠΡΟΤΕΡΑΙΟΤΗΤΑΣ, (insert, find min, delete min), στην οποία να είναι δυνατόν να «αυξάνουμε» την προτεραιότητα ενός στοιχείου (promote(σ)). Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 3/8
Ενδεικτικός ψευδοκώδικας : // PQ: η δομή της ουράς προτεραιότητας { PQ.SETUP Για όλους του κόμβους κ { PQ.ENQUEUE(κ, βαθμός(κ))} Εφόσον PQ.NOTEMPTY { κ PQ.DEQUEUE Για όλους τους γειτονικούς γ του κ { Αφαιρούμε ακμή (κ,γ) από τον γειτονικό γ PQ.PROMOTE(γ, βαθμός(γ)-1) } } } Παράδειγμα 6 ο ΚΛΑΣΕΙΣ ΙΣΟΔΥΝΑΜΙΑΣ ( DISJOINT SETS ) Έχουμε ένα αμφίδρομο γράφημα, δηλαδή Ν «κόμβους» όπου κάθε κόμβος έχει ένα πλήθος από γειτονικά στοιχεία, με τα οποία συνδέεται με ακμές. Θέλουμε να εξετάσουμε όλες τις ακμές (με κάποια σειρά που έχει την οποιαδήποτε σημασία για μας) και εάν μια υπό εξέταση ακμή e μας συνδέει δύο διαφορετικά σύνολα κόμβων, θέλουμε να τα ενώσουμε, να σημειώσουμε δηλαδή ότι αυτά αποτελούν πλέον ένα ενιαίο σύνολο. εξετάζουμε μία μία τις ακμές (α, β), και, εάν τα άκρα α, β ανήκουν σε διαφορετικές συνιστώσες, τις ενώνουμε αλλιώς αγνοούμε την ακμή. Τι είδους δομή δεδομένων θα μας βοηθούσε όμως να κάνουμε «γρήγορα» την παραπάνω διαδικασία; Προσέξτε εδώ ότι για άλλη μια φορά δεν χρειάζεται να γνωρίζουμε τί ακριβώς «επιδιώκει» ο αλγόριθμος. Αρκεί να διαγνώσουμε τί είδους ενέργειες εκτελεί επανειλημμένα και επί ποίου συνόλου στοιχείων. Προσέξτε επίσης ότι για άλλη μια φορά σε 2 γραμμές παρουσίασης του «αλγορίθμου» θα εμφανιστούν τελικα 5 χειρισμοί μια δομής δηλαδή αν και οι εκφραστικές γλώσσες είνα χρήσιμες με τον τρόπο τους η διαπίστωση του ποιά δομή είναι η κατάλληλης είναι μια αναλυτική διαδικασία. Αυτό που χειριζόμαστε δεν είναι κόμβοι αλλά είναι σύνολα κόμβων. Στην αρχή κάθε κόμβος αποτελεί ένα μονοσύνολο. Το ερώτημα που επανέρχεται με κάθε ακμή (κ,λ) είναι: «τα στοιχεία κ, λ ανήκουν στο ίδιο ή σε διαφορετικά σύνολα;». Προφανώς για να απαντάμε αυτό το ερώτημα πρέπει να απαντάμε το πιο θεμελιακό ερώτημα: «το στοιχείο κ σε ποιό σύνολο ανήκει». Η ενέργεια που επανέρχεται είναι «δεδομένων των συνόλων α και β, ένωσέ τα». Χρειαζόμαστε λοιπόν, μια λειτουργία κατασκευής για να κατασκευάσουμε τα αρχικά σύνολο, Make class(σ), μία λειτουργία διαπίστωσης του σε ποιό σύνολο ανήκει ένα στοιχείο σ, «Find class(σ)», και μια λειτουργία ένωσης δύο συνόλων, Union class(α,β). Συμπέρασμα: χρειαζόμαστε μια δομή «ΚΛΑΣΕΩΝ ΙΣΟΔΥΝΑΜΙΑΣ» (ή ισοδυνάμως χειρισμού ξένων συνόλων (disjoint set union)), με λειτουργίες make class, find class, union class, Την σχεδίαση και ανάλυση αυτής της δομής αξίζει να αναζητήσετε στην βιβλιογραφία. Ενδεικτικός ψευδοκώδικας : // EC: η δομή της κλάσεων ισοδυναμίας { EC.SETUP Για όλους του κόμβους κ { EC.MAKECLASS(κ) } Για όλες τις ακμές e = (α,β) κατά σειρά αύξοντος βάρους { C α EC.FINDCLASS(α) C β EC.FINDCLASS(β) Εάν C α C β τότε { EC.UNIONCLASS(C a,c β } } } } Παράδειγμα 7 ο ΔΙΑΧΡΟΝΙΚΑ ΕΥΡΕΤΗΡΙΑ Το παράδειγμα αυτό είναι φαινομενικά λίγο «ακραίο μας δίνει όμως ένα πολύ καλό μάθημα για το πόσο ευφάνταστοι και δημιουργικοί χρειάζεται να είμαστε στην περιοχή των αλγορίθμων. Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 4/8
Ας υποθέσουμε ότι έχουμε Ν ορθογώνια (με πλευρές παράλληλες στους δύο άξονες συντεταγμένων). Για απλότητα ας τα θεωρήσουμε ξένα μεταξύ τους. Θα θέλαμε δεδομένου ενός σημείου (x,y) να μπορούμε γρήγορα να εντοπίζουμε σε ποιό από τα ορθογώνια περιλαμβάνεται (όταν αυτό συμβαίνει). Προσέξτε ότι η κατακόρυφη ευθεία που περνά από αυτό (από την x συντεταγμένη του) διατέμνει ίσως κάποια ορθογώνια, με αποτέλεσμα να ορίζονται επ αυτής μια σειρά ξένων διαστημάτων. Αρκεί στη συνέχεια να εντοπίσουμε την y συντεταγμένη σε αυτό το σύνολο «διατομών». Αυτό το 2 ο πρόβλημα είναι προφανώς πρόβλημα για το οποίο αρκεί μια δομή ΕΥΡΕΤΗΡΙΟΥ. Insert διατομή Delete διατομή (x, y) Εκδοχές Εκδοχές 1 η 2 η 3 η 4 η 5 η εκδοχή για το x, προς εντοπισμό του y Tο ποιό θα είναι ομως αυτό το ευρετήριο διαφέρει από x σε x: τα Ν ορθογώνια έχουν μια αριστερή και μια δεξιά πλευρά και αυτές δημιουργούν 2Ν προβολές στον άξονα των x. Από προβολή σε προβολή δημιουργείται και μια διαφορετική «ΔΙΑΤΟΜΗ» (= σύνολο διαστημάτων που θελουμε να οργανώσουε ως ΕΥΡΕΤΗΡΙΟ). Αν τις εξετάσουμε από αριστερά προς τα δεξιά, όταν συναντάμε την αριστερή πλευρά ενός ορθογωνίου τότε πρέπει να εισάγουμε στο ευρετήριο «ΔΙΑΤΟΜΕΣ» την διατομή αυτού του ορθογώνιου. Και όταν συναντάμε την δεξιά πλευρά ενός ορθογωνίου τότε πρέπει να διαγράψουμε από «ΔΙΑΤΟΜΕΣ» την διατομή αυτού του ορθογώνιου. Αυτό που χειριζόμαστε είναι (ξένα) διαστήματα που διατάσσονται κατά μήκος μιας κατακόρυφης γραμμής. Στις «ΔΙΑΤΟΜΕΣ» αυτές εισάγονται και διαγράφονται στοιχεία, προκύπτει δηλαδή ένα ιστορικό ενέργειών εισαγωγής και διαγραφής, κάθε μία των οποίων παράγει μια εκδοχή. Πρέπει να επίσης να αναζητώνται κάποιες y συντεταγμένες, και μάλιστα σε οποιαδήποτε από τις εκδοχές που έχουν παραχθεί. Συμπέρασμα: χρειαζόμαστε ένα δυναμικό ΕΥΡΕΤΗΡΙΟ το οποίο εμφανίζει ένα ιστορικό εκδοχών (και θέλουμε να θυμόμαστε όλες τις εκδοχές, ώστε να μπορούμενα αναζητούμε ένα στοιχείο σε μια οποιαδήποτε από αυτές). Μπορούμε να το κάνουμε αυτό «οικονομικά» χωρίς να κρατήσουμε δηλαδή πλήρη αντίγραφα όλων των εκδοχών του ευρετηρίου των διατομών; (Αυτό θα απαιτούσε στη χειρότερη περίπτωση μεγάλη σπατάλη μνήμης, αφού τα ίδια και ίδια στοιχεία θα αποθηκεύονταν σε πολλαπλά αντίγραφα). (ΜΕΡΙΚΩΣ ) ΔΙΑΧΡΟΝΙΚΟ ΕΥΡΕΤΗΡΙΟ Insert(σ) Εισάγει στη τελευταία εκδοχή της δομής το σ. Find( κ, σ): ΝΑΙ/ΟΧΙ Εντοπίζει (ή όχι) στην υπ.αρ. κ εκδοχή της δομής το στοιχείο σ. Delete(σ) Διαγράφει από την τελευταία εκδοχή της δομής το στοιχείο σ. Αν είχαμε μια τέτοια δομή, τότε, από τον x συντεταγμένη ενός σημείου θα διαπιστώναμε σε Θ(logΝ) χρόνο σε ποιά εκδοχή υπ.αρ. κ των ευρετηρίου των διατομών θα έπρεπε να αναφερθούμε, και, Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 5/8
από την y συντεταγμένη θα διαπιστώναμε εάν αυτό περιλαμβάνεται ή οχι σε κάποια διατομή (εάν δηλαδή ανήκει ή όχι σε ένα ορθογώνιο, και ποιό). Αυτές οι δομές που θυμούνται κατά οικονομικό τρόπο την ιστορία τους ονομάζονται «διαχρονικές». Μπορούμε να έχουμε διαχρονικές δομές; Ναι, είναι δυνατόν και την σχεδίαση και ανάλυση τέτοιων περιπτώσεων αξίζει να αναζητήσετε στην βιβλιογραφία (υπό τον όρο διαχρονικές δομές ως απόδοση του persistant data structures). Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 6/8
Προς ΕΞΑΣΚΗΣΗ Βασιζόμενοι στα προηγούμενα παραδείγματα θα πρέπει να είστε σε θέση να λύσετε τα παρακάτω προβλήματα. Δώσατε γραπτώς 3 από αυτά με τις απαραίτητες εξηγήσεις. 1. Δίδονται Ν 3 σημεία στο επίπεδο, Ρ1,..., ΡΝ, ταξινομημένα από αριστερά προς τα δεξιά. Θέλουμε να βρούμε τα «κορυφαία» από αυτά, δηλαδή το άνω μέρος του κυρτού περιβλήματος των σημείων. Προς τούτο κάνουμε το εξής: y Κ Ρ 1 Ρ 2 Ρ λ Ρ λ+1...... Ρ Ν x Εξετάζουμε την διατεταγμένη ακολουθία των σημείων Ρ, και φτιάχνουμε μια νέα ακολουθία Κ. Αρχικά εισάγουμε στην Κ τα δύο πρώτα σημεία Α, Β της Ρ. Όσο δεν έχουμε εξαντλήσει την σειρά Ρ, ελέγχουμε το εξής: Θέτουμε ως Γ το επόμενο προς εξέταση της ακολουθίας Ρ (αρχικά είναι το 3 ο ). Εάν το, ενδιάμεσο, σημείο Β είναι «κάτω» από την γραμμή ΑΓ, διαγράφουμε το Β από την σειρά Κ, ανασύρουμε ως (Α, Β) τα δύο πιο πρόσφατα σημεία της Κ, και επανελέγχουμε έως ότου το Β βρεθεί πάνω από την ΑΓ, ή η Κ απομείνει με ένα μόνον σημείο. Αποθέτουμε το σημείο Γ στη σειρά Κ ως το πιο πρόσφατο αυτής, και επαναλαμβάνουμε. Η ακολουθία Κ που σχηματίζεται είναι το άνω κυρτό περίβλημα της Ρ. Ποιά «δομή δεδομένων» υποκρύπτεται (και πώς θα την αξιοποιούσαμε); 2. Μας δίδεται ένα κυρτό πολύγωνο Π με Ν κορυφές και θέλουμε να εξετάζουμε (σε επαναλαμβανόμενες περιπτώσεις) εάν ένα διδόμενο σημείο Σ κείται εντός του Π ή όχι. Θυμίζουμε ότι μπορούμε να εξακριβώνουμε εάν ένα σημείο Σ κείται εντός μιας γωνίας Οxy σε Θ(1) βήματα (ελέγχοντας εάν 0 (ΟxΣ) (Οxy) ). Ποιά «δομή δεδομένων» υποκρύπτεται (και πώς θα την αξιοποιούσαμε); 3. Μας δίδεται ένα σύνολο αριθμών (διαφόρων ανά δύο προς απλούστευση), το οποίο είναι δυναμικό, δηλαδή μεταβάλλεται υπό καθεστώς αυθαίρετων εισαγωγών και διαγραφών. Θέλουμε να είμαστε σε θέση να απαντάμε το ταχύτερον δυνατόν (σε Θ(1) χρόνο) το ποιό εξ αυτών είναι το διάμεσο στοιχείο μ δηλαδή εκείνο το οποίο έχει Ν /2 ± 1 μικρότερα στοιχεία, και Ν /2 ± 1 μεγαλύτερα, αν τα διαθέσιμα στοιχεία την στιγμή της ερώτησης είναι Ν το πλήθος. Οι λειτουργίες θα ήσαν: Διαδικασία INSERT(a) Συνάρτηση FINDMEDIAN: αριθμός Διαδικασία DELETEMEDIAN Ποιά «δομή δεδομένων» υποκρύπτεται (και πώς θα την αξιοποιούσαμε); Υπόδειξη: Αρκεί ένα είδος δομής, αν και σε δύο «αντίτυπα». 4. Δίδονται Ν τριάδες ακεραίων και θέλουμε να εξακριβώσουμε εάν υπάρχουν ή όχι τρείς εξ αυτών Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 7/8
που αθροίζονται στο μηδέν: ai + aj + ak = 0. Όλες οι τριάδες είναι Θ(Ν 3 ), αλλά όλα τα ζεύγη (ai, aj) είναι «μόνο» Θ(Ν 2 ). Ποιά «δομή δεδομένων» θα βοηθούσε να ελέγξουμε εξαντλητικά τα ζεύγη (και όχι τριάδες); 5. Μας δίδονται Ν οριζόντια ευθύγραμμα τμήματα Ικ στο ημι επίπεδο πάνω από τον άξονα x τα άκρα τους είναι τα (Ακ, Υκ) (Βκ, Υκ). Ταξινομώντας τα σημεία Ακ, Βκ πάνω στον οριζόντιο άξονα παίρνουμε 2Ν σημεία Ρλ που χωρίζουν το επίπεδο σε 2Ν+1 ζώνες «Ρλ x Ρλ+1». y ορατά τμήματα Α κ Β κ Υ κ I κ Ρ 1 Ρ λ Ζ Ρ λ+1 x Αν «περπατήσουμε» κατά μήκος του άξονα x (λ.χ. από αριστερά προς τα δεξιά), τότε κυττώντας από κάθε σημείο Ζ κατακόρυφα, ένα και μόνο τμήμα Ικ θα είναι ορατό, και αυτό θα μένει το ίδιο σε κάθε «ζώνη» (τουλάχιστον). Για να εντοπίσουμε τα ορατά τμήματα σε όλες τις ζώνες εξαντλητικά, θα χρειαστούμε Θ(Ν 2 ) χρόνο. Μπορούμε ταχύτερα; Ποιά «δομή δεδομένων» υποκρύπτεται (και πώς θα την αξιοποιούσαμε); Πανεπιστήμιο Κρήτης Τμ. Επιστήμης υπολογιστών «Αλγόριθμοι & πολυπλοκότητα, ΗΥ380 Γεώργιος Φ.Δ. Γεωργακόπουλος, 1/5/2014, 8/8