- Πίνακες 1
Πίνακες Οι πίνακες έχουν σταθερό μέγεθος και τύπο δεδομένων. Βασικά πλεονεκτήματά τους είναι η απλότητα προγραμματισμού τους και η ταχύτητα. Ωστόσο δεν παρέχουν την ευελιξία η οποία απαιτείται για την αντιμετώπιση πολλών προβλημάτων. 2
Πίνακες (arrays) Ακολουθία μεταβλητών με το ίδιο όνομα, με τον ίδιο τύπο δεδομένων, σε συνεχόμενες θέσεις μνήμης. Παράδειγμα int a[50]; double d1[5], d2[10]; Η αρίθμηση αρχίζει από το 0! for (i = 0; i < 50; i++) a[i] = i; 3
Πίνακες (arrays) Αρχικοποίηση πινάκων int a[3] = {6, 7, 42}; char c[] = {'a', 'b', 'c', 'd', 'e'}; Συμβολοσειρές Είναι πίνακες χαρακτήρων char s[6] = "abcde"; Τερματίζονται με τον κενό χαρακτήρα '\0' char s[6] = {'a', 'b', 'c', 'd', 'e', '\0'}; 4
Πίνακες (arrays) Παράδειγμα int a[3] = {5, 6, 7}; int b[3] = {2, 3, 1}; int i; for (i = 0; i < 3; i++) printf("%d times %d is %d\n", a[i], b[i], a[i]*b[i]); 5 times 2 is 10 6 times 3 is 18 7 times 1 is 7 5
Πολυδιάστατοι πίνακες Παράδειγμα int a[3][5]; char c[5][10][4]; Αρχικοποίηση int i[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }; char s[][10] = { "my", "name", "is", "joe" }; 6
Πολυδιάστατοι πίνακες Παράδειγμα: πολλαπλασιασμός πινάκων double a[3][4] =..., b[4][5] =..., c[3][5]; int i, j, k; for (i=0; i<3; i++) for (j=0; j<5; j++) { c[i][j] = 0.0; for (k=0; k<4; k++) c[i][j] += a[i][k] * b[k][j]; } 7
Πίνακες ως ΑΤΔ (i) Βασική πράξη: προσπέλαση στοιχείου a[i] Συνήθως υλοποιούνται με κάποιο ΣΤΔ πινάκων (arrays) Κόστος προσπέλασης: O(1) Ο ΣΤΔ του μονοδιάστατου πίνακα επαρκεί για την υλοποίηση κάθε ΑΤΔ πίνακα Συνάρτηση loc υπολογίζει τη θέση ενός στοιχείου του ΑΤΔ πίνακα στο μονοδιάστατο ΣΤΔ πίνακα της υλοποίησης 8
Πίνακες ως ΑΤΔ (ii) ΑΤΔ πίνακα δύο διαστάσεων n m i = 1 0 1 2 3 4 5 i = 2 6 7 8 9 10 11 i = 3 12 13 14 15 16 17 n = 3 m = 6 j = 1 2 3 4 5 6 loc (n, m, i, j) = m (i 1) + j 1 Αρίθμηση κατά στήλες loc (n, m, i, j) = n (j 1) + i 1 9
Πίνακες ως ΑΤΔ (iii) ΑΤΔ κάτω τριγωνικού πίνακα n n i = 1 i = 2 i = 3 i = 4 i = 5 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 j = 1 2 3 4 5 n = 5 loc (n, i, j) = i (i 1) / 2 + j 1 Ομοίως για συμμετρικούς πίνακες 10
Πίνακες ως ΑΤΔ (iv) ΑΤΔ τριδιαγώνιου πίνακα n n i = 1 i = 2 i = 3 i = 4 i = 5 0 1 2 3 4 5 6 7 8 9 10 11 12 j = 1 2 3 4 5 n = 5 loc (n, i, j) = 2 i + j 3 11
Πίνακες ως ΑΤΔ (v) ΑΤΔ αραιού πίνακα n m i = 1 a 1 i = 2 a 2 i = 3 a 3 a 4 i = 4 j = 1 2 3 4 5 Υλοποίηση με δυαδικό πίνακα Υλοποίηση με τρεις πίνακες row = [ 1, 2, 3, 3, 4 ] col = [ 1, 3, 2, 3, 5 ] val = [ a 1, a 2, a 3, a 4, a 5 ] a 5 n = 4 m = 5 12
Πίνακες Ανάλυση 13
Μέσος όρος (Quadratic) Ο επόμενος αλγόριθμος υπολογίζει το μέσο όρο σε τετραγωνικό χρόνο, εφαρμόζοντας τον ορισμό Algorithm prefixaverages1(x, n) Input array X of n integers Output array A of prefix averages of X #operations A new array of n integers n for i 0 to n 1 do n s X[0] n for j 1 to i do 1 2 (n 1) s s X[j] 1 2 (n 1) A[i] s (i 1) n return A 1 14
Ανάλυση Ο χρόνος εκτέλεσης του prefixaverages1 είναι O(1 2 n) Το άθροισμα των πρώτων n ακεραίων είναι n(n 1) 2 Μια απλή απεικόνιση του αποτελέσματος Επομένως ο αλγόριθμος prefixaverages1 τρέχει σε O(n 2 ) χρόνο 7 6 5 4 3 2 1 0 1 2 3 4 5 6 15
Μέσος όρος (Γραμμικός) Ο επόμενος αλγόριθμος υπολογίζει το μέσο όρο σε γραμμικό χρόνο υπολογίζοντας ένα άθροισμα σε κάθε βήμα Algorithm prefixaverages2(x, n) Input array X of n integers Output array A of prefix averages of X A new array of n integers n s 0 1 for i 0 to n 1 do n s s X[i] n A[i] s (i 1) n return A 1 #operations Ο αλγόριθμος prefixaverages2 τρέχει σε O(n) χρόνο 16
Πίνακες Αναζήτηση 17
Αναζήτηση Έχω έναν πίνακα Α με Ν στοιχεία. Πρόβλημα: Βρες αν το στοιχείο x ανήκει στον πίνακα Αν ο πίνακας είναι αταξινόμητος τότε μόνη λύση σειριακή αναζήτηση for (i=0; i<n; i++) if (A[i]==x) return i;//th thesh toy stoixeioy return -1; //-1 dhlonei apotyxia Χειρότερη και Μέση περίπτωση: O(N) 18
Αναζήτηση σε πίνακες Σειριακή αναζήτηση Τα στοιχεία διατρέχονται κατά σειρά Κόστος: O(n) 12 9 72 22 42 99 14 61 (1) (2) (3) (4) (5) n = 8 x = 42 19
Αναζήτηση σε πίνακες Υλοποίηση σε C int ssearch (int a[], int n, int x) { int i; } for (i = 0; i < n; i++) if (a[i] == x) return i; return -1; 20
Παράδειγμα Εύρεση ενός στοιχείου σε αταξινόμητο πίνακα. Χειρότερη Περίπτωση: Ψάχνω όλον τον πίνακα δηλ. n συγκρίσεις => Ο(n) Μέση Περίπτωση: Θεωρώ ισοπίθανο το να βρεθεί το στοιχείο που ψάχνω σε οποιαδήποτε από τις θέσεις του πίνακα. Από ορισμό έχω: A( n) 1 k n 1/ n k 1 2... n n n n n( n 1)/2 n ( n 1)/2 O( n) 21
Δυαδική Αναζήτηση Αν ο πίνακας είναι ταξινομημένος μπορώ να εφαρμόσω δυαδική αναζήτηση (binary search) ΙΔΕΑ Πήγαινε στο μεσαίο στοιχείο του πίνακα (έστω Α[mid]) Αν Α[mid]==x επέστρεψε επιτυχία Αν Α[mid]<x τότε πήγαινε στη μέση του υποπίνακα mid+1..n-1 Αν Α[mid]>x τότε πήγαινε στη μέση του υποπίνακα 0..mid-1 Συνέχισε αναδρομικά 22
Παράδειγμα: Δυαδική Αναζήτηση Πόσα στοιχεία εξετάζουμε στη χειρότερη περίπτωση? Απάντηση: 4 (= log 2 16) 23
Αναζήτηση σε πίνακες Δυαδική αναζήτηση Ο πίνακας πρέπει να είναι ταξινομημένος Κόστος: O(logn) 3 7 14 22 42 61 72 99 (1) (3) (2) Άλλες μέθοδοι αναζήτησης n = 8 x = 42 Μικρότερο κόστος περισσότερος χώρος Πίνακες κατακερματισμού (hash tables) 24
Δυαδική Αναζήτηση-Κώδικας #include <iostream> using namespace std; int binarysearch (int A[], int x, int left, int right){ int mid; if (left>right) return -1; mid=(left+right)/2; if (A[mid]==x) return mid; if (A[mid]<x) return binarysearch(a,x,mid+1,right); else return binarysearch(a,x,left,mid-1); } void main(){ int A[10]={0,1,2,3,4,5,6,7,8,9}; cout << binarysearch(a,8,0,9) << endl; cout << binarysearch(a,10,0,9) << endl; } 25
Δυαδική Αναζήτηση (συν.) // Επιστροφή της θέσης του στοιχείου με τιμή // x στον ταξινομημένο πίνακα a μεγέθους n. int BinarySearch(int a[], int n, int x) { int left = 0; int right = n-1; // όρια πίνακα while (left <= right) { // σταμάτα όταν τα // όρια ταυτιστούν int middle = (left + right) / 2; // έλεγχος του μεσαίου στοιχείου if (x == a[middle]) return middle; // βρέθηκε if (x > a[middle]) left = middle + 1; else right = middle 1; // αναζήτηση στο δεξί ή αριστερό μισό, αντίστοιχα } return -1; // ένδειξη ότι δεν βρέθηκε } 26
Ανάλυση Ποια η πολυπλοκότητα στη χειρότερη περίπτωση? - Χειρότερη περίπτωση = Να μη βρεθεί καθόλου Απλή ανάλυση Επανάληψη 1 : Απομένει N/2 (μισός πίνακας) Επανάληψη 2: N/4 Επανάληψη 3: N/8. Δηλ. Για μια τυχαία επανάληψη k απομένει (1/2) k Ν Ο αλγ. Τελειώνει όταν στην επανάληψη k για την οποία ισχύει (1/2) k Ν=1=> 2 k =Ν => k=logn Άρα Θ(logN) στη χειρότερη περίπτωση. Η ανάλυση της μέσης περίπτωσης είναι πιο δύσκολη... 27
Δυαδική Αναζήτηση-Ανάλυση Χειρότερη περίπτωση: To στοιχείο δε βρίσκεται στον πίνακα Μας ενδιαφέρει το πλήθος συγκρίσεων που γίνονται. Σε κάθε κλήση της αναδρομής ο αλγόριθμος κάνει μια σύγκριση και κατόπιν συνεχίζει για το μισό πίνακα που απομένει. Έστω Τ(Ν) η πολυπλοκότητα για μέγεθος πίνακα Ν. Τότε έχω Τ(Ν)<=Τ( N / 2 ) +1 με αρχική τιμή Τ(1)=1 Για τη λύση της αναδρομής διακρίνω 2 περιπτώσεις: To N είναι δύναμη του 2 Το Ν δεν είναι 28
Δυαδική Αναζήτηση-Ανάλυση Αν το Ν είναι δύναμη του 2 τότε έχω: T(N) <= T(N/2) +1 T(N/2) <= T(N/4) +1 T(N/4) <= T(N/8) + 1.. T(N/2 logn-1 ) <= T(N/2 logn ) + 1 Αθροίζοντας παίρνω Τ(Ν) <= logn + 1 29
Δυαδική Αναζήτηση-Ανάλυση Αν το Ν δεν είναι δύναμη του 2 αποδεικνύω επαγωγικά ότι Τ(Ν)<= logn + 1 Για Ν=3 ισχύει αφού χρειάζομαι 2 συγκρίσεις (Τ(Ν)=2 ) Έστω ότι ισχύει για k<ν Θα δείξω για k=n Έχω: T(N) <= T( N / 2 ) + 1 <= (από επαγωγική υπόθεση) log N / 2 + 1 + 1 <= log(( N 1) / 2) +1 +1 <= log( N 1) + 1 <= logn + 1 Επομένως ο αλγόριθμος στη χειρότερη περίπτωση (όπου δε βρίσκουμε αυτό που αναζητούμε) έχει πολυπλοκότητα Ο(logN). 30
Δυαδική Αναζήτηση-Ανάλυση Μέση Περίπτωση: Στη μέση περίπτωση το στοιχείο μπορεί να βρίσκεται στον πίνακα σε οποιαδήποτε θέση του ή και να μη βρίσκεται. Υπάρχουν 2Ν + 1 καταστάσεις στις οποίες μπορεί να τερματίσει η αναζήτηση. Οι Ν αντιστοιχούν σε επιτυχή αναζήτηση (μία για κάθε θέση του πίνακα που μπορεί να βρεθεί το στοιχείο) Οι υπόλοιπες Ν+1 αντιστοιχούν στις θέσεις που μπορεί να τερματίσει η αναζήτηση ανεπιτυχώς (Ν-2 ενδιάμεσα των στοιχείων και 2 στις άκρες του πίνακα) Αν θεωρήσω ισοπίθανα τα 2Ν+1 ενδεχόμενα αθροίζοντας προκύπτει πάλι Ο(logN) (η απόδειξη αφήνεται) 31
Αναζήτηση Παρεμβολής (Interpolation Search) Γενικώς, αν τα στοιχεία του πίνακα είναι οποιασδήποτε μορφής (αρκεί να ορίζεται σχέση διάταξης) πχ. αλφαριθμητικά, μπορεί να αποδειχτεί ότι δεν υπάρχει αλγόριθμος που να λύνει το πρόβλημα της αναζήτησης σε χρόνο λιγότερο του Ο(logN). Στην ειδική περίπτωση που τα στοιχεία είναι αριθμοί μπορούμε να ρίξουμε το χρόνο στη μέση περίπτωση. ΙΔΕΑ Παρεμβολής Ίδια με Binary Search μόνο που σαν mid επιλέγεται το: x A[ left] ( right A[ right] A[ left] left) left 32
Αναζήτηση Παρεμβολής (Interpolation Search) ΠΑΡΑΔΕΙΓΜΑ 1 Έστω πίνακας Α={2,4,6,...,20} και x = 20 Τότε στην πρώτη κλήση επιλέγεται: x A[ left] ( right A[ right] A[ left] mid=(20-2)/(20-2) * (9-0) + 0 δηλ. 1*9+0 δηλ. η θέση 9 left) left Με άλλα λόγια ο αλγόριθμος θα βρει κατευθείαν το ζητούμενο κάνοντας μια μόνο σύγκριση (σε αντίθεση με τη δυαδική αναζήτηση) Γενικά αν τα στοιχεία του πίνακα αντιπροσωπεύουν αριθμητική πρόοδο η αναζήτηση παρεμβολής έχει πολυπλοκότητα Ο(1). 33
Αναζήτηση Παρεμβολής (Interpolation Search) ΠΑΡΑΔΕΙΓΜΑ 2 Έστω πίνακας Α={0,1,2,3,4,5,6,7,8,9000} και x = 8 x A[ left] ( right Τότε στην πρώτη κλήση επιλέγεται: A[ right] A[ left] mid=(8-0)/(9000-0) * (9-0) + 0 δηλ. 72/9000 δηλ. η θέση 0 left) left Η δεύτερη κλήση θα είναι για left =1 mid=8-1/9000-1 *(9-1) + 1 = 56/8999 +1 δηλ η θέση 1 Κατόπιν θα ελεγχθεί η θέση 2,3,4...8 Με άλλα λόγια στη χειρότερη περίπτωση ο αλγόριθμος έχει πολυπλοκότητα Ο(Ν) Στη μέση περίπτωση μπορεί να αποδειχτεί ότι είναι Ο(loglogN) 34