ASD 02
Transkrypt
ASD 02
Algorytmy i Struktury Danych Wykład II Sortowania 1 Co dziś? Garść teorii Sortowania proste Sortowania „szybkie” ASD 02 2 Sortowanie Sortowaniem nazywamy proces ustawiania zbioru obiektów w określonym porządku Zastosowanie algorytmów sortowania (edukacyjno/naukowe): # # # # wiele algorytmów rozwiązujących ten sam problem, prosta analiza algorytmów i ich porównanie, pokazują, że warto szukać nowych, zależność wyboru algorytmów od struktury przetwarzania danych (metody sortowania wewnętrzne i zewnętrzne). ASD 02 3 1 Sortowanie Sortowanie polega na przestawianiu obiektów, aż do chwili osiągnięcia ich uporządkowania takiego, że dla danej funkcji porządkującej f: f(a1) <= f(a2) <= ... <= f(an) (wartość tej funkcji nazywa się kluczem) ASD 02 4 Klasyfikacja metod Według rodzaju struktury danych # sortowanie tablicy # sortowanie listy, łańcucha Według miejsca sortowania # wewnętrzne # zewnętrzne Według podziału algorytmu na etapy # bezpośrednie (jeden etap - obiekty ulegają przestawieniom) # pośrednie - dwa etapy etap logiczny - informacja jak przestawiać obiekty, można wykonać kilka etapów logicznych etap fizyczny - nie zawsze konieczny ASD 02 5 Klasyfikacja metod Według wykorzystania pamięci # metody intensywne (in situ) # metody ekstensywne (dodatkowa pamięć - metody szybsze) Według efektywności (podział umowny) # metody proste O(n2) # metody szybkie O(n log n)) Według stabilności # stabilne # niestabilne ASD 02 6 2 Sortowanie przez wstawianie Insertionsort Zachowanie naturalne Algorytm stabilny Działa w miejscu Złożoność O(n2) Próba poprawy przez wstawianie połówkowe # liczba porównań nie zależy od docelowego miejsca początkowego elementu - faworyzuje nieuporządkowanie # zmienia się tylko liczba porównań, a nie przesunięć czasochłonne, gdy elementy są uporządkowane # gorsze niż liniowe przeszukiwanie ASD 02 7 Sortowanie przez wstawianie 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) |41>67|34|00|69|24|78|58|62|64| |41|67>34|00|69|24|78|58|62|64| |34|41|67>00|69|24|78|58|62|64| |00|34|41|67>69|24|78|58|62|64| |00|34|41|67|69>24|78|58|62|64| |00|24|34|41|67|69>78|58|62|64| |00|24|34|41|67|69|78>58|62|64| |00|24|34|41|58|67|69|78>62|64| |00|24|34|41|58|62|67|69|78>64| |00|24|34|41|58|62|64|67|69|78| for( i = 1 ; i < A.size() ; i++ ) { x = A[i]; l = 0; p = i-1; while( l <= p ) { m = (l+p) / 2; if ( x < A[m] ) p = m – 1; else l = m + 1; } for( j = i – 1 ; j >= l ; j-- ) A[j+1] = A[j]; A[l] = x; } 3 Sortowanie przez wybór Selectionsort Zachowanie naturalne Algorytm niestabilny Działa w miejscu Złożoność O(n2) Gorszy niż sortowanie przez wstawianie ASD 02 10 Sortowanie przez wybór 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) >41|67|34|00|69|24|78|58|62|64| |00>67|34|41|69|24|78|58|62|64| |00|24>34|41|69|67|78|58|62|64| |00|24|34>41|69|67|78|58|62|64| |00|24|34|41>69|67|78|58|62|64| |00|24|34|41|58>67|78|69|62|64| |00|24|34|41|58|62>78|69|67|64| |00|24|34|41|58|62|64>69|67|78| |00|24|34|41|58|62|64|67>69|78| |00|24|34|41|58|62|64|67|69>78| |00|24|34|41|58|62|64|67|69|78| n = A.size(); for ( i = 0 ; i < n - 1 ; i++ ) { k = i; for ( j = i + 1 ; j < n ; j++ ) if ( A[j] < A[k] ) k = j; x = A[i]; A[i] = A[k]; A[k] = x; } 4 n = A.size(); for ( i = 0 ; i < n - 1 ; i++ ) { k = i; for ( j = i + 1 ; j < n ; j++ ) if ( A[j] < A[k] ) k = j; if ( k != i ) { x = A[i]; A[i] = A[k]; A[k] = x; } } Sortowanie przez zamianę Sortowanie bąbelkowe boublesort Porównujemy jedynie sąsiednie elementy tak długo, aż posortujemy Algorytm stabilny In situ Złożoność O(n2) ASD 02 14 Sortowanie przez zamianę 1) |41|67|34|00|69|24|78|58|62|64| 2) |41>34|67|00|69|24|78|58|62|64| 3) |41|34>00|67|69|24|78|58|62|64| 4) |41|34|00|67>24|69|78|58|62|64| 5) |41|34|00|67|24|69>58|78|62|64| 6) |41|34|00|67|24|69|58>62|78|64| 7) |41|34|00|67|24|69|58|62>64|78| 8) >34|41|00|67|24|69|58|62|64|78| 9) |34>00|41|67|24|69|58|62|64|78| 10)|34|00|41>24|67|69|58|62|64|78| 11)|34|00|41|24|67>58|69|62|64|78| 12)|34|00|41|24|67|58>62|69|64|78| 13)|34|00|41|24|67|58|62>64|69|78| 14)>00|34|41|24|67|58|62|64|69|78| 15)|00|34>24|41|67|58|62|64|69|78| 16)|00|34|24|41>58|67|62|64|69|78| 17)|00|34|24|41|58>62|67|64|69|78| 18)|00|34|24|41|58|62>64|67|69|78| 19)|00>24|34|41|58|62|64|67|69|78| 5 n = A.size(); for ( i = 0 ; i < n ; i++ ) for ( j = n-1 ; j > 0 ; j-- ) if ( A[j-1] > A[j] ) { x = A[j-1]; A[j-1] = A[j]; A[j] = x; } Sortowanie przez zamianę ulepszenia Zapamiętanie, czy dokonano zmiany Zapamiętanie ostatniej pozycji zamiany Zamiana kierunku przejść (sortowanie mieszane) asymetria ciężkiego i lekkiego końca: korzyści tylko w przypadku prawie posortowanych ciągów elementów Generalnie nie stosujemy!!! ASD 02 17 Sortowania proste Porównują (zamieniają) elementy stojące koło siebie Najgorszy przypadek to O(n2) Jak to poprawić: # Trzeba zastosować porównywanie (przestawianie) elementów znajdujących się daleko od siebie ASD 02 18 6 Shell sort Poprawa sortowania przez wstawianie # grupuje się i sortuje elementy oddalone co jakąś wartość – odstęp (gap) # sortujemy przez wstawianie # zmieniamy wartość gap # powtarzamy aż gap będzie równy 1 Złożoność O(n2) In situ Metoda niestabilna Donald Shell, 1959 ASD 02 19 Shell sort 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) |41|67|34|00|69| |24|78|58|62|64| |24|67|34|00|69| |41|78|58|62|64| |24|67|34|00|69| |41|78|58|62|64| |24|67|34|00|69| |41|78|58|62|64| |24|67|34|00|64| |41|78|58|62|69| |00|24|67|34|64|41|78|58|62|69| |00|24|34|64|67|41|78|58|62|69| |00|24|34|41|64|67|78|58|62|69| |00|24|34|41|58|64|67|78|62|69| |00|24|34|41|58|62|64|67|78|69| |00|24|34|41|58|62|64|67|69|78| Shell sort 1) 2) 3) 4) 5) 6) 7) 8) |41|67| |34|00|69| |24|78| |24|67| |34|00|69| |41|78| |24|00| |34|62|69| |41|67| |24|00| |34|62|64| |41|67| |00|24|34|62|64|41|67|58|78|69| |00|24|34|41|62|64|67|58|78|69| |00|24|34|41|58|62|64|67|78|69| |00|24|34|41|58|62|64|67|69|78| |58|62|64| |58|62|64| |58|78|64| |58|78|69| 7 void shellSort() { static const int gaps[] = { 1, 4, 10, 23, 57, 132, 301, 701 }; int k; for ( k = gaps.Size() - 1; k >= 0; k-- ) shellSortPhase( gaps[k] ); } shellSortPhase( int gap ) { int i, j; int x; for ( i = gap; i < A.size() ; i++ ) { x = A[i]; for ( j = i – gap ; j >= 0 && A[j] > x ; j -= gap) { a[j + gap] = a[j]; } a[j + gap] = x; } Shell sort Dobór stałych h # 1, 4, 13, 40, 121 hk+1 = 3hk+1; h1=1 # 1, 3, 7, 15, 31 hk+1 = 2hk+1; h1=1 Doświadczalne wyniki pomiędzy O(n1.25) a O(n1.5) – zależne od stałych h ASD 02 24 8 Comb sort Sortowanie grzebieniowe # przestawiamy nie o 1 tak jak w bąbelkowym ale o większą odległość # odległość jest wyznaczona empirycznie # ostatni krok to odległość 1 Ulepszone sortowanie przez zamianę Złożoność O(n log(n)) In situ Metoda niestabilna ASD 02 25 int gap, swapped, n,t; n = gap = A.size(); swapped = 1; while( gap > 1 || swapped ) { swapped = 0; gap = newgap(gap); for ( i = 0 ; i < n – gap ; i++ ) { if ( A[i] > A[i+gap] ) { t=A[i]; A[i]=A[i+gap]; A[i+gap]=t; swapped = 1; } } } int newgap(int gap) { gap = gap * 10 / 13; if ( gap == 9 || gap == 10 ) gap = 11; return gap?gap:1; } 9 Comb sort Wybór czynnika 1.3 (1.247330950103979) 1/(1-1/exp((sqrt(5)+1)/2)) # 9, 6, 4, 3, 2, 1 # 10, 7, 5, 3, 2, 1 # 11, 8, 6, 4, 3, 2, 1 Wcześniejsze umieszczenie w tablicy wartości gap ASD 02 28 Merge Sort Sortowanie przez scalanie # podziel na 2 części # zastosuj metodę dla każdej z części # wyniki scal Złożonośc O(n log(n)) Metoda ekstensywna, stabilna Dziel i zwyciężaj (rekurencja) ASD 02 29 Merge Sort |41|67|34|00|69|24|78|58|62|64| |41|67|34|00|69| |41|67| |34|00|69| |00|69| |00|34|69| |00|34|41|67|69| |24|78|58|62|64| |24|78| |58|62|64| |62|64| |58|62|64| |24|58|62|64|78| |00|24|34|41|58|62|64|67|79|78| 10 void mergesort( int p, int r ) { int q; if ( p < r ) { q = (p + r)/2; mergesort( p, q ); mergesort( q + 1, r ); merge( p, q, r ); } } void merge(int p, int q, int r) { int i,j,k; int n1 = q - p + 1; int n2 = r - q; int * L = new int[n1+1]; int * R = new int[n2+1]; for ( i = 0 ; i < n1 ; i++ ) L[i] = A[p+i]; for ( j = 0 ; j < n2 ; j++ ) R[j] = A[q+j+1]; L[n1] = L[n1-1] + R[n2-1]; R[n2] = L[n1-1] + R[n2-1]; i = 0; j = 0; for ( k = p ; k <= r ; k++ ) if ( L[i] <= R[j] ) A[k] = L[i++]; else A[k] = R[j++]; delete L; delete R; } Merge Sort cn cn cn/2 cn/2 cn/4 cn/4 cn cn/4 cn/4 cn lg n c c … … … … … … … … c c … ... c cn c cn n ASD 02 33 11 Merge Sort wersja podstawowa (iteracyjna): # podziel tablicę na odcinki 1-elementowe # scalaj 1 z 2, 3 z 4 itd. przepisując do drugiej tablicy # dwuelementowe odcinki scalaj w 4-elementowe, przepisując z powrotem do 1-szej tablicy # aż do odcinka posortowanego o długości tablicy wersja naturalna: # zaczyna się od serii naturalnych # kłopot z wyznaczeniem granic serii # jest atrakcyjna, gdy tablica jest częściowo posortowana ASD 02 34 Merge Sort wersja w miejscu: # podziel tablicę na dwa odcinki # wykonaj sortowanie jednej części metodą MergeSort’ (bez scalania) # scal korzystając z drugiego nieposortowanego odcinka # wywołaj rekurencyjnie dla drugiego odcinka aż długość odcinka będzie równa 1 # wstaw pozostały element we właściwe miejsce ASD 02 35 Heap Sort Wykorzystanie kopca (struktury danych) ang. sterta – zwyczajowo kopiec Drzewo binarne # pełne na wszystkich poziomach za wyjątkiem ostatniego # ostatni poziom wypełniony od strony lewej Kopiec implementujemy przy pomocy tablicy ASD 02 36 12 Heap 1 18 2 3 14 12 4 5 6 7 13 10 11 5 8 9 10 4 1 9 1 2 3 4 5 6 7 8 9 10 18 14 12 13 10 11 5 4 1 9 ASD 02 37 Heap Właściwości # parent(i) = i/2 # left(i) = 2*i # right(i) = 2*i+1 # A[parent(i)) ≥ A[i] Implementacja # przywracanie właściwości kopca (dane: element, dwa podwieszone poddrzewa, które są kopcami) # budowanie kopca ASD 02 38 void heap(int i, int max) { int l = 2 * i + 1; int r = 2 * i + 2; int maxi,t; if ( l < max && A[l] > A[i] ) maxi = l; else maxi = i; if ( r < max && A[r] > A[maxi] ) maxi = r; if ( maxi != i ) { t = A[i]; A[i] = A[maxi]; A[maxi] = t; heap( maxi, max ); } } 13 void heap_build() { int n = A.size(); int i; for ( i = n/2-1 ; i >= 0 ; i-- ) heap( i, n ); } Heap sort # budujemy kopiec # element z wierzchołka kopca (największy) przenosimy na koniec # budujemy kopiec na tablicy zmniejszonej o 1 Złożoność O(n log(n)) Metoda niestabilna Metoda intensywna ASD 02 41 void sort_heap() { int i,n,x; n = A.size(); heap_build(); for ( i = n-1 ; i > 0 ; i-- ) { x = A[0]; A[0] = A[i]; A[i] = x; heap(0,i); } } 14 Pytania? KONIEC ASD 02 43 Na zajęcia Zaimplementować wszystkie omawiane algorytmy Zaimplementować wszystkie warianty Przeprowadzić testy porównawcze zaimplementowanych algorytmów (w domu) ASD 02 44 15