Post on 02-Oct-2015
Algorytmy i struktury
danych sortowanie - pojcia wstpne,
podstawowe alg. sortowania tablic,
zaawansowane alg. sortowania tablic,
kolejki priorytetowe oparte o kopiec
sortowanie w czasie liniowym,
statystyki pozycyjne
Sortowanie
Uporzdkowanie elementw
Klucz fragment danych, dla ktrego jest okrelona
relacja uporzdkowania
Zoono problemu najlepszy znany algorytm
Sortowanie tablic czy plikw
Zachowanie uporzadkowania czciowego
Mediana
Statystyka pozycyjna
Indeksy
Bezporednie sortowanie elementw
Sortowanie indeksu
1 7 2 4 8 11 9 5
1 7 2 4 8 11 7 2
bezporednie
0 2 3 7 1 4 6 5
index
Klasyczne algorytmy dla tablic
sortowanie przez wstawianie (Insertion Sort)
w kolejnym kroku nastpny element z czci nie posortowanej
wstawiany jest na odpowiedni pozycj czci posortowanej
sortowanie przez wybieranie (Selection Sort)
w kolejnym kroku najwikszy (najmniejszy) element z czci
nie posortowanej wstawiany jest na koniec czci posortowanej
sortowanie przez zamian (Exchange, Bubble Sort)
zamiana elementw miejscami a do skutku
N. Wirth Algorytmy+Struktury danych = programy
Sortowanie bbelkowe
1 7 2 4 8 11 7 2
2 7
I II 4
7
7 11 2 11
III IV
for j in range(0,n):
for i in range(0,n-1):
if(A[i] > A[i+1]):
A[i],A[i+1] = A[i+1],A[i]
Sortowanie bbelkowe
1 7 2 4 8 11 7 2
2 7 4 7
7 11 2 11
I II
1 7 2 4 8 11 7 2
2 7 4 7
7 11 2 11
7 8 2 8
for j in range(0,n):
for i in range(0,n-1):
if(A[i] > A[i+1]):
A[i],A[i+1] = A[i+1],A[i]
Sortowanie bbelkowe
//wariant podstawowy for j in range(0,n):
for i in range(0,n-1):
if(A[i] > A[i+1]):
A[i],A[i+1] = A[i+1],A[i]
//wariant ulepszony wewntrzna ptla nie przeglda
//uporzdkowanych elementw for j in range(n-1,-1,-1):
for i in range(0,j):
if(A[i] > A[i+1]):
A[i],A[i+1] = A[i+1],A[i]
Sortowanie bbelkowe
//wariant ulepszony - detekcja koniecznoci powtrze for j in range(n-1,-1,-1):
change = false
for i in range(0,j):
if(A[i] > A[i+1]):
A[i],A[i+1] = A[i+1],A[i]
change = true
if not change: break
Sortowanie bbelkowe
Waciwoci:
alg. prosty w implementacji
zoono O(n2)
zwizy kod - mae stae proporcjonalnoci
zachowuje uporzdkowania czciowe
Stosunkowo najgorsze zachowanie spord prostych
metod
Sortowanie przez proste
wstawianie
zachowuje uporzdkowania czciowe
pesymistyczna zoono O(N2)
mniej zapisw ni przy sortowaniu przez zamian parami
1 7 2 8 11 4 7 2
2 7
X = 1 X = 7 X = 2 for i in range (1, n)
x = A[i]
p = znajdz_miejsce_na(x)
A[p] = x
Sortowanie przez proste
wstawianie
1 2 7 8 11 4 7 2
4 7 8
11
X = 2 X = 8 X = 11 X = 4
zachowuje uporzdkowania czciowe
pesymistyczna zoono O(N2)
mniej zapisw ni przy sortowaniu przez zamian parami
for i in range (1, n)
x = A[i]
p = znajdz_miejsce_na(x)
A[p] = x
Sortowanie przez proste
wstawianie
def ProsteWstawianie(A, n):
for i in range (1, n):
x = A[i]
for j in range (i-1, -1, -1):
if x>=A[j] : break
A[j+1] = A[j]
A[j+1] = x
Sortowanie Shella Zaawansowane sortownie przez wstawianie elementw
1. Wybieramy k = kp
2. Sortujemy przez wstawianie proste podciagi caej tablicy (co
k-ty element)
3. zmniejszamy k tak dugo a osignie 1
o zoonoci alg. decyduje kp i sposb zmiany k
kp = 1 oznacza zwyke sortowanie
dla ki = 2i - 1 (....., 31, 15, 7, 3, 1 )
algorytm ma zoono O(N1.2)
dla ki = 2r3q (r,q N) (......, 20, 16, 10, 9, 8, 6, 4, 3, 2, 1)
algorytm ma zoono O(N log2N)
algorytm zachowuje uporzdkowanie czciowe
Sortowanie Shella
1 2 7 8 11 4 7 2
4
zachowuje uporzdkowanie czciowe
pesymistyczna zoono O(N1.2)
for k in [ ..., 31, 15, 7, 3, 1] :
sortuj_przez_wstawianie_k_podtablic(A)
#A[0],A[k],A[2k] ...
#A[1],A[k+1],A[2k+1] ...
#...
#A[k-1],A[2k-1],A[3k-1] ...
k=7
Sortowanie Shella
1 2 7 8 11 4 7 2
4
zachowuje uporzdkowanie czciowe
pesymistyczna zoono O(N1.2)
for k in [ ..., 31, 15, 7, 3, 1] :
sortuj_przez_wstawianie_k_podtablic(A)
#A[0],A[k],A[2k] ...
#A[1],A[k+1],A[2k+1] ...
#...
#A[k-1],A[2k-1],A[3k-1] ... 1 2 4 8 11 4 7 2 11
2
k=7 k=3
8
7
Sortowanie Shella def ShellSort (A, N):
k = 2lg N - 1
while k >= 1:
for i in range(k,N):
x = A[i]
j = i-k
while j >= 0 and x < A[j]:
A[j+k] = A[j]
j -= k
A[j+k] = x
k = (k+1)/2 1
Sortowanie szybkie
Zaawansowane sortowanie przez zamian elementw
1. Podziel tablic A[p..r] na dwie A1[p..q] i A2[q+1..r],
takie, e kady element nalecy do A1 jest mniejszy
ni dowolny element A2
2. Posortuj A1 i A2
Quicksort - implementacja def QuickSort(A, l, r):
if (l < r) :
q = Partition(A, l, r)
QuickSort (A, l, q)
QuickSort (A, q+1, r)
QuickSort(Tablica, 0, MAX-1)
Partition
1. Wybieramy element x (granic podziau)
2. Idc od poczatku oprzedziau szukamy pierwszego
elementu wikszego lub rwnego ni x.
3. Idc od gry przedziau szukamy ostatniego
elementu mniejszego lub rwnego ni x
4. Zamieniamy znalezione elementy.
5. Koczymy gdy poszukiwania dotr to tego samego
elementu
6. Warunki brzegowe:
co bdzie gdy wybierzemy min/max w przedziale?
Partition - implementacja def Partition(A, l, r):
x = A[l]
i = l-1
j = r+1
while true:
while true:
j = j-1
if A[j] = x : break
if i
Randomized partition
Zapobiega umylnemu wygenerowaniu
najgorszego przypadku danych (ale dalej
moliwe jest wystpienie takiego przypadku)
def RandomPartition(A, l, r):
i = Random(l, r)
A[i],A[l] = A[l],A[i]
return Partition(A, l, q)
Qicksort - waciwoci redni czas O(N log N)
pesymistyczny czas O(N2)
prosty algorytm niewielki narzut
najgorszy przypadek:
Partition za kadym razem tworzy obszary
o rozmiarach N-1 i 1
Randomized Partition brak moliwoci podania
najgorszego przypadku
Aby zmniejszy ew. zajto stosu (w najgorszym przypadku
~N) mona wybiera do sortowania najpierw mniejszy
a potem wikszy z przedziaw (co najwyej log N)
Zachowanie uporzdkowania czciowego zaley od
implementacji funkcji Partition
Kopiec
Kady element jest nie mniejszy (wikszy) ni jego
dzieci
15
9 13
8 7 10 1
2 4 3
15 9 13 8 7 10 1 2 4 3
def Parent(i): return i/2
def Left(i): return i*2
def Right(i): return i*2+1
UWAGA index = 1..size
A[Parent(i)] >= A[i]
1
2 3
4 5 6 7
8 9 10
Przywracanie wasnoci kopca
Z: waciwo kopca moe nie by speniona tylko dla
korzenia
1) rozpocznij od korzenia (W=Root)
2) if jest speniona waciwo kopca dla W i synw:
koniec
else
zamie W z wikszym z synw W
powtrz 2) dla nowego W
Przywracanie w. kopca
15
5 14
10 4 9 3
2 8 1
15
10 14
5 4 9 3
2 8 1
15
10 14
8 7 9 3
2 5 1
1
2 3
4 5 6 7
8 9 10
1
2 3
4 5 6 7
8 9 10
1
2 3
4 5 6 7
8 9 10
Przywracanie wasnoci kopca def Heapify(A, i, size):
L = Left(i)
R = Right(i)
if LA[i-1]:
maxps = L
else:
maxps = i
if RA[maxps-1]:
maxps = R
if maxps != i:
A[i-1],A[maxps-1] = [maxps-1],A[i-1]
Heapify(A, maxps, size)
Sortowanie kopcowe
Tworzenie kopca z caej tablicy
Przywracamy wasno kopca dla coraz wikszych kopcw
Dla kolejnych (coraz mniejszych) kopcw Wybr najwikszego elementu (korze kopca),
Zamiana z ostatnim,
Zmniejszenie rozmiarw kopca,
Przywrcenie wasnoci kopca.
Budowa kopca 5 1 3 2 11 7 4 10 5 7
5
1 3
2 11 7 4
10 6 7
1
2 3
4 5 6 7
8 9 10
5
1 3
10 11 7 4
2 6 7
1
2 3
4 5 6 7
8 9 10
5
1 7
10 11 3 4
2 6 7
1
2 3
4 5 6 7
8 9 10
5
11 7
10 7 3 4
2 6 1
1
2 3
4 5 6 7
8 9 10
11
10 7
6 7 3 4
2 5 1
1
2 3
4 5 6 7
8 9 10
11 10 7 6 7 3 4 2 5 1
Sortowanie kopca 11 10 7 8 7 9 3 2 4 1 8 7 7 4 1 9 9 2 10 11
11
10 7
8 7 9 9
2 4 1
1
2 3
4 5 6 7
8 9 10
1
10 7
8 7 9 9
2 4 11
1
2 3
4 5 6 7
8 9
10
8 7
4 7 9 9
2 1 11
1
2 3
4 5 6 7
8 9
1
8 7
4 7 9 9
2 10 11
1
2 3
4 5 6 7
8
8
7 7
4 1 9 9
2 10 11
1
2 3
4 5 6 7
8
Sortowanie kopcowe def BuildHeap(A, size):
for i in range(size/2,0,-1):
Heapify(A, i, size)
def HeapSort(A, size):
BuildHeap(A, size)
for i in range(size-1,1,-1) :
A[i], A[0] = A[0], A[i]
Heapify(A, 1, i)
Sortowanie przez scalanie
nie jest wymagany dostp do wszystkich elementw
np. dla plikw, list
podzia cigu A -> B,C
scalenie B+C -> cig par
cig par - > B,C
scalenie B+C -> cig czwrek
cig czwrek - > B,C
scalenie B+C -> cig semek
.
Sortowanie przez scalanie we: 40, 60, 10, 45, 90, 20, 09, 72
podzia: (40) (60) (10) (45)
(90) (20) (09) (72)
scalanie: (40 90) (20 60) (09 10) (45 72)
podzia: (40 90) (20 60) (09 10) (45 72)
scalanie: (09 10 40 90) (20 45 60 72)
podzia : (09 10 40 90) (20 45 60 72)
scalanie: (09 10 20 40 45 60 72 90)
Kolejka priorytetowa
Przykad: zadania do wykonania, zamwienia
Wymagane operacje:
Dodaj element o priorytecie X
Pobierz element o najwyszym priorytecie
Przeczytaj element o najwyszym priorytecie (bez
usuwania)
Przy realizacji kolejki priorytetowej przy pomocy kopca
Zapis: dodawanie elementw do kopca
Odczyt: zwr A[0] i przebuduj kopiec
Dodawanie do kopca 1) dodaj nowy element w na koniec kopca
2) if jest speniona waciwo kopca dla W\
i ojca W:
koniec
else:
zamie W z ojcem W
powtrz 2) dla W i nowego ojca W
Dodawanie do kopca
13
10 7
6 7 3 4
2 5 1
1
2 3
4 5 6 7
8 9 10
11
13 10 7 6 7 3 4 2 5 1 11
7 13 11 7 6 10 3 4 2 5 1
13
11 7
6 10 3 4
2 5 1
1
2 3
4 5 6 7
8 9 10
7
Usunicie maksimum/minimum
Spostrzeenie: Maximum (Minimum) jest korze kopca
1) Usuwamy korze
2) Na miejsce korzenia wstawiamy ostatni
element kopca
3) Wykonujemy Heapify(Root)
Kolejka priorytetowa - realizacja def HeapInsert(A, size, newElement):
if size>=MAXSIZE:
ERROR przepelnienie kopca
else:
size=size+1
i = size
while i>1 and A[Parent(i)-1]
Kolejka priorytetowa - realizacja def HeapGetMax(A, size):
if size
Sortowanie liniowe?
Niekiedy dodatkowe informacje o kluczach
lub charakterze elementw umoliwiaj
sortowanie w czasie liniowym
Sortowanie przez zliczanie Czas liniowy
Zaoenie: wszystkie elementy s liczbami
z przedziau 0..maxN
maxN jest akceptowalnie due (tablica mieci si
w pamici komputera)
1) zlicz (w tablicy A) wystpienia poszczeglnych\
elementw
2) przygotuj tablice B z pocztkami sekwencji
B[] = 0
B[i] = B[i-1] + A[i-1]
3) przepisz elementy do nowej tablicy C na pozycj
C[B[element.klucz]++] = element
Sortowanie przez zliczanie def CountingSort(A, B, maxN, size):
for i in range(0, maxN+1):
C[i] = 0
for i in range(0, size):
C[A[i]] = C[A[i]]+1
# C[i] zawiera liczb elementw rwnych i
for i in range(1, maxN+1):
C[i] = C[i] + C[i-1]
# C[i] zawiera liczb elementw
Sortowanie przez zliczanie We I A[i] B[i] Wy
A3 0 0 0 E1
B2 1 2 0+1+1 I1
C3 2 2 2+1+1 B2
D5 3 2 4+1+1 F2
E1 4 2 6+1+1 A3
F2 5 1 8+1 C3
G4 6 0 9 G4
H4 7 0 9 H4
I1 8 0 9 D5
Sortowanie kubekowe Czas liniowy
Zaoenie: wszystkie klucze s liczbami (rzeczywistymi) z
przedziau x0 .. x1
Rwnomierny rozkad wartoci kluczy w przedziale
1) podziel dziedzin kluczy na n rwnych przedziaw
dugoci p = (x1 - x0) / n,
gdzie i-ty przedzia < x0+(i-1)*p , x0+i*p),
dla i = 1..n, a ostatni (pierwszy) przedzia jest
obustronnie domknity
2) przepisz n elementw do n list (kubekw), tak
aby elementy na i-tej miay klucze z nalece do
i-tego przedziau
3) Posortuj elementy w kubekach (dowolnym alg.)
4) Wypisz zawarto poszczeglnych kubekw od i = 1
do n
Wyszukiwanie maksimum def Minimum(A, size):
m = A[0]
for i in range(1,size):
if (m>A[i]): m=A[i]
return m
Wyszukiwanie min i maks def MinMax(A, size):
mi = A[0]
ma = A[0]
for i in range(2,size+2,2) :
if A[i]
Zwracanie kilku wartoci C/C++ struct MM {
ELEMENT min, max;
MM(ELEMENT emin, ELEMENT emax) {// konstruktor
Min = emin;
Max = emax;
}
};
MM Minmax(ELEMENT A[], INDEX size)
{
.....
return MM(min, max);
//bez konstruktora trzeba uy zmiennej
//chwilowej
}
Wyszukiwanie i-tej statystyki
Oczekiwany czas dziaania = O(n)
Pesymistyczny czas dziaania = O(n2)
def RandomizedSelect(A, i, l, r):
if l == r: return A[p]
q = RandomizedPartition(A, l, r)
k = ql+1
if i
Wyszukiwanie i-tej statystyki Pesymistyczny czas dziaania = O(n)
INDEX PartitionX(ELEMENT A[], INDEX p, INDEX r,
ELEMENT e)
ELEMENT Select(ELEMENT A[], INDEX p, INDEX r)
1. Podziel elementy p do q na n/5 grup po 5 elementw O(n)
2. Wyznacz median kadej z n/5 grup, sortujc je (czas stay). Jeli (ostatnia) ma parzyst liczb elementw wybierz wiksz z median
O(n)
3. Wywoaj rekurencyjnie x = Select(...) na zbiorze median
wyznaczonym w kroku 2 - b.d.
4. Podziel tablic A wzgldem mediany median tj. x i zmodyfikowanej
PartitionX. Niech wynik bdzie k - O(n)
5. Wywoaj rekurencyjnie Select(A, p, k) jeeli i
Wyszukiwanie i-tej statystyki
x
Uwagi:
Co najmniej poowa median jest wiksza rwna x
Co najmniej n/5 grup zawiera 3 elementy wiksze rwne x,
przy czym jedna z nich zawiera x, a druga moe by niepena
Std liczba elementw wiksza (mniejsza) od x wynosi co
najmniej 3 (1/2 n/5 - 2) 3n/10 - 6