Ταχεία Ταξινόμηση Quc-Sort 7 4 9 6 2 2 4 6 7 9 4 2 2 4 7 9 7 9 2 2 9 9 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 1
Outlne Quc-sort Αλγόριθμος Βήμα διαχωρισμού Δένδρο Quc-sort Παράδειγμα εκτέλεσης Ανάλυση του quc-sort In-place quc-sort Περίληψη αλγορίθμων ταξινόμησης Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 2
QucSort Βασίζεται στην τεχνική του διαίρει και βασίλευε (dvde & conquer) Στην τεχνική αυτή για να λύσω ένα πρόβλημα το σπάω σε υποπροβλήματα. Λύνω κάθε υποπρόβλημα ξεχωριστά και συνθέτω τις επιμέρους λύσεις για να παράγω την τελική λύση του προβλήματος. ΕΦΑΡΜΟΓΗ - Ας υποθέσω ότι έχω στη διάθεσή μου μια συνάρτηση Partton() που κάνει τα ακόλουθα: δοθέντος ενός στοιχείου του πίνακα Α τοποθετεί το στοιχείο στη σωστή θέση στον πίνακα έτσι ώστε όλα τα στοιχεία που βρίσκονται αριστερά του να είναι μικρότερα και όλα που είναι δεξιά του μεγαλύτερα. - Το στοιχείο το οποίο μπαίνει στη «σωστή» θέση το ονομάζουμε στοιχείο διαχώρισης (pvot element) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 3
QucSort Πρόκειται για απλή και γρήγορη μέθοδο ταξινόμησης Εάν θεωρήσουμε τον πίνακα Α: 25 12 7 15 33 60 45 64 80 τον οποίο θέλουμε να ταξινομήσουμε. Σε αυτόν τον πίνακα ο αριθμός 33 έχει μια σημαντική ιδιότητα. Όλοι οι αριθμοί στα αριστερά είναι μικρότεροι και όλοι οι αριθμοί στα δεξιά είναι μεγαλύτεροι Αυτό σημαίνει ότι ο αριθμός 33 βρίσκεται στη σωστή στου θέση!! Έτσι προκειμένου να ταξινομήσουμε τον πίνακα αρκεί να επικεντρώσουμε την προσοχή μας στα δύο υποσύνολα το δεξί και το αριστερό. Το πρόβλημα χωρίστηκε σε δύο υποπροβλήματα (Διαίρει και Βασίλευε) Πώς δημιουργούμε στοιχεία σαν το 33? Τα κατασκευάζουμε! Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 4
QucSort Έστω λοιπόν συνάρτηση: nt Partton(nt A[], left, rght, pvotindex) που παίρνει σαν ορίσματα έναν πίνακα Α, το αριστερό και δεξί όριο του πίνακα και τη θέση του στοιχείου διαχώρισης και επιστρέφει την καινούργια θέση του στοιχείου διαχώρισης. Η συνάρτηση Partton πραγματοποιεί τη αναδιάταξη και διαίρεση του πίνακα A[p,r]. ΕΡΩΤΗΣΗ: Πως μπορώ να χρησιμοποιήσω τη συνάρτηση για να λύσω το πρόβλημα της ταξινόμησης? Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 5
Ταχεία Ταξινόμηση QucSort vod Qucsort(nt A[], nt left, nt rght) { f (left>=rght) return; nt p = Partton (A, left, rght-1, pvot); Qucsort(A, left, p-1); Qucsort(A, p+1, rght); Όπου η διαδικασία partton (A,, j-1,pvot), χωρίζει τον πίνακα Α[ j-1] έτσι ώστε Α[..-1] να περιέχει στοιχεία < pvot, A[ j-1] να περιέχει στοιχεία >pvot, και επιστρέφει την τιµή. Ο αλγόριθμος είναι σωστός αφού η Partton εξασφαλίζει ότι το στοιχείο που θα βρεθεί στη θέση p είναι και αυτό που θα ήταν αν ο πίνακας ήταν ταξινομημένος, ενώ όλα που είναι αριστερά του θα είναι μικρότερα (αλλά αταξινόμητα) και όσα είναι δεξιά μεγαλύτερα (και αταξινόμητα). H Partton οργανώνει τη διαίρεση του πίνακα A[p,r] γύρω από το στοιχείο x=a[p]. Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 6
Quc-Sort Ο Quc-sort είναι ένας randomzed αλγόριθμος ταξινόμησης βασισμένος στο πρότυπο «διαίρει και βασίλευε»: Dvde: διάλεξε ένα τυχαίο στοιχείο x (που καλείται pvot) και χώρισε το S σε L στοιχεία μικρότερα του x E στοιχεία ίσα με x G στοιχεία μεγαλύτερα του x Recur: ταξινόμησε τα L και G Conquer: ένωσε τα L, E και G L x E x G x Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 7
QucSort ΠΑΡΑΔΕΙΓΜΑ Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 8
QucSort ΜΕΘΟΔΟΛΟΓΙΑ (Partton) - Ξεκίνα ένα αριστερό counter (lc) και ένα δεξί counter (rc) - Αρχικά lc = left + 1 //μια θέση μετά το pvot και rc = rght - O lc θα ανεβαίνει όσο A[lc]<=A[pvotIndex] και ο rc θα κατεβαίνει όσο Α[rc]>A[pvotIndex] - Όταν σταματήσουν και οι δύο αντιμεταθέτω τα Α[rc] και Α[lc] και συνεχίζω - Τελειώνουμε όταν ο rc ξεπεράσει το lc - Η θέση που σταμάτησε ο rc είναι και η θέση που πρέπει να μπει το pvot Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 9
QucSort ΠΑΡΑΔΕΙΓΜΑ (Partton) 42 3 51 624 62 7 15 pvot lc rc Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 10
QucSort Partton (nt A[], nt left, nt rght, nt pvotindex){ swap (A[left], A[pvotIndex]);//στη γενική περίπτωση //pvotindex!=left nt lc = left + 1; nt rc = rght; whle (lc<rc){ whle (A[lc]<=A[left] && lc<rght) lc++; whle (A[rc]>A[left]) rc--; f (lc<rc) swap (A[lc], A[rc]); swap (A[left], A[rc]); return rc; Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 11
Διαχωρισμός Διαχωρίζουμε μια ακολουθία εισόδου ως εξής: Αφαιρούμε, κατά σειρά, κάθε στοιχείο y από το S και Εισάγουμε το y στο L, E ή G, ανάλογα με το αποτέλεσμα της σύγκρισης με το pvot x Κάθε εισαγωγή και αφαίρεση γίνεται στην αρχή ή στο τέλος μιας ακολουθίας, και έτσι χρειάζεται χρόνο O(1) Έτσι, το βήμα διαχωρισμού του qucsort χρειάζεται χρόνο O(n) αλγόριθμος partton(s, p) Είσοδος ακολουθία S, θέση p του pvot Έξοδος υποακολουθίες L, E, G των στοιχείων του S που είναι μικρότερα, ίσα, ή μεγαλύτερα από το pvot. L, E, G κενές ακολουθίες x S.remove(p) whle S.sEmpty() y S.remove(S.frst()) f y < x L.nsertLast(y) else f y = x E.nsertLast(y) else { y > x G.nsertLast(y) return L, E, G Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 12
QucSort (Ανάλυση) ΧΕΙΡΟΤΕΡΗ ΠΕΡΙΠΤΩΣΗ - Όταν σαν pvot επιλέγουμε πάντα το Α[left] τότε η χειρότερη περίπτωση για τον αλγόριθμο είναι να είναι ο πίνακας ήδη ταξινομημένος. - Στην πρώτη κλήση η Partton συγκρίνει/μεταθέτει Ν στοιχεία και διασπά τον πίνακα σε έναν κενό αριστερό πίνακα και ένα δεξί πίνακα μεγέθους Ν-1. - Όμοια στη δεύτερη κλήση θα απομείνει στα δεξιά πίνακας Ν-2 μεγέθους ενώ θα έχουν εκτελεστεί Ν-1 συγκρίσεις. Άρα κόστος = Ν + Ν-1 +...+2 = Ο(Ν 2 ) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 13
QucSort (Ανάλυση) ΜΕΣΗ ΠΕΡΙΠΤΩΣΗ - Στη μέση περίπτωση το pvot μπορεί να βρεθεί σε οποιαδήποτε θέση του πίνακα με την ίδια πιθανότητα. - Υπάρχουν Ν δυνατές θέσεις κάθε μια με πιθανότητα 1/Ν Έστω, το μέγεθος του αριστερού κομματιού μετά το χωρισμό των στοιχείων. Αφού ο pvot είναι στη μέση το αριστερό κομμάτι θα είναι N--1. O μέσος χρόνος για ταξινόμηση του αριστερού και δεξιού θα είναι αντίστοιχα T() και Τ(N--1). Ο χρόνος που απαιτείται για το χωρισμό των στοιχείων θα είναι μικρότερος του cn, όπου c σταθερά. Άρα: T ( N) c N 1 N N 1 0 [ T ( ) T ( N 1)] => T ( N) c N 2 N N 1 0 T ( ) Για να επιλύσουμε την παραπάνω αναδρομική πρέπει να διώξω το άθροισμα Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 14
QucSort (Ανάλυση) Πολλαπλασιάζω τις σχέσεις για Ν και Ν-1 με Ν και Ν-1 αντίστοιχα και κατόπιν τις αφαιρώ ( N NT NT ( N 1) T ( N ) c 1) N 2 2 c ( N N 1 0 1) T ( ) 2 2 με αφαίρεση => ( N ) ( N 1) T ( N 1) 2cN 2c 2T ( N 1) Για να συνεχίσω θα πρέπει να διώξω το Τ(Ν-1). Για να γίνει αυτό διαιρώ με Ν(Ν-1) και αθροίζω N 2 0 T ( ) NT ( N ) ( N 1) T ( N 1) 2cN 2T ( N 1) NT ( N ) 2cN ( N 1) T ( N 1) => => Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 15
T ( N ) 2c T ( N 1) N 1 N 1 N QucSort (Ανάλυση) T( N 1) N 2c N T( N 2) N 1... T( 2) 2c T 2 1 2 1 (1) 2 με πρόσθεση => T N N 1 ( N) 2c 1 j 3 1 j T (1) 2 Για Ν=1 δε γίνεται κλήση επομένως Τ(1) =0. Άρα η παραπάνω σχέση γίνεται: N 1 T ( N) 2c( N 1) j 3 1 j Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 16
QucSort (Ανάλυση) Ισχύει όμως: N 1 j 3 1 N 1 j 2 dx x 1 ln( N 1) Άρα έχω: T ( N) 2c( N 1)(1 ln( N 1)) c ' N log N O( N log N) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 17
QucSort (Ανάλυση) Η πολυπλοκότητα στη μέση περίπτωση λοιπόν είναι Ο(ΝlogN). Ίδια πολυπλοκότητα με τον HeapSort αν και στην πράξη ο QucSort είναι γρηγορότερος. Τι μπορούμε να κάνουμε για να αποφύγουμε το Ο(Ν 2 ) της χειρότερης περίπτωσης? ΑΠΑΝΤΗΣΗ Εφόσον το πρόβλημα προκύπτει όταν ο πίνακας είναι ταξινομημένος αντί να διαλέγουμε το πρώτο στοιχείο σαν pvot διάλεξε ένα τυχαίο (Randomzed QucSort). Μπορεί να δειχτεί ότι η εκδοχή αυτή στη μέση περίπτωση έχει πολυπλοκότητα Ο(ΝlogN) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 18
Θεωρητικό Όριο Ερώτηση: Μπορούμε να κατασκευάσουμε αλγόριθμο ταξινόμησης (βασιζόμενο σε συγκρίσεις δύο στοιχείων) που να έχει πολυπλοκότητα μικρότερη του Ο(ΝlogN)? Απάντηση: OXI (με την προϋπόθεση ότι ο αλγόριθμος θα πρέπει να λειτουργεί για οποιοδήποτε τύπο στοιχείων αρκεί φυσικά να ορίζεται ο τελεστής σύγκρισης). Παρατήρηση: Αν τα στοιχεία προς ταξινόμηση είναι ακέραιοι μπορώ να πετύχω χρόνο Ο(Ν) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 19
Θεωρητικό Όριο Απόδειξη: - Περιγράφουμε τον αλγόριθμο σαν ένα δέντρο απόφασης - Έστω αρχικά ο αλγόριθμος συγκρίνει τα στοιχεία Α[] και A[j]. Το αριστερό υπόδεντρο της ρίζας θα αντιστοιχεί στην περίπτωση Α[]<A[j] και δεξί στην περίπτωση Α[]>A[j] - Ένας κόμβος του δέντρου περιέχει τις περιπτώσεις της τελικής λύσης που ικανοποιούν τις συγκρίσεις που έγιναν στο μονοπάτι από τη ρίζα προς τον κόμβο αυτόν. - Τα φύλλα περιέχουν μία λύση. Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 20
Θεωρητικό Όριο Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 21
Θεωρητικό Όριο - Έστω αλγόριθμος ταξινόμησης Ι και Τ το δέντρο απόφασής του. - Το πλήθος των φύλλων είναι Ν! (όσες και οι δυνατές διατάξεις Ν στοιχείων) - Το ύψος του δυαδικού δέντρου αντιστοιχεί σε κάτω φράγμα για την απόδοση του αλγορίθμου - Ένα δυαδικό δέντρο έχει το πολύ 2 h φύλλα όπου h το ύψος του - Άρα για οποιονδήποτε αλγόριθμο θα πρέπει: 2 h N! => h log(n!) => h log(n/e) N => h NlogN-Nloge - Άρα οποιοσδήποτε αλγόριθμος είναι Ω(NlogN) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 22
Δένδρο Quc-Sort Μια εκτέλεση του quc-sort απεικονίζεται από ένα δυαδικό δένδρο Κάθε κόμβος αναπαριστά μια αναδρομική κλήση του quc-sort και αποθηκεύει Μη ταξινομημένη ακολουθία πριν την εκτέλεση και τον pvot αυτής Ταξινομημένη ακολουθία στο τέλος της εκτέλεσης Η ρίζα είναι η αρχική κλήση Τα φύλλα είναι κλήσεις σε υποακολουθίες μεγέθους 0 ή 1 7 4 9 6 2 2 4 6 7 9 4 2 2 4 7 9 7 9 2 2 9 9 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 23
Παράδειγμα εκτέλεσης Επιλογή Pvot 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 7 2 9 4 2 4 7 9 3 8 6 1 1 3 8 6 2 2 9 4 4 9 3 3 8 8 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 24
Παράδειγμα εκτέλεσης (συνέχεια) Διαχωρισμός, αναδρομική κλήση, επιλογή pvot 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 2 4 3 1 2 4 7 9 3 8 6 1 1 3 8 6 2 2 9 4 4 9 3 3 8 8 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 25
Παράδειγμα εκτέλεσης (συνέχεια) Διαχωρισμός, αναδρομική κλήση, βασική περίπτωση 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 2 4 3 1 2 4 7 3 8 6 1 1 3 8 6 1 1 9 4 4 9 3 3 8 8 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 26
Παράδειγμα εκτέλεσης (συνέχεια) Αναδρομική κλήση,, βασική περίπτωση, συνένωση 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 2 4 3 1 1 2 3 4 3 8 6 1 1 3 8 6 1 1 4 3 3 4 3 3 8 8 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 27
Παράδειγμα εκτέλεσης (συνέχεια) Αναδρομική κλήση, επιλογή pvot 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 2 4 3 1 1 2 3 4 7 9 7 1 1 3 8 6 1 1 4 3 3 4 8 8 9 9 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 28
Παράδειγμα εκτέλεσης (συνέχεια) Διαχωρισμός,, αναδρομική κλήση, βασική περίπτωση 7 2 9 4 3 7 6 1 1 2 3 4 6 7 8 9 2 4 3 1 1 2 3 4 7 9 7 1 1 3 8 6 1 1 4 3 3 4 8 8 9 9 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 29
Παράδειγμα εκτέλεσης (συνέχεια) Συνένωση, συνένωση 7 2 9 4 3 7 6 1 1 2 3 4 6 7 7 9 2 4 3 1 1 2 3 4 7 9 7 17 7 9 1 1 4 3 3 4 8 8 9 9 9 9 4 4 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 30
Χρόνος Εκτέλεσης Χειρότερης Περίπτωσης Η χειρότερη περίπτωση για τον quc-sort συμβαίνει όταν το pvot είναι το μοναδικό ελάχιστο ή μέγιστο στοιχείο Ένα από τα L και G έχει μέγεθος n 1 και το άλλο 0 Ο χρόνος εκτέλεσης είναι ανάλογος με το άθροισμα n (n 1) 2 Έτσι, ο χρόνος εκτέλεσης χειρότερης περίπτωσης είναι O(n 2 ) βάθος χρόνος 0 n 1 n 1 n 1 1 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 31
Αναμενόμενος Χρόνος Εκτέλεσης Σκεφτείτε μια αναδρομική κλήση του quc-sort σε μια ακολουθία μεγέθους s Καλή κλήση: τα μεγέθη των L και G είναι το καθένα λιγότερο από 3s 4 Κακή κλήση: ένα από τα L και G έχει μέγεθος μεγαλύτερο από 3s 4 7 2 9 4 3 7 6 1 9 7 2 9 4 3 7 6 1 2 4 3 1 7 9 7 1 1 1 7 2 9 4 3 7 6 Good call Bad call Μια κλήση είναι καλή με πιθανότητα 1 2 1/2 των πιθανών pvots προκαλούν καλές κλήσεις: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Δομές Δεδομένων και Αλγόριθμοι Κακοί pvots Καλοί pvots Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής Κακοί pvots 32
Αναμενόμενος Χρόνος Εκτέλεσης, Μέρος 2 Πιθανοτικό γεγονός: ο αναμενόμενος αριθμός ρίψεων νομίσματος που απαιτείται για να έρθουν κορώνες είναι 2 Για έναν κόμβο βάθους, περιμένουμε ότι Οι 2 πρόγονοι είναι καλές κλήσεις Το μέγεθος της ακολουθίας εισόδου για την παρούσα κλήση είναι το πολύ (3 4) 2 n Άρα έχουμε Για έναν κόμβο βάθους 2log 4 3 n, το αναμενόμενο μέγεθος εισόδου είναι ένα Το αναμενόμενο ύψος του δένδρου quc-sort tree είναι O(log n) Το ποσό της εργασίας που γίνεται στους κόμβους ίδιου βάθους είναι O(n) Έτσι ο αναμενόμενος χρόνος εκτέλεσης είναι O(n log n) expected heght O(log n) s(a) s(r) s(b) s(c) s(d) s(e) s(f) tme per level O(n) O(n) O(n) total expected tme: O(n log n) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 33
In-Place Quc-Sort Ο Quc-sort μπορεί να υλοποιηθεί για να τρέχει n-place Στο βήμα διαχωρισμού, χρησιμοποιούμε πράξεις αντικατάστασης για να αναδιατάξουμε τα στοιχεία της ακολουθίας εισόδου έτσι ώστε Τα στοιχεία μικρότερα του pvot έχουν βαθμό μικρότερο του h Τα στοιχεία που είναι ίσα με το pvot έχουν βαθμό ανάμεσα σε h και Τα στοιχεία μεγαλύτερα του pvot έχουν βαθμό μεγαλύτερο από Οι αναδρομικές κλήσεις λαμβάνουν υπόψη Στοιχεία με βαθμό μικρότερο από h Στοιχεία με βαθμό μεγαλύτερο από Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής Αλγόριθμος nplacequcsort(s, l, r) Είσοδος ακολουθία S, βαθμοί l και r Έξοδος ακολουθία S με στοιχεία βαθμού ανάμεσα σε l και r αναδιατεταγμένα σε αύξουσα σειρά f l r return a r και om nteger between l και r x S.elemAtRan() (h, ) nplacepartton(x) nplacequcsort(s, l, h 1) nplacequcsort(s, 1, r) 34
In-Place Διαχωρισμός Εκτέλεσε το διαχωρισμό με 2 δείκτες για να χωρίσεις το S σε L και E G (μια παρόμοια μέθοδος μπορεί να χωρίσει το E G σε E και G). j 3 2 5 1 0 7 3 5 9 2 7 9 8 9 7 6 9 (pvot = 6) Επανάλαβε μέχρι τα j και να διασταυρωθούν: Διάτρεξε το j δεξιά μέχρι να βρεις στοιχείο > x. Διάτρεξε το αριστερά μέχρι να βρεις στοιχείο < x. Άλλαξε τις θέσεις των στοιχείων που δείχνουν οι j και j 3 2 5 1 0 7 3 5 9 2 7 9 8 9 7 6 9 Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 35
Παράδειγμα A. Κατασκευάστε το δυαδικό δέντρο (bnary tree) που αντιστοιχεί στην εκτέλεση του αλγόριθμου ταξινόμησης qucsort (ταξινόμηση με διαμερισμό και ανταλλαγή) στον πίνακα Α=[10, 4, 15, 7, 23, 6, 15,14, 16, 20]. Κάθε κόμβος του δέντρου θα περιέχει τον υποπίνακα που κάθε φορά καλείται με τις αναδρομικές κλήσεις της συνάρτησης. Β. Πώς επηρεάζει η επιλογή του άξονα (pvot) την απόδοση του αλγόριθμου qucsort; Μπορούμε να χρησιμοποιούμε ως άξονα το τελευταίο στοιχείο του πίνακα; Δικαιολογείστε την απάντησή σας. Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 36
A. Κατασκευάστε το δυαδικό δέντρο (bnary tree) που αντιστοιχεί στην εκτέλεση του αλγόριθμου ταξινόμησης qucsort (ταξινόμηση με διαμερισμό και ανταλλαγή) στον πίνακα Α=[10, 4, 15, 7, 23, 6, 15,14, 16, 20]. Κάθε κόμβος του δέντρου θα περιέχει τον υποπίνακα που κάθε φορά καλείται με τις αναδρομικές κλήσεις της συνάρτησης. Μέχρι να πάρουμε τα δύο πρώτα παιδιά, (6,4,7) και (15,23,10,15,14,16,20), γίνονται οι παρακάτω ανταλλαγές (swaps): 10 με 6, 15 (το αριστερότερο) με 7. Μέχρι να πάρουμε τα δύο παιδιά (14,15,10) και (23,15,16,20) γίνονται οι παρακάτω ανταλλαγές (swaps): 15 (το αριστερότερο) με 14, 23 με 15 (το αριστερότερο). Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 37
Παράδειγμα Β. Πώς επηρεάζει η επιλογή του άξονα (pvot) την απόδοση του αλγόριθμου qucsort; Μπορούμε να χρησιμοποιούμε ως άξονα το τελευταίο στοιχείο του πίνακα; Δικαιολογείστε την απάντησή σας. Aν κάθε φορά επιλέγεται ως άξονας το μεσαίο στοιχείο και οι τιμές των κλειδιών ακολουθούν τυχαία κατανομή τότε η ταξινόμηση είναι αποτελεσματική γιατί ο πίνακας χωρίζεται σε δύο περίπου ισομήκεις υποπίνακες Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 38
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Pvot το 1 ο στοιχείο του πίνακα = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 8 8 12 14 15 13 10 11 9 Άρα, μετά το partton στον πίνακα ταξινομήσαμε τα στοιχεία έτσι ώστε στα αριστερά του pvot (8) να είναι όλα όσα είναι μικρότερα από αυτό (κανένα) και στα δεξιά όλα όσα είναι μεγαλύτερα. Με βάση τον αλγόριθμο του qucsort θα πρέπει να κάνουμε qucsort για κάθε υποπίνακα ο οποίος στο παράδειγμά μας είναι ο null για τα στοιχεία «μικρότερα του 8» και ο [12 14 15 13 10 11 9] για τα στοιχεία «μεγαλύτερα του 8»
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 12 14 15 13 10 11 9 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Pvot το 1 ο στοιχείο του πίνακα = 12 8 12 14 15 13 10 11 9 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 14 15 13 10 11 9 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 14 15 13 10 11 9 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 14 15 13 10 11 9 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 15 13 10 11 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 15 13 10 11 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 15 13 10 11 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 13 10 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 13 10 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 13 10 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 13 10 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 10 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 10 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 10 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 12 9 11 10 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 12 8 10 9 11 12 13 15 14 gude Άρα, μετά το partton στον πίνακα ταξινομήσαμε τα στοιχεία έτσι ώστε στα αριστερά του pvot (12) να είναι όλα όσα είναι μικρότερα από αυτό και στα δεξιά όλα όσα είναι μεγαλύτερα. Με βάση τον αλγόριθμο του qucsort θα πρέπει να κάνουμε qucsort για κάθε υποπίνακα ο οποίος στο παράδειγμά μας είναι ο [10 9 11] για τα στοιχεία «μικρότερα του 12» και ο [13 15 14] για τα στοιχεία «μεγαλύτερα του 12»
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Pvot το 1 ο στοιχείο του πίνακα = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 10 9 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot = 10 8 9 10 11 12 13 15 14 gude Άρα, μετά το partton στον πίνακα ταξινομήσαμε τα στοιχεία έτσι ώστε στα αριστερά του pvot (10) να είναι όλα όσα είναι μικρότερα από αυτό και στα δεξιά όλα όσα είναι μεγαλύτερα. Με βάση τον αλγόριθμο του qucsort θα πρέπει να κάνουμε qucsort για κάθε υποπίνακα ο οποίος στο παράδειγμά μας είναι ο [9] για τα στοιχεία «μικρότερα του 10» και ο [11] για τα στοιχεία «μεγαλύτερα του 10»
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Η συνθήκη f δεν ισχύει άρα τελειώσαμε με το αριστερό τμήμα 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Η συνθήκη f δεν ισχύει άρα τελειώσαμε με το δεξί τμήμα 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 15 14 gude Άρα, συνεχίζουμε με το δεξί τμήμα του gude=12 που είναι ο πίνακας [13 15 14]
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Pvot το 1 ο στοιχείο του πίνακα = 13 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot=13 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot=13 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot=13 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot=13 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; pvot=13 8 9 10 11 12 13 15 14 gude Άρα, μετά το partton στον πίνακα ταξινομήσαμε τα στοιχεία έτσι ώστε στα αριστερά του pvot (13) να είναι όλα όσα είναι μικρότερα από αυτό και στα δεξιά όλα όσα είναι μεγαλύτερα. Με βάση τον αλγόριθμο του qucsort θα πρέπει να κάνουμε qucsort για κάθε υποπίνακα ο οποίος στο παράδειγμά μας είναι ο null για τα στοιχεία «μικρότερα του 13» και ο [15 14] για τα στοιχεία «μεγαλύτερα του 13»
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Η συνθήκη f δεν ισχύει άρα τελειώσαμε με το αριστερό τμήμα 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 15 14 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; 8 9 10 11 12 13 14 15 gude Άρα, μετά το partton στον πίνακα ταξινομήσαμε τα στοιχεία έτσι ώστε στα αριστερά του pvot (15) να είναι όλα όσα είναι μικρότερα από αυτό και στα δεξιά όλα όσα είναι μεγαλύτερα. Με βάση τον αλγόριθμο του qucsort θα πρέπει να κάνουμε qucsort για κάθε υποπίνακα ο οποίος στο παράδειγμά μας είναι ο [14] για τα στοιχεία «μικρότερα του 15» και ο null για τα στοιχεία «μεγαλύτερα του 15»
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Η συνθήκη f δεν ισχύει άρα τελειώσαμε με το αριστερό τμήμα 8 9 10 11 12 13 14 15 gude
qucsort(a,, ) { f( < ) { gude = partton(a,, ) qucsort(a,, gude-1); qucsort(a, gude+1, ); partton (A,, ) { pvot= πρώτο στοιχείο, ή μεσαίο στοιχείο, ή τυχαίο στοιχείο του πίνακα; swap(a[], pvot); = ; = +1; ++ untl (A[] >= pvot or ==); -- untl (A[] <= pvot or ==); f (<) swap(a[], A[]); untl >=; swap(a[], A[]); return ; Ο πίνακας ταξινομημένος είναι : 8 9 10 11 12 13 14 15
Περίληψη Αλγορίθμων Ταξινόμησης Αλγόριθμος Μέσος Χρόνος Χειρότερος Χρόνος Παρατηρήσεις Bubble sort O(n 2 ) O(n 2 ) selecton-sort O(n 2 ) O(n 2 ) nserton-sort O(n 2 ) O(n 2 ) n-place αργός (καλός για μικρές εισόδους) n-place αργός (καλός για μικρές εισόδους) n-place αργός (καλός για μικρές εισόδους) quc-sort O(n log n) expected O(n 2 ) n-place, randomzed ταχύτατος (καλός για μεγάλες εισόδους) heap-sort O(n log n) O(n log n) merge-sort O(n log n) O(n log n) n-place ταχύς (καλός για μεγάλες εισόδους) σειριακή πρόσβαση δεδομένων ταχύς (καλός για πολύ μεγάλες εισόδους) Δομές Δεδομένων και Αλγόριθμοι Εργαστήριο Γνώσης και Ευφυούς Πληροφορικής 91