(5 ο ) Η «πλοκή» ενός αλγορίθμου: η βάση μιας αξιολόγησης Ι (6 ο ) Η «πλοκή» ενός αλγορίθμου: ο Ο Ω Θ συμβολισμός ΙΙ Έχουμε συγκεκτρώσει τα στοιχεία που χρειαζόμαστε για να μπορέσουμε να πούμε περί αλγορίθμων τα όσα θα θέλαμε και θα έπρεπε. Είδαμε τα προβλήματα και τις πρακτικές τους πηγές, τους αλγορίθμους (έστω ως τα γνωστά μας «προγράμματα»), και είδαμε ότι οι απλές, ή μάλλον απλοϊκές τεχνικές δεν (λ.χ. μια εξαντλητική αναζήτηση) συχνότατα δεν αποδίδουν. Τί ζητάμε τότε; Ακόμα και για να το διατυπώσουμε θα χρειαστούμε λίγη προσπάθεια αυτήν που θα καταβάλουμε στον παρόν κεφάλαιο: Χρειαζόμαστε έναν τρόπο να «ορισουμε» και στην συνέχεια α «μετρήσουμε» την δραστικότητα ενός αλγορίθμου, το πόσο γρήγορα δηλαδή μπορεί να επιφέρει τα αποτελέσματά του. Προς τούτο θα πρέπει να μιλήσουμε για αυτά τα θέματά μέσα σε ένα σαφές εννοιολογικό πλαίσιο: Προβλήματα & αλγόριθμοι: το τυπικό («φορμαλιστικό») πλαίσιο. Για να μελετήσουμε τα προβλήματα και τους αλγορίθμους με όση αυστηρότητα χρειάζεται ώστε να μπορούμε να τα καταστήσουμε αντικείμενα ακριβούς μαθηματικής ανάλυσης και μέτρησης, αρκούν σχετικά λίγα στοιχεία τα εξής: Σ λ D Σ* R Σ* Q D R Ένα πεπερασμένο σύνολο συμβόλων {σ1, σ2,..., σk } για να «γράφουμε» λέξεις, δηλαδή πληροφορίες. Το αλφάβητο ASCII έχει μείνει ιστορικό, σε ευρεία διάδοση έχουμε τώρα το Uicode, αλλά γνωρίζουμε πως ακόμα το ελάχιστο ταπεινό δυαδικό αλφάβητο {0,1}, αρκεί για την παράσταση κάθε ενδεχόμενης πληροφορίας. Λέξεις εξ αυτού του αλφαβήτου, δηλαδή πεπερασμένες ακολουθίες συμβόλων λ1, λ2,..., λν, λi Σ. Θα συμβολίζουμε με Σ* το σύνολο όλων των πεπερασμένων λέξεων που φτιάχνονται από σύμβολα του Σ. Π.χ. η λέξη +2, 3,+1 επί του αλφαβήτου Σ = { +,, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,, } αρκεί για να παραστήσει την πολυωνυμική εξίσωση «2x 2 3x + 1 = 0». Προσέξτε επίσης, ότι τα αρχεία των συνηθισμένων δίσκων των υπολογιστικών συσκευών μας δεν είναι παρά ακολουθίες από bytes δηλαδή λέξεις από τα οκταδυφιακά σύμβολα του {0,1} 8. Όλες οι λέξεις που παριστάνουν τα ενδεχόμενα δεδομένα (ή στιγμιότυπα) του προβλήματος που μας ενδιαφέρει. (Π.χ. οι παραστάσεις όλων των 2 ο βάθμιων εξισώσεων με ακέραιους συντελεστές.) Όλες οι λέξεις που παριστάνουν τα ενδεχόμενα ζητούμενα του προβλήματος που μας ενδιαφέρει. (Π.χ. οι παραστάσεις όλων των ρητών αριθμών υπό μορφή κλασμάτων.) Η γενική μορφή ενός προβλήματος, δηλαδή μια σχέση δεδομένων και ζητουμένων. Το καρτεσιανό γινόμενο D R αποτελείται από διατεταγμένα ζεύγη (d, r), όπου η λέξη d D παριστά κάποια δεδομένα του προβλήματος μας, και η λέξη r R παριστά μια αποδεκτή απάντηση για αυτά τα δεδομένα. Η σχέση αυτή δεν δίδεται, φυσικά, με πλήρη απαρίθμηση όλων αυτών των ζευγών (το πλήθος των οποίων είναι συνήθως άπειρο), αλλά μέσω μιας λογικής μαθηματικής συνθήκης η οποία με παραμέτρους τα d και r και περιγράφει το πότε κάποια απάντηση r θεωρείται ως αποδεκτή (και πότεπότε ως η μόνη αποδεκτή) απάντηση για τα δεδομένα d. Με Q[d] (την εικόνα των δεδομένων d υπό την σχέση Q) θα συμβολίζουμε όλες τις αποδεκτές απαντήσεις για τα δεδομένα d: Q[d] = { r : (d, r) Q } Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 1
ΑQ Ένας αλγόριθμος για το πρόβλημα Q. Στην θεωρία των αλγορίθμων συνηθίζεται να θεωρούμε ως αλγορίθμους τα λεγόμενα προγράμματα ή μηχανές Turig, (για τεχνικούς αλλά και ιστορικούς λόγους). Προς το παρόν, θα είναι αρκετό για τους σκοπούς μας να θεωρούμε ως «αλγορίθμους» τα προγράμματα μιας οποιασδήποτε γλώσσας υψηλού επιπέδους, οποιαδήποτε από αυτές που διδάσκονται στα μαθήματα προγραμματισμού: Java, C, C++, Delphi, ML, Lisp, κττ. Θα λέμε ότι ο αλγόριθμος ΑQ λύνει το πρόβλημα Q αν το αποτέλεσμα του αλγορίθμου με δεδομένα ένα οποιδήποτε στιγμιότυπο d του Q, ΑQ(d) ανήκει πάντοτε στις αποδεκτές απαντήσεις Q[d]: d D ( AQ(d) Q[d] ) Ας δούμε πώς θα εκφραζόταν σε αυτό το πλαίσιο ένα πεντα κλασικό πρόβλημα, ένα για το οποίο έχουμε στη διάθεσή μας μια αλγοριθμική λύση ήδη από την κλασική αρχαιότητα αυτό της εύρεσης του μέγιστου κοινού διαιρέτη δύο φυσικών αριθμών, (με τον αλγόριθμο του Ευκλείδη). Σ λ Σ* D Σ* R Σ* Q D R Αρκεί το Σ = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, _ } (δηλ. το δεκαδικό + βοηθητικά συμβολα) Μια λέξη από το Σ. Αν αποτελείται μόνον από ψηφία τότε παριστάνει έναν φυσικό. Τα ζεύγη φυσικών αριθμών, με την μορφή λ.χ. 3450_567, ή 98749_655 κττ. Οι παραστάσεις στο Σ* των φυσικών αριθμών, λ.χ. 55 ή 67 ή 1889, κττ. Τα ζεύγη ( α_β, μ ) όπου μ είναι ο μέγιστος κοινός διαιρέτης των α και β, δηλαδή ο μοναδικός αριθμός μ τέτοιος ώστε εάν ν α και ν β τότε ν μ. Ανάμεσα σε αυτά λ.χ. τα: (55_12, 1), (44_12, 4), (1024_96, 32), (17_3675, 1) κοκ. ΑQ Ένας αλγόριθμος που με δεδομένο το «ζεύγος» α_β θα υπολόγιζε τον μ.κ.δ. των α & β. Ο αρχαίος αλγόριθμος του Ευκλείδη εκφράζεται σε μερικές γραμμές, και παραμένει ένα υπόδειγμα ανθεκτικό στον χρόνο: Δεδομένα: α>0, β>0. Εφόσον (α>0) και (β>0) {Εάν α β τότε α (β α) αλλιώς εάν β<α τότε β (β α)} Αποτέλεσμα ο μη-μηδενικός εκ των α,β Η χρονική πλοκή ενός αλγορίθμου και μερικοί συμβιβασμοί. Τα παραπάνω μας προσφέρουν έναν απλό αλλά επαρκή τρόπο για να μετρήσουμε τα (εκάστοτε) δεδομένα ενός προβλήματος Q: το μέγεθος των δεδομένων ενός στιγμιότυπου d δεν είναι παρά το μήκος αυτής της λέξης, d, δηλαδή το πλήθος δηλαδή των συμβόλων από τα οποία απαρτίζεται. Έστω ότι έχουμε στη διάθεσή μας έναν αλγόριθμο ΑQ για το πρόβλημα Q. Η επόμενη οντότητα που θα θέλαμε να μετρήσουμε είναι το πόσο «δραστικά» παράγει ο αλγόριθμος ΑQ τα αντίστοιχα αποτελέσματα ΑQ(d). Οι ερευνητές του κλάδου των αλγορίθμων έχουν κατά καιρούς επινοήσει διαφόρων ειδών αλγοριθμικές γλώσσες, όλοι όμως οι τρόποι καταλήγουν ή είναι δυνατόν να καταλήξουν στον εξής κοινό παρονομαστή: ο αλγόριθμος είναι ένα κείμενο «οδηγιών προς εκτέλεση», ότι την εκτέλεση αυτή μπορεί να την αναλάβει κάποιου είδους «μηχανή», και ότι η μηχανή αυτή εκτελεί το έργο της σε διακριτά στάδια, υκ, παράγοντας έναν υπολογισμό υ0, υ1,..., υκ, υκ+1,..., υl. Κάθε υπολογισμός αρχίζει από τα δεδομένα υ0 = d, προχωρεί με διακριτά βήματα υκ υκ+1 (σύμφωνα με τον αλγόριθμο AQ), και (θα πρέπει να) καταλήγει στα επιθυμητά αποτελέσματα, υl. Το μήκος αυτού του υπολογισμού είναι η χρονική πλοκή, t(d) του αλγορίθμου μας ως προς τα συγκεκριμένα δεδομένα d. (Στο πρότυπο που έχουμε συμφωνήσει να έχουμε κατά νού, οι αλγόριθμοί μας είναι τα προγράμματα μια συνηθισμένης γλώσσας προγραμματισμού (όπως αυτά μεταφράζονται από τους γλωσσο Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 2
μεταφραστές), η μηχανή που εκτελεί το πρόγραμμα είναι ένας συνηθισμένος (πια!) μικροεπεξεργαστής, και τα διακριτά βήματα που κάνει αυτός αντιστοιχούν στους κύκλους του ρολογιού του.) Αυτή η έννοια της πλοκής του αλγορίθμου είναι ακριβής μεν, αλλά πρακτικώς άχρηστη, διότι μια τέτοια πλοκή δεν είναι δυνατόν να υπολογιστεί παρά σε ελάχιστες απλοϊκές περιπτώσεις: η τιμή της είναι εξαιρετικά ευαίσθητη στα μυρίων ειδών δεδομένα ενός προβλήματος, και στις παραμικρές λεπτομέρειες του σχετικού αλγορίθμου. Για να οδηγηθούμε σε μια έννοια επαρκώς ακριβή, αλλά και επαρκώς χρήσιμη (δηλαδή πρακτικώς εύκολα υπολογίσιμη) θα χρειαστεί να κάνουμε ορισμένους συμβιβασμούς: «Πλοκή»: d tακριβεσ(d) και συμβιβασμοί: Ν tχπ(n) Ν tφ XΠ(N) Ν t(n) Σημασία: από τα δεδομένα στο ακριβές πλήθος βημάτων από το μέγεθος των δεδομένων, Ν= d, στο κόστος για την χειρότερη περίπτωση δεδομένων dχ Π με αυτό το μέγεθος, dχ Π =N. από το μέγεθος των δεδομένων, Ν= d, σε ένα φράγμα (άνω ή κάτω, ανάλογα με το τί μας ενδιαφέρει) το κόστος για την χειρότερης περίπτωσης με μέγεθος N. από το μέγεθος των δεδομένων, Ν= d, σε μια συνάρτηση που περιγράφει ασυμπτωτικά το φράγμα tφ XΠ(N), (που περιγράφει δηλαδή την «μορφή» που αυτή έχει, βλ. παρακάτω). Ένα παράδειγμα: Για να εξηγήσουμε το τελευταίο από τα παραπάνω βήματα θα μας φανεί χρήσιμο ένα παράδειγμα για το πώς φτάνουμε έως εκεί. Σκεφθείτε ένα απόσπασμα κώδικα σαν εκείνα των συνηθισμένων γλωσσών προγραμματισμού. Σε αυτές συναντάμε απλές ή/και σύνθετες εντολές ή εκφράσεις. Οι απλές εντολές ή εκφράσεις είναι της μορφής x 3, (x+y), x T[k], (x y), όπου οι πράξεις που εμπλέκονται είναι συνήθως τιμοδοτήσεις, αλγεβρικές ή λογικές πράξεις και συγκρίσεις. Με πόσα βήματα υπολογισμού θα χρεώνατε τον υπολογισμό μιας τέτοιας έκφρασης; Άλλοτε με «1», άλλοτε με «2» ή «3», σε κάθε περίπτωση όμως δεν ξεπερνούσατε ένα άνω σταθερό όριο, έστω c πράξεων. Το σοβαρό κόστος έρχεται λοιπόν από τις σύνθετες εντολές, και κυρίως τις εντολές ελέγχου ροής. Ας δούμε λοιπόν ένα τρόπο για να κοστολογούμε ένα «πρόγραμμα» εντολή προς εντολή οι σχετικές ιδέες είναι σχεδόν αυθερμήνευτες: Εντολή S: Εκτίμηση κόστους (χειρίστης περιπτώσεως): Κ1 απλή εντολή ή έκφραση κόστος(s) = «σταθερό» κόστος σύνθετη εντολή: Κ2 S ={ S ; S } κόστος(s) κόστος(s ) + κόστος(s ) (προσέξτε ότι κάνουμε εδώ έναν συμβιβασμό: όταν οι περιστάσεις είναι οι χειρότερες για την S, δεν είναι βέβαιο ότι αυτές οι ίδιες θα είναι και οι χειρότερες για την S, και αντιστρόφως). Κ2 S = εάν E τότε S1 αλλιώς S2 κόστος(s) κόστος(e) + max{ κόστος(s ), κόστος(s ) } Κ4 S = για κ = 1 έως E { S } κόστος(s) κόστος(ε) + (c+κόστος(s )) max{ τιμή της Ε } Κ5 S = εφόσον Ε τότε { S } κόστος(s) (κόστος(ε) + κόστος(s )) max επαναλήψεις Δεν έχουμε τώρα παρά να προσπαθήσουμε να εφαρμόσουμε αυτές τις ιδέες σε ένα παράδειγμα. Ας πάρουμε το εξής κομμάτι κώδικα. Δεν έχει σημασία τί κάνει, ούτε κάν αν είναι «σωστός»! (Εξ άλλου, «σωστός» ως προς ποιό πρόβλημα;) Χρεώνουμε ως συνολκό κόστος το άθροισμα του κόστους κάθε μιάς εντολής χωριστά (κανόνας Κ2), χρεώνουμε κάθε απλή εντολή ή έκφραση με κόστος (K1), την εντολή «εάν» με c + 2c ( = 3c ), την εντολή «για» με c + (c + 3c) το μέγιστο πλήθος επαναλήψεων ( N) που θα κάνει ( = c+4cν ), και την Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 3
εντολή «εφόσον» με (c+2c+(c+4cν)) το μέγιστο πλήθος επαναλήψεων που θα κάνει που εδώ προκύπτει N. Από αυτά η πλοκή του αλγορίθμου «Επίλυση» δηλαδή το πλήθος των βημάτων που θα κάνει ο αλγόριθμος για Ν δεδομένα προκύπτει ως το πολύ: 2c + (4c+4cN)) Ν, δηλαδή : T(N) 4cN 2 +4cN+2c. Κόστος: Κώδικας: Επεξεργασία(Α[1..Ν]: πίνακας Ν αριθμών) { Τελευταίο Ν Τέλος ΨΕΥΔΕΣ βρόχος Εφόσον (όχι Τέλος) Ν { Τέλος ΑΛΗΘΕΣ βρόχος Για κ = 1 έως Τελευταίο-1 Ν { Εάν Α[κ]>Α[κ+1] τότε { Α[κ] Α[κ+1} // εναλλαγή Τέλος ΨΕΥΔΕΣ } } } } Τελευταίο Τελευταίο-1 Σε πολλούς αναγνώστες ίσως να έλθει όμως αυθόρμητα η παρατήρηση πως «ουσιαστικά» η πλοκή αυτού του αλγορίθμου είναι «Ν 2» και ότι όλες οι άλλες λεπτομέρειες είναι σε μια πρώτη προσέγγιση περιττές. Σε σχέση με αυτή την παρατήρηση που εν πολλοίς είναι ορθή, έχουμε δύο καθήκοντα: α) πώς να καταστήσουμε σαφές και ακριβές τί εννούμε με ότι αυτή είναι «ουσιαστικά Ν 2». β) πώς να υπολογίζουμε εύκολα αυτό το «Ν 2», κατ ευθείαν, δηλαδή χωρίς όλη την παραπάνω ανάλυση. Ασυμπτωτική ανάλυση: ο συμβολισμός Ο Ω Θ ο. Για να μιλήσουμε με σαφήνεια όταν δεν μπορούμε να μιλήσουμε με «ακρίβεια», θα χρειαστούμε τις εξής έννοιες και συμβολισμούς. Έστω f() g() δύο συναρτήσεις από τους φυσικούς στους φυσικούς. Εισάγουμε με τον παρακάτω πίνακα 4 συμβολισμούς: f() = O( g() ) «f όμικρον του g» ή «f το πολύ ευθέως ανάλογη της g» Υπάρχει μια σταθερά C, τέτοια ώστε για κάθε, (ή έστω για κάθε *): f() C g() f() = Ω( g() ) «f ωμέγα του g» ή «f τουλάχιστον ευθέως ανάλογη της g» Υπάρχει μια σταθερά C, τέτοια ώστε για κάθε, (ή έστω για κάθε *): f() C g() f() = Θ( g() ) «f θήτα του g» ή «f περίπου ευθέως ανάλογη της g» Υπάρχουν σταθερές C1, C2, τέτοια ώστε για κάθε, (ή έστω για κάθε *): C1 g() f() C2 g() f() = ο( g() ) «f ο πεζό του g» ή «f μηδενίζεται ως προς g» lim f( ) = 0 g ( ) ( ) Αυτός ο συμβολισμός μας επιτρέπει να γράψουμε με σαφήνεια ότι η «μορφή» της πλοκής που βρήκαμε προηγουμένως, είναι Θ(Ν 2 ): Τ(Ν) = 3cN 2 +3cN+2c = Θ(Ν 2 ), διότι ισχύουν ωρισμένοι κανόνες απλοποίησης: Θετικές ποσότητες c, φραγμένες ως προς... c = Θ(1) Πολλαπλασιαστικές σταθερές αμελούνται O( c τ() ) = O( τ() ) Ω( c τ() ) = Ω( τ() ) «Τάξη του γινομένου = γινόμενο των τάξεων» f() = O(α()), g() = O(β()) fg() = Ο(αβ()) f() = Ω(α()), g() = Ω(β()) fg() = Ω(αβ()) Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 4
Οι μηδενιζόμενες ποσότητες αμελούνται f() = o(g()) Θ(g()+f()) = Θ(g()) Λ.χ. 550 = Θ(1), 100f() = Θ(f()), 3 3 +4 3 = 7 3 = Θ( 3 ), 3 +5 2 = Θ( 3 ), +100 = Θ(). Το σημαντικό είναι ότι αυτοί οι κανόνες απλοποίησης επιτρέπουν να φτάσουμε κατ ευθείαν σε μια έκφραση τύπου Ο Ω Θ, χωρίς να προχωρήσουμε σε απολύτως ακριβείς αναλύσεις, και αυτό είναι που χρειαζόμαστε για να μπορούμε να υπολογίζουμε τις πλοκές των αλγορίθμων. Δίνουμε αμέσως μερικά παραδείγματα: Πόσο κόστος έχει η έκφραση: Τ[k] (k Τ[k+1]); Πόσο συνδυασμούς ν στοιχείων ανά κ, έχουμε για κ = 2, 3, 4, κοκ; Πόσο περίπου είναι το άθροισμα: k ; Πόσο περίπου είναι το άθροισμα: log k ; Ποιά είναι η πλοκή του κώδικα που εξετάσαμε λίγο προηγουμένως: Κάθε τέτοια «αλγεβρική» έκφραση έχει φραγμένo μέγεθος, και αποτελείται από πράξεις με κόστος, όπου c μια σταθερά, άρα το κόστος είναι Θ(1). Οι συνδυασμοί ν ανά κ είναι ν!/(ν κ)!κ! = ν(ν 1)(ν 2)...(ν κ+1)/κ! δηλαδή Θ(ν κ ), για κ σταθερό. Λ.χ. Cν,4 = Θ(ν 4 /4!) = Θ(ν 4 ). Για να βρούμε μια Ο( ) έκφραση σκεπτόμαστε ότι «όλα είναι μικρότερα του μεγίστου», και εδώ «όλα» είναι, και το «μέγιστο» είναι επίσης, άρα Ο( 2 ). Για να βρούμε μια Ω( ) έκφραση σκεπτόμαστε ότι «τα μισά είναι τουλάχιστον το μισό», εδώ δηλαδή οι μισοί όροι από /2 και μετά είναι τουλάχιστον /2, άρα συνολικά έχουμε Ω((/2) 2 ) = Ω( 2 /4) = Ω( 2 ). 2 Αποτέλεσμα: k = Θ( ). Για να βρούμε μια Ο( ) έκφραση σκεπτόμαστε και εδώ ότι «όλα είναι μικρότερα του μεγίστου», και εδώ «όλα» είναι το, και «μέγιστο» είναι το «log», άρα Ο(log). Για να βρούμε μια Ω( ) έκφραση σκεπτόμαστε ότι «τα μισά είναι τουλάχιστον το μισό», εδώ δηλαδή οι μισοί όροι από /2 και μετά είναι μεγαλύτεροι από log(/2), άρα συνολικά έχουμε: Ω( log( / 2)) = Ω( (log 1)) = Ω( log ) = Ω( log ) Αποτέλεσμα: log k = Θ( log ). Η πλοκή Ο(Ν 2 ) έρχεται σχεδόν αμέσως στο νού μας, διότι στον κώδικα αυτό δεν έχουμε παρά απλές εντολές (πλήθους προφανώς Θ(1) αφού κάθε πρόγραμμα έχει φραγμένο μέγεθος...) εκάστη με κόστος Θ(1), και δύο βρόχους που θα επαναληφθούν το πολύ Ν φορές Ν Ν κάνει Ν 2 και... τέλος η ανάλυση: Τ(Ν) = Ο(Ν 2 ). Επιστροφή στην αφετηρία: από την πλοκή στην αξιολόγηση. Να μην ξεχάσουμε φυσικά γιατί τα κάναμε όλα αυτά: γράφοντας έναν αλγόριθμο σαν ένα πρόγραμμα υπολογίζουμε (με βάση τους απλοποιητικούς κανόνες μας) πολύ πιο εύκολα την χρονική του πλοκή κατά την έννοια της ασυμπτωτικής μορφής που έχει ένα φράγμα τους κόστους χειρίστης περιπτώσεως. Με βάση αυτή την πλοκή έχουμε την ελπίδα να αξιολογήσουμε κατά σαφή τρόπο δύο αλγορίθμους: το «απόλυτο» κριτήριο ταξινόμησης είναι: «προτιμάμε τον αλγόριθμο Α έναντι του Β εάν η χρονική του πλοκή χ.π. του Α μηδενίζεται ως προς την πλοκή χ.π. του Β». Δίνουμε 4 σχετικά παραδείγματα: Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 5
Πλοκή χ.π. αλγορίθμου «1» Πλοκή χ.π. αλγορίθμου «2» Προτιμότερος?? Ο(N 2 ) Ο(Ν 3 ) Δυστυχώς δεν μπορούμε να διαλέξουμε. Χρειαζόμαστε μια πιο ακριβή ανάλυση της πλοκής των δύο αλγορίθμων: εάν η πρώτη ανάλυση είναι αρκετά ακριβής ενώ η 2 η πολλή «χαλαρή» τότε ίσως ο 2 ος να είναι καλύτερος από τον 1 ο... Ο(N 2 ) Θ(Ν 2 ) (Ελαφρά) ο 1 ος διότι στον 2 ο οι χειρότερες περιπτώσεις είναι οπωσδήποτε Ω(Ν 2 ), ενώ στο 1 ο δεν αποκλείεται να είναι καλύτερες. Ο(N 2 ) Ω(Ν 2 ) Αν δεν διαθέτουμε περισσότερο λεπτομερή στοιχεία, προτιμότερος είναι μάλλον ο 1 ος διότι ο 2 ος έχει ως κάτω φράγμα αυτό που ο άλλος έχει ως άνω φράγμα. Ο(N 2 ) Ω(Ν 2 logn) Οπωσδήποτε ο 1 ος ο 2 ος κάνει πάντοτε περισσότερες πράξεις (ασυμπτωτικά): Ν 2 = ο(ν 2 logn)?!!!!!! Στον παρακάτω πίνακα περιέχεται μια σειρά από «πλοκές» που εμφανίζονται κατά την ανάλυση της πλοκής των αλγορίθμων. Δίνουμε την μορφή τους, την ονομασία τους και την τις έχουμε διατάξη κατ «αύξουσα» σειρά κάθε μία «μηδενίζεται» (κατά την έννοια του ο( ) ) ως προς την επόμενή της. Πλοκή: Ονομασία: 1 σταθερή, σταθερού χρόνου logn λογαριθμική a N, N ( a< 1) υπογραμμική Ν, Ν 2, Ν 3 πολυωνυμική, (γραμμική, τετραγωνική, κυβική, κοκ) Ν α, (α 1) πολυωνυμική Ν Θ(logN), κττ α Ν, Ν Ν, Ν! υπερπολυωνυμική εκθετική, υπερεκθετική 2 2 N διπλά εκθετική Ανακεφαλαίωση και τα επόμενα βήματα: Είδαμε λοιπόν ότι έχουμε έναν τρόπο να εκτιμούμε την «δραστικότητα» ενός αλγορίθμου, υπό την μορφή της χρονικής (ή και χωρικής του) πλοκής. Η πλοκή αυτή είναι δυνατόν να υπολογιστεί πολλές φορές με αρκετή ευκολία (αν και όχι πάντοτε...), και μέσω αυτής είναι δυνατόν να ιεραρχούμε τους αλγορίθμους αναλόγως της δραστικότητας που παρουσιάζουν. Όσο ακριβέστερη είναι η ανάλυση της πολυπλοκότητάς τους, τόσο σαφέστερη είναι και η γνώση μας για την ιεράρχησή τους. Τέλος είδαμε ότι έχουμε σοβαρούς λόγους να προτιμάμε τις «πολυωνυμικές» πλοκές, παρά τις «εκθετικές» πλοκές (που είναι και αυτές που συνήθως παράγονται από μια εξαντλητική αναζήτηση). Μπορούμε πια να θέσουμε αν μη τι άλλο τον στόχο της περιοχής που ονομάζουμε «σχεδίαση και ανάλυση αλγορίθμων»: την σχεδίαση αλγοριθμικών λύσεων των διαφόρων προβγημάτων, λύσεων που θα πρέπει να έχουν την χαμηλότερη εφικτή πλοκή, και αν είναι δυνατόν πολυωνυμική πλοκή. Από το αμέσως επόμενο κεφάλαιο (και για πολλά επόμενα) θα αφιερωθούμε στην παρουσίαση μιας σειράς τεχνικών επινοημένων με αυτό τον σκοπό. Πανεπιστήμιο Κρήτης Τμήμα Επιστήμης Υπολογιστών Γ.Φ. Γεωργακόπουλος ver: 20/3/2012 6