ΜΥΥ105: Εισαγωγή στον Προγραµµατισµό Αναζήτηση και Ταξινόµηση Χειµερινό Εξάµηνο 2014
Αναζήτηση και Ταξινόµηση Βασικές λειτουργίες σε προγράµµατα Αναζήτηση (searching): Βρες ένα ζητούµενο στοιχείο σε µια δοθείσα ακολουθία στοιχείων Ταξινόµηση (sorting): Ταξινόµησε µια δοθείσα ακολουθία στοιχείων Οι περισσότερες µοντέρνες γλώσσες προγραµµατισµού έχουν υλοποιηµένες αυτές τις λειτουργίες σαν συναρτήσεις (ή µεθόδους) Εµείς θα µάθουµε κάποιους αλγορίθµους και πως υλοποιούνται στην Python 2
Έτοιµες συναρτήσεις αναζήτησης στην Python Η µέθοδος index() επιστρέφει τη θέση ενός στοιχείου σε µια ακολουθία. Αν το στοιχείο υπάρχει πολλές φορές, τότε επιστρέφει την πρώτη θέση. >>> s = 'abcdefab' >>> s.index('b') 1 >>> l = [1,2,3,4,5,6,1,2,3,4,5] >>> l.index(3) 2 >>> l.index(99) Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> l.index(99) ValueError: 99 is not in list Η μέθοδος find() έχει παρόμοια συμπεριφορά, αλλά ισχύει μόνο για αλφαριθμητικά. Η μέθοδος get() «ψάχνει» σε λεξικά. 3
Συνάρτηση αναζήτησης Άσκηση: γράψτε µια συνάρτηση search_list, η οποία παίρνει σαν όρισµα µια λίστα και ένα στοιχείο και επιστρέφει την πρώτη θέση του στοιχείου στη λίστα αν το στοιχείο υπάρχει -1 αλλιώς def search_list(l, x): for i in range(len(l)): if x == l[i]: return I return -1 >>> l = [1,2,3,4,5,6,1,2,3,4,5] >>> search_list(l, 4) 3 >>> search_list(l, 99) -1 if x in l: return l.index(x) 4
Συνάρτηση αναζήτησης Άσκηση: γράψτε µια συνάρτηση search_list2, η οποία παίρνει σαν όρισµα µια λίστα και ένα στοιχείο και επιστρέφει όλες τις θέσεις του στοιχείου στη λίστα >>> l = [1,2,3,4,5,6,1,2,3,4,5] >>> search_list2(l, 4) [3, 9] >>> search_list2(l,99) [] def search_list2(l, x): pos = [] for i in range(len(l)): if x == l[i]: pos.append(i) return pos 5
Γραµµική αναζήτηση Οι search_list, search_list2 υλοποιούν τη γραµµική αναζήτηση (linear search), όπου κοιτάµε ένα-ένα τα στοιχεία της ακολουθίας µέχρι να βρούµε το στοιχείο (ή τα στοιχεία) που ψάχνουµε Η γραµµική αναζήτηση δεν προϋποθέτει τίποτα σχετικά µε την οργάνωση των στοιχείων στην ακολουθία ο απλούστερος δυνατός τρόπος αναζήτησης συγκρίνει όλα τα στοιχεία της ακολουθίας µε το στοιχείο προς εύρεση χρήσιµος για µικρές, µη ταξινοµηµένες ακολουθίες 6
Δυαδική αναζήτηση Μπορούµε να εφαρµόσουµε δυαδική αναζήτηση (binary search), αν η ακολουθία µας είναι ταξινοµηµένη. Π.χ. ψάχνουµε το στοιχείο key στη λίστα lst Βασική ιδέα: mid = len(lst)/2 (το µεσαία θέση στη λίστα) αν lst[mid] == key τότε το βρήκαµε! αν lst[mid] > key τότε ψάχνουµε στο 1ο µισό της λίστας αν lst[mid] < key τότε ψάχνουµε στο 2ο µισό της λίστας ψάχνουµε αναδροµικά 7
Δυαδική αναζήτηση def binarysearchrec(lst, key, low, high): if low>high: return -1 else: mid=(low+high)//2 if key==lst[mid]: return mid elif key<lst[mid]: «βασική» περίπτωση 1: δεν βρέθηκε «βασική» περίπτωση 2: βρέθηκε! return binarysearchrec(lst, key, low, mid-1) else: return binarysearchrec(lst, key, mid+1, high) [1,2,3,4,5,6,9,10,15,20] key = 4 low = 0, high = 9 mid = 4, lst[mid]=5 [1,2,3,4,5,6,9,10,15,20] low = 0, high = 3 mid = 1, lst[mid]=2 [1,2,3,4,5,6,9,10,15,20] low = 2, high = 3 mid = 2, lst[mid]=3 [1,2,3,4,5,6,9,10,15,20] low = 3, high = 3 mid = 3, lst[mid]=4 return 3 8
Δυαδική αναζήτηση def binarysearchrec(lst, key, low, high): if low>high: return -1 else: mid=(low+high)//2 if key==lst[mid]: return mid elif key<lst[mid]: return binarysearchrec(lst, key, low, mid-1) else: return binarysearchrec(lst, key, mid+1, high) [1,2,3,4,5,6,9,10,15,20] key = 11 low = 0, high = 9 mid = 4, lst[mid]=5 [1,2,3,4,5,6,9,10,15,20] low = 5, high = 9 mid = 7, lst[mid]=10 [1,2,3,4,5,6,9,10,15,20] low = 8, high = 9 mid = 8, lst[mid]=15 [1,2,3,4,5,6,9,10,15,20] low = 8, high = 7 return -1 9
Δυαδική αναζήτηση Η δυαδική αναζήτηση είναι πολύ γρήγορη Σε κάθε αναδροµή, το εύρος της ακολουθίας που εξετάζουµε µειώνεται στο µισό Άσκηση: πόσες φορές καλείται η συνάρτηση (αναδροµικά) αν η λίστα έχει 1000 στοιχεία; 10 γιατί κάθε φορά ψάχνουµε στο µισό της λίστας από την προηγούµενη φορά Πόσες φορές καλείται για µια λίστα µήκους n; log 2 n στη χειρότερη περίπτωση 10
Δυαδική αναζήτηση Επαναληπτική συνάρτηση def binarysearch(lst, key, low, high): while low<=high: mid=(low+high)//2 if key==lst[mid]: return mid elif key<lst[mid]: high=mid-1 else: low=mid+1 return -1 11
Ταξινόµηση Στόχος της ταξινόµησης είναι να ανακατατάξει τα στοιχεία µιας ακολουθίας ώστε να εµφανίζονται µε σειρά από το µικρότερο στο µεγαλύτερο (η αντίστροφα) Η µέθοδος sort ταξινοµεί λίστες της Python Θυµηθείτε ότι τα αλφαριθµητικά και πλειάδες είναι µη µεταβαλλόµενα και στα λεξικά δεν έχει νόηµα η ταξινόµηση Η συνάρτηση sorted() επιστρέφει µια ταξινοµηµένη λίστα απο µια ακολουθία (λίστα, πλειάδα, string) ή λεξικό Θα δούµε κάποιους αλγορίθµους ταξινόµησης και πως αυτοί υλοποιούνται στην Python 12
Ταξινόµηση µε επιλογή: (selection sort) Λογική: Βρες το µικρότερο στοιχείο και βάλτο πρώτο, µετά το 2ο µικρότερο και βάλτο 2ο, κ.ο.κ. 64, 25, 12, 22, 11 11, 25, 12, 22, 64 11, 12, 25, 22, 64 11, 12, 22, 25, 64 11, 12, 22, 25, 64 13
Ταξινόµηση µε επιλογή: (selection sort) def SelectionSort(lst): for pos in range(0, len(lst)): # find min starting from pos minpos=findmin(lst, pos) # swap elements lst[pos],lst[minpos] = lst[minpos],lst[pos] def FindMin(lst, low): minpos=low for i in range(low, len(lst)): if lst[i]<lst[minpos]: minpos=i return minpos 14
Βubble sort Λογική: Συγκρίνουµε το κάθε στοιχείο µε το επόµενό του και αλλάζουµε τις θέσεις τους αν δεν είναι στη σωστή σειρά. Μετά το πρώτο πέρασµα το µεγαλύτερο στοιχείο θα είναι τελευταίο στη λίστα. Μετά το 2ο πέρασµα το δεύτερο µεγαλύτερο στοιχείο θα είναι προ-τελευταίο στη λίστα, κ.ο.κ. 15
Βubble sort: [64, 25, 12, 22, 11] πρώτο πέρασµα 64, 25, 12, 22, 11 25, 64, 12, 22, 11 25, 64, 12, 22, 11 25, 12, 64, 22, 11 25, 12, 64, 22, 11 25, 12, 22, 64, 11 25, 12, 22, 64, 11 25, 12, 22, 11, 64 το µέγιστο στοιχείο δεύτερο πέρασµα 25, 12, 22, 11, 64 12, 25, 22, 11, 64 12, 25, 22, 11, 64 12, 22, 25, 11, 64 12, 22, 25, 11, 64 12, 22, 11, 25, 64 το 2ο µέγιστο στοιχείο τρίτο πέρασµα 12, 22, 11, 25, 64 12, 22, 11, 25, 64 12, 11, 22, 25, 64 το 3ο µέγιστο στοιχείο... 16
Bubble sort def BubbleSort(lst): for i in range(len(lst)): # rounds for j in range(0,len(lst)-i-1): # i-th round if lst[j]>lst[j+1]: lst[j],lst[j+1] = lst[j+1],lst[j] 17
Insertion sort Λογική: Αρχίζοντας από το 2ο στοιχείο, βάλε το κάθε στοιχείο στη σωστή σειρά σε σχέση µε τα προηγούµενά του Τελειώνοντας το ν-στο στοιχείο τα πρώτα ν στοιχεία είναι ταξινοµηµένα 2ο στοιχείο 64, 25, 12, 22, 11 25, 64, 12, 22, 11 3ο στοιχείο 25, 64, 12, 22, 11 25, 12, 64, 22, 11 12, 25, 64, 22, 11 4ο στοιχείο 12, 25, 64, 22, 11 12, 25, 22, 64, 11 12, 22, 25, 64, 11 5ο στοιχείο 12, 22, 25, 64, 11 12, 22, 25, 11, 64 12, 22, 11, 25, 64 12, 11, 22, 25, 64 11, 12, 22, 25, 64 18
Insertion sort def InsertionSort(lst): for i in range(1,len(lst)): # 2nd, 3rd, etc. pos = i #swap with previous element while smaller while pos>0 and lst[pos]<lst[pos-1]: lst[pos],lst[pos-1] = lst[pos-1],lst[pos] pos = pos-1 19
Merge sort Λογική: Ταξινόµησε αναδροµικά το πρώτο µισό και το δεύτερο µισό της λίστας και µετά «συγχώνευσε» τα δύο µισά σε µια ταξινοµηµένη λίστα. MergeSort(64, 5, 25, 12, 22, 11) αναδρομικές κλήσεις MergeSort(64, 5, 25) MergeSort(12, 22, 11) 5, 25, 64 11, 12, 22 merge 5 11 12 22 25 64 20
Merge sort def MergeSort(lst): if len(lst)<=1: # base case: already sorted return lst else: # recursive case mid = (len(lst))//2 lst1 = MergeSort(lst[:mid]) # sort first half lst2 = MergeSort(lst[mid:]) # sort second half outl = [] # merged list to be returned i = j = 0 # pointers to positions of sorted halves while i<len(lst1) and j<len(lst2): if lst1[i]<=lst2[j]: outl.append(lst1[i]) i += 1 else: outl.append(lst2[j]) j += 1 outl.extend(lst1[i:]) # add remainders outl.extend(lst2[j:]) return outl 21
Άλλοι αλγόριθµοι ταξινόµησης Heap sort: βέλτιστος χρόνος στη χειρότερη περίπτωση (όπως και ο merge sort) Quick sort: βέλτιστος χρόνος στην πράξη Counting/Bucket sort: βέλτιστος χρόνος σε ειδικές περιπτώσεις Λεπτοµέρειες και ανάλυση στο µάθηµα: «Δοµές Δεδοµένων» 22