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