background image

Algorytmy i struktury danych

Wykład 4

Rekurencja c.d.

Temat

• Quicksort, czyli ….

• … raz jeszcze o rekurencji… lub

• … kiedy rekurencja bardzo pomaga!

Problem sortowania raz jeszcze…

Specyfikacja

Dane

nci

ą

g S=s

1

,…s

n

Wynik

elementy w porz

ą

dku niemalej

ą

cymi, czyli: 

s

i1

s

i2

s

in

.

Dziel i zwyci

ęŜ

aj

1. Podziel problem na podproblemy tego 

samego (lub podobnego) rozmiaru

2. Rozwi

ąŜ

podproblemy

3. Poł

ą

cz rozwi

ą

zania podproblemów tak, 

aby uzyska

ć

rozwi

ą

zanie problemu 

głównego

background image

Sortowanie przez scalanie jako 

zastosowanie zasady „dziel i rz

ą

d

ź

1. Podziel ci

ą

g wej

ś

ciowy S na dwa 

podci

ą

gi S1, S2 (prawie) tej samej 

długo

ś

ci

2. Posortuj S1 i S2 osobno (rekurencja)

3. Scal posortowane ci

ą

gi S1 i S2

Quicksort jako inny przykład 

zastosowania metody dziel i zwyci

ęŜ

aj

1. Wybierz element s ci

ą

gu wej

ś

ciowego S i 

podziel S na dwa rozł

ą

czne podzbiory:

S1: elementy, które s

ą

s

S2: elementy, które s

ą

s

2. Posortuj S1 i S2 osobno (rekurencja)

3. Zwró

ć

ą

czone ci

ą

gi S1 i S2

Uwaga

Ŝ

ne wyst

ą

pienia elementu s mog

ą

nale

Ŝ

e

ć

do S1 lub S1, ALE 

ka

Ŝ

da kopia nale

Ŝ

y tylko do jednego ze zbiorów S1, S2.

Sortowanie dokładniej…

Specyfikacja 

Input

l, r – liczby naturalnea – tablica 

sortowanych elementów

Output

elementy z a[lr] w porz

ą

dku 

niemalej

ą

cym, czyli

a[l

a[l+1] 

a[r].

Quick sort dokładniej…

Je

ś

li :

1. Wybierz ze zbioru {a[l], a[l+1],…, a[r]} i 

przemie

ść

elementy a[l], a[l+1],…, a[r] tak, aby:

Elementy a[l..s] s

ą

x

Elementy a[s+1…r] s

ą

x

gdzie s jest pewn

ą

liczb

ą

naturaln

ą

tak

ą

Ŝ

l

s

r

2. Posortuj :

a[l...s]

a[s+1…r]

background image

Quick sort jeszcze dokładniej…

qsort

(int a[], int l, int r)

//sortuje a[l…r]

int s;

if (l<r) {

s = partition(a,l,r);

qsort

(a, l,

s);

qsort

(a, s+1, r);

}

}

int partition(int a[], int l, int r):

Wybierz z podtablicy a[l..r]

Poprzemieszczaj elementy tak, aby:

Elementy w a[l..j] s

ą

x

Elementy w a[j+1..r] s

ą

x

Zwró

ć

jako wynik

Partition: idea

1.

Wybierz x

2.

i

lj

r

3.

Dopóki i

<

powtarzaj:

1. Zwiększaj aŜ do spełnienia warunku a[i

x

2. Zmniejszaj aŜ do spełnienia warunku a[j

x

Zamień a[i] z a[j]

4.

Zwróć i

Partition: implementacja

partition(int a[], int l, int r)

int x,y;

x=a[l];

l--;

r++;

do

while (a[--r]>x);

while (a[++l]<x);

if (l<r) {y=a[r]; a[r]=a[l]; a[l]=y;}

else return r;

while (1);

}

Quick sort: zło

Ŝ

ono

ść

pami

ę

ciowa

Pami

ęć

:

Tablica zawieraj

ą

ca ci

ą

g wej

ś

ciowy

Stała liczba dodatkowych zmiennych

Pami

ęć

potrzebna do realizacji 

rekurencji…?

background image

Quick sort: zło

Ŝ

ono

ść

czasowa

Najgorszy przypadek: procedura partition dzieli 
problem na podproblemy o rozmiarach 1 i – 1:

T(1) = 1

T(n) = T(n-1)    +   T(1) + n

dla n 

>

1

Rozwi

ą

zanie: T(n

n

2

/2=O(n

2

)

First recursive call

Second recursive call

Cost of partition

Quicksort: zło

Ŝ

ono

ść

czasowa

„Zamierzona” sytuacja: procedura partition dzieli 
problem rozmiaru n na dwa podproblemy
rozmiaru n/2:

T(1) = 1

T(n) = T(n/2)  +  T(n/2) + n

dla n

>

1

Rozwi

ą

zanie: T(n) = O(log n)

Pierwsze wywoł. rek.

Koszt partition

Drugie wywoł. rek.

Quicksort: zło

Ŝ

ono

ść

czasowa

W praktyce: quicksort jest najszybszym algorytmem 

sortowania.

Pyt.:

Jaki czas preferujesz n

2

czy n log n?

Uwagi

Mo

Ŝ

liwe jest uzyskanie czasu O(n log n) w 

najgorszym przypadku (korzystamy z algorytmu 
liniowego szukaj

ą

cego mediany)

Wiadomo, 

Ŝ

ś

redni czas działania Quicksort

jest O(log n)