ΓΕ0170 -Αλγόριθμοι και Προηγμένες Προγραμματικές Τεχνικές Array-based sequences Νίκος Αθανάσης e-mail: athanasis@geo.aegean.gr
Χαρακτηριστικά Object Oriented Programming Ευρωστία Προσαρμοστικότητα portability επαναχρησιμοποίηση Τμηματοποίηση Math, δομές δεομένων Αφαιρετικότητα Ενθυλάκωση
Χαρακτηριστικά Robustness (Ευρωστία): Το σύστημα μπορεί να χειρίζεται απροσδόκητες ροές πληροφορίας Adaptability (Προσαρμοστικότητα): Το σύστημα μπορεί να προσαρμόζεται με βάση τις υπάρχουσες ανάγκες της τεχνολογίας
Χαρακτηριστικά Reusability (επαναχρησιμοποίηση): Ο ίδιος κώδικας μπορεί να χρησιμοποιηθεί από διαφορετικά συστήματα και εφαρμογές Modularity (Τμηματοποίηση ): Το σύνθετο σύστημα αποτελείται από επιμέρους τμήματα που αλληλεπιδρούν μεταξύ τους
Χαρακτηριστικά Abstraction (Αφαιρετικότητα): Το σύνθετο σύστημα αποτελείται από επιμέρους τμήματα σε μια ιεραρχική δομή
Χαρακτηριστικά Encapsulation (Ενθυλάκωση): Το κάθε τμήμα «κρύβει» τα χαρακτηριστικά του από τα υπόλοιπα
Class Diagram για την κλάση CreditCard
Παραδείγματα University Cars
Arrays και Sequences Lists [1,2,3] Tuples (1,2,3) Strings 1,2,3 Είναι κλάσεις της Python που υποστηρίζουν δείκτες (πχ l[1], t[0], s[2]) για αυτό λέγονται και array-based sequences
Αναπαράσταση μνήμης RAM: Συνεχόμενες θέσεις στη διεύθυνση μνήμης (memory adress) v Κάθε θέση (κελί) στο array χρησιμοποιεί τον ίδιο αριθμό από bytes Κάθε κελί είναι άμεσα προσβάσιμο μέσω του τύπου Start + (Cellsize) * index Έτσι, η προβασιμότητα για κάθε θέση μνήμης είναι η ίδια Για αυτό και λέγεται Random Access Memory Σε μια γλώσσα προγραμματισμού: Συσχετιζόμενα αντικείμενα αποτελούν ένα array με ένα κοινό όνομα και έναν δείκτη για πρόσβαση στο κάθε επιμέρους στοιχείο
Arrays και συνεχόμενες θέσεις μνήμης Οι 6 χαρακτήρες του αλφαριθμητικού SAMPLE αποθηκεύονται σε ένα array 6 χαρακτήρων σε 12 bytes μνήμης
names = [ Rene, Joseph, Janet, Jonas, Helen, Virginia ] print(names[0] primes = [2,3,5,7,11,13,17,19] temp = primes[3:6] temp[2] = 15
Όλα τα κελιά αναφέρονται στο ίδιο αντικείμενο Counters = [0] * 8 counters[2]+=1 Το κελί στη θέση 2 δείχνει σε μια νέα θέση μνήμης.
primes = [2,3,5,7,11,13,17,19] extras = [23,29,31] primes.extend(extras) print(primes)
fruits = ['apple', 'pear', 'banana', 'kiwi', 'apple', 'pineapple'] print ("Fruits are: {}".format(fruits)) print ("How many fruits are there? {}".format(len(fruits))) print ("How many grapes are there? {}".format(fruits.count('grape'))) print ("First two fruits are: {}".format(fruits[0:2])) fruits.reverse() print ("Fruits reversed:", end = " ") print(fruits) fruits.append('grape') fruits.insert(1, "grape fruit") print ("Appending grape and inserting grape fruit at place 1. Fruits now are: {}".format(fruits)) fruits.sort() print ("Fruits sorted: {}".format(fruits)) forest_fruits = ['strawberries', 'raspberries', 'blueberries'] print ("Forest fruits:", end = " ") print(forest_fruits) fruits.extend(forest_fruits) print ("Extending fruits with forest fruits:", end = " ") print(fruits) fruits.remove("apple") print ("Removing apple. Fruits are: {}".format(fruits)) # Πώς θα διαγράψουμε όλα τα apples? print ("Fruits seperated with \",\":") for fruit in fruits: print(fruit,end=',')
vec = [-4, -2, 0, 2, 4] vec2 = [x*2 for x in vec] print (vec2) vec3 = [x for x in vec if x >= 0] print(vec3) vec4 = [abs(x) for x in vec] print(vec4) names = [' nick dimitriou', ' jack zahariou', ' maria anastasiou '] names2= [name.strip() for name in names] print (names2) vec5 = [(x, x+1) for x in range(6)] print(vec5) list_sentence = ['this','is','a','sentence'] list_sentence = ' '.join(list_sentence)+"." print(list_sentence)
Tuples (πλειάδες) t = 12345, 54321, 'hello! u = t, (1, 2, 3, 4, 5) Οι λίστες είναι are mutable (μεταβλητά αντικείμενα), και περιέχουν στοιχεία ίδιου τύπου Οι πλειάδες είναι μη μεταβλητά αντικείμενα (immutable) και μπορεί να είναι διαφορετικών τύπων
Παράδειγμα t1 = 12345, 54321, "hello1!" t2 = (12345, 54321, "hello2!") print (t1 == t2) u = t1, t2, (1, 2, 3, 4, 5), "hello3", 1,2,3 print(u) print(u[1]) x = u[1] print(x[2]) #x[2] = "hello4" TypeError: 'tuple' object does not support item assignment
Sets (σειρές): Μη διατεταγμένα στοιχεία, ίδιου τύπου, χωρίς διπλότυπες εγγραφές fruits = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} print("fruits:{}".format(fruits)) print("fruits sorted:{}".format(sorted(fruits))) has_orange = ' orange' in fruits print("has orange:{}".format(has_orange)) a = set('abcdd') print(a) b = set('abcce') print(b) c = a-b print(c) #Εκτελέστε το πολλές φορές και δείτε τί συμβαίνει!
print('is jim in telephones?{}'.format('jim' in tel)) Dictionaries (λεξικά) Αντί να χρησιμοποιούν ως δείκτη έναν αριθμό, χρησιμοποιούν ένα key tel = {'nick': 697112233, 'jim': 697445566} print ("Telephones:{}".format(tel)) print ("Telephone of nick:{}".format(tel['nick'])) dict([("nick", 697112233), ("jim", 697445566)]) dict(nick= 697112233, jim= 697445566) tel['sofia'] = 698119988 print ("Telephones:{}".format(tel)) del tel['jim'] tel['nick'] = 698667755 tel['antonis'] = 69899999 print ("Telephones:{}".format(tel)) keys_list = list(tel.keys()) print ("Telephone keys:{}".format(keys_list)) keys_list.sort() print ("Telephone keys sorted:{}".format(keys_list))
Iterations names = ['Nick', 'Jack', 'Jim'] for i, v in enumerate(names): print(i, v) LastNames = ['Athanasis', 'Dimitriou', 'Zahariou'] for n, l in zip(names, LastNames): print('name: {0}.\tLast name: {1}.'.format(n, l))
Παράδειγμα Αντικειμενοστραφούς Προγραμματισμού με List: H κλάση CreditCard
Εκφώνηση Εργασίας
def katoptriki(s): s = s.replace(' ', '') size = len(s) cnt = 0 i = 0 while i < size: if s[i] == s[-1-cnt]: i +=1 cnt+=1 else: return False return True print (katoptriki("νιψον ανομηματα μη μοναν οψιν")) Κατοπτρικές φράσεις
def rev_word(s): words = [] s_split = s.split(' ') cnt = 0 for i in range(len(s_split)): word = s_split[len(s_split)-1-cnt] #print(word) if len(word)>0: words.append(word) cnt +=1 #return words return " ".join(words) print (rev_word("nik athanasis")) Αντιστροφή λέξεων σε φράση def rev_word2(s): words = [] length = len(s) i = 0 while i < length: if s[i]!=' ': word_start = i while i < length and s[i]!=' ': i += 1 words.append(s[word_start:i]) i += 1 return " ".join(reversed(words)) print (rev_word2("nik athanasis"))
def anagram(s1,s2): s1 = s1.replace(' ','').lower() s2 = s2.replace(' ','').lower() if len(s1)!= len(s2): return False dict = {} for letter in s1: if letter in dict: dict[letter] += 1 else: dict[letter] = 1 Αναγραμματισμοί for letter in s2: if letter in dict: dict[letter] -= 1 else: return False return True print(anagram('nik ','ink'))
def compress(s): r = "" l = len(s) if l == 0: return "" Συμπίεση του AAAABBBBCCCCCDDEEEE = A4B4C5D2E4 if l == 1: return s + "1" cnt = 1 i = 1 while i < l: if s[i] == s[i - 1]: cnt += 1 else: r = r + s[i - 1] + str(cnt) cnt = 1 Εντοπίστε και διορθώστε το σφάλμα κατά την εκτέλεση i += 1 return r print compress("aaaabbbb")
Λίστες και καταχώρηση τιμών list2 = [] list2 = list2 + [1] list2.append(2) print(list2) def method1(): my_list1 = [] for n in range(100000): my_list1 = my_list1 + [n] #print(my_list) def method2(): my_list2 = [] for n in range(100000): my_list2.append(n) #print(my_list)
Λίστες και καταχώρηση τιμών def method3(): my_list3 = [n for n in range(100000)] #print(my_list) def method4(): my_list4 = list(range(100000)) #print(my_list) method4() print("done 4") method1() print("done 1") method3() print("done 3") method2() print("done 2")
Μερικό άθροισμα def average1(s): n = len(s) A = [0]*n for i in range(n): total = 0 for j in range(i + 1): total += S[j] A[i] = total / (i+1) return A numbers = [1,2,3,4,5] print(average1(numbers))
Μερικό άθροισμα def average2(s): n = len(s) A = [0]*n total = 0 for j in range(n): total += S[j] A[j] = total / (j+1) return A numbers = [1,2,3,4,5] print(average2(numbers))
def unique1(s): for i in range(len(s)): for j in range(i+1, len(s)): if S[i] == S[j]: return False return True print(unique1("abcd")) print(unique1("abcda")) def unique2(s): temp =sorted(s) for i in range(1,len(temp)): if temp[i-1] == temp[i]: return False def unique3(s): chars = [] for let in s: # Check if in list if let in chars: return False else: chars.append(let) return True print(unique3("abcd")) print(unique3("abcda")) Διπλά γράμματα return True print(unique2("abcd")) print(unique2("abcda")
H Λίστα των HighScores (Nikos, 80) (Dimitris, 78) (Christos, 50) 0 1 2 High score list New Game: (Maria, 79) (Nikos, 80) (Maria, 79) (Dimitris, 78) 0 1 2
Υλοποίηση Game Περισσότερα στο αρχείο PlayGame στο φάκελο του μαθήματος
Ταξινόμηση Εισαγωγής
Υλοποίηση InsertSort Περισσότερα στο αρχείο InsertSort στο φάκελο του μαθήματος
Αποτελεσματικότητα Αλγορίθμων Είναι ο αλγόριθμος Α αποτελεσματικότερος του αλγόριθμου Β; Με άλλα λόγια, επιλύει ο αλγόριθμος Α το πρόβλημα Π σε λιγότερο χρόνο από τον αλγόριθμο Β; Πόσο θα αυξηθεί ο χρόνος εκτέλεσης του αλγόριθμου Α ή, ισοδύναμα, ο χρόνος επίλυσης του προβλήματος Π, εάν διπλασιάσουμε τα δεδομένα εισόδου του Π; Μπορώ να χρησιμοποιήσω τον αλγόριθμο Α, όταν τα δεδομένα εισόδου του προβλήματος Π, που επιλύει ο αλγόριθμος Α, είναι πολύ μεγάλα; Υπάρχει αλγόριθμος (ή, μπορώ να σχεδιάσω έναν) ο οποίος επιλύει το πρόβλημα Π σε δεδομένο χρόνο t;
Παράμετροι απόδοσης αλγόριθμου 1. Χρόνος εκτέλεσης 2. Απαιτούμενοι πόροι, π.χ. μνήμη, επικοινωνία (π.χ. σε κατανεμημένα συστήματα) 3. Βαθμός δυσκολίας υλοποίησης Ένας αλγόριθμος θα λέγεται αποδοτικός ή αποτελεσματικός, εάν ελαχιστοποιεί τις παραπάνω παραμέτρους
Πολυπλοκότητα και χρόνος εκτέλεσης αλγορίθμου Ένας αλγόριθμος με μικρό χρόνο εκτέλεσης θα λέμε ότι έχει μικρή πολυπλοκότητα χρόνου, ενώ αντίθετα ένας με μεγάλο χρόνο εκτέλεσης θα λέμε ότι έχει μεγάλη πολυπλοκότητα. Εμπειρική Προσέγγιση (posteriori) Θεωρητική Προσέγγιση (priori)
Εμπειρική Πολυπλοκότητα start_time = time( ) run _algorithm() # record the ending time end_time = time( ) # compute the elapsed time elapsed = end_time start_time Περισσότερα στο αρχείο Complexity στο φάκελο του μαθήματος
Θεωρητική Πολυπλοκότητα H θεωρητική πολυπλοκότητα καθορίζει μαθηματικά το χρόνο (και άλλες παραμέτρους) που απαιτεί ο αλγόριθμος, συναρτήσει του μεγέθους των εξεταζόμενων εισόδων του. Το πλεονέκτημα της θεωρητικής προσέγγισης για τον υπολογισμό της αποτελεσματικότητας ενός αλγόριθμου είναι ότι: δεν εξαρτάται από τον Η/Υ, δεν εξαρτάται από την γλώσσα προγραμματισμού, δεν εξαρτάται από τις ικανότητες του προγραμματιστή.
Ασυμπτωτική ανάλυση Θέλουμε να συγκρίνουμε πόσο γρήγορα ο χρόνος εκτέλεσης αυξάνεται, όχι να συγκρίνουμε τους χρόνους εκτέλεσης αφού αυτοί εξαρτώνται από τους πόρους του συστήματος Αφού θέλουμε να συγκρίνουμε το χρόνο εκτέλεσης για διαφορετικά μεγέθη εισόδου, μας ενδιαφέρει η αύξηση του χρόνου εκτέλεσης σε σχέση με τα δεδομένα εισόδου Καθώς τα δεδομένα (n) αυξάνονται, μας ενδιαφέρει η συμπεριφορά του αλγορίθμου όταν τα δεδομένα (n) γίνονται πάρα πολύ μεγάλα (Ασυμπτωτική ανάλυση)
Ασυμπτωτική ανάλυση
Παραδείγματα πολυπλοκότητας O(1) (σταθερή πολυπλοκότητα): Εύρεση του τηλεφώνου στον τηλεφωνικό κατάλογο αν γνωρίζουμε τη σελίδα και το όνομα που ψάχνουμε O(n) (γραμμική): Βρείτε όλα τα άτομα που το τηλέφωνό τους περιέχει το ψηφίο «9» O(n): Με δεδομένο ένα τηλέφωνο, βρείτε το όνομα στο οποίο αντιστοιχεί O(log n): Με δεδομένο ένα όνομα, βρείτε το τηλέφωνο του στον τηλεφωνικό κατάλογο (δυαδική αναζήτηση) O(n log n): Ταξινομήστε τις σελίδες του καταλόγου σε αλφαβητική σειρά, κοιτάζοντας το πρώτο όνομα σε κάθε σελίδα και τοποθετώντας κάθε σελίδα στην κατάλληλη θέση
def func_constant(values): ''' Prints first item in a list of values. ''' print (values[0]) func_constant([1,2,3]) def func_lin(lst): ''' Takes in list and prints out all values ''' for val in lst: print (val) func_lin([1,2,3]) def comp(lst): print (lst[0]) midpoint = len(lst)//2 for val in lst[:midpoint]: print (val) for x in range(10): print ("number") lst = [1,2,3,4,5,6,7,8,9,10] comp(lst) Τι πολυπλοκότητα έχει? def func_quad(lst): ''' Prints pairs for every item in list. ''' for item_1 in lst: for item_2 in lst: print (item_1,item_2) lst = [0, 1, 2, 3] func_quad(lst)
Ασυμπτωτική ανάλυση
Αλγοριθμική ανάλυση Πίνακας αλγοριθμικής ανάλυσης Μέγιστο μέγεθος δεδομένων προβλήματος (n) που μπορεί να λυθεί σε συγκεκριμένο χρονικό διάστημα για διαφορετικούς αλγόριθμους
Συμβολισμοί πολυπλοκότητας Την πολυπλοκότητα την εκφράζουμε με τη βοήθεια ειδικών συμβολισμών: Ο, Ω, Θ. Χρησιμοποιούμε το συμβολισμό Ο και το συμβολισμό Ω για να δηλώσουμε ότι η επίδοση ενός αλγορίθμου είναι ασυμπτωτικά φραγμένη από επάνω και από κάτω αντίστοιχα. Με το συμβολισμό Θ δηλώνουμε ότι η επίδοση ενός αλγορίθμου είναι ασυμπτωτικά φραγμένη από επάνω και από κάτω ταυτόχρονα. Ο
Συμβολισμός Ο Συμβολισμός Ο. Μία συνάρτηση f(n) λέγεται ότι έχει πολυπλοκότητα της τάξης O(g(n)) και συμβολίζεται με f(n) = O(g(n)) ή με f(n) O(g(n)), αν υπάρχει μία θετική σταθερά c και μία τιμή n0, έτσι ώστε για κάθε n > n0 να ισχύει η σχέση f(n) < cg(n).
Συμβολισμός Ω Συμβολισμός Ω. Μία συνάρτηση f(n) λέγεται ότι έχει πολυπλοκότητα της τάξης Ω(g(n)) και συμβολίζεται με f(n) = Ω(g(n)) ή με f(n) Ω(g(n)), αν υπάρχει μία θετική σταθερά c και μία τιμή n0, έτσι ώστε για κάθε n > n0 να ισχύει η σχέση f(n) > cg(n).
Συμβολισμός Θ Συμβολισμός Θ. Μία συνάρτηση f(n) λέγεται ότι έχει πολυπλοκότητα της τάξης Θ(g(n)) και συμβολίζεται με f(n) = Θ(g(n)) ή με f(n) Θ(g(n)), αν υπάρχουν δύο θετικές σταθερές c1, c2 και μία τιμή n0, έτσι ώστε κάθε για n > n0 να ισχύει η σχέση c2g(n) < f(n) < c1g(n).
Συμβολισμός Ο «Η f (n) είναι O(g(n)). Εναλλακτικά, Η f (n) είναι τάξης (order of) g(n). Εναλλακτικά, f (n) O(g(n))», f(x) O( άνω άκρο ) σημαίνει ότι η f «μεγαλώνει όχι γρηγορότερα από" το ανω άκρο Στον Συμβολισμό Ο δεν μας ενδιαφέρουν σταθεροί όροι / μη ασυμπτωτικοί όροι Ο αλγόριθμος τάξης 9x² είναι ίδιας τάξης με τον 10x². ο αλγόριθμος τάξης 10x² είναι ίδιας τάξης με τον 10x² - x + 2017 διότι, τα μικρότερα μέρη τείνουν να μην έχουν σημασία σε μεγάλη κλίμακα
Συμβολισμός Ο Μας ενδιαφέρει ο λόγος (ratio) καθώς το μέγεθος των δεδομένων τείνουν στο άπειρο
Παραδείγματα Η συνάτηση 8n+5 είναι O(n). Αρκεί να βρούμε μια σταθερά c>0, και μια σταθερά no>=1 ώστε 8n+5 cn για κάθε n n0. Με c = 9 και n0 = 5, έχουμε 8n+5<=9n που ισχύει για κάθε n>=5 ή εναλλακτικά με c = 13 έχω 8n+5<=13n που ισχύει για κάθε n>=1 Η 5n 4 +3n 3 +2n 2 +4n+1 είναι O(n 4 ). Διότι: 5n 4 +3n 3 +2n 2 +4n+1 (5+3+2+4+1)n 4 = cn 4, για c = 15 Η 5n 2 +3nlog n+2n+5 is O(n 2 ). Διότι:5n 2 +3nlog n+2n+5 (5+3+2+5)n 2 =cn 2, για c=15 Η 20n 3 +10nlog n+5 είναι O(n 3 ). Διότι: 20n 3 +10nlog n+5 35n 3, για c=35 H 3logn+2 είναι O(logn). Διότι: 3logn+2 5logn, για c=5. H 2n+100log n is O(n). Διότι: 2n+100log n 102n, για c= 102