• Nie Znaleziono Wyników

ALGORYTMY I STRUKTURY DANYCH

N/A
N/A
Protected

Academic year: 2021

Share "ALGORYTMY I STRUKTURY DANYCH"

Copied!
18
0
0

Pełen tekst

(1)

ALGORYTMY I STRUKTURY DANYCH

WYKŁAD 05 Problem Sortowania Grażyna Mirkowska

PJWSTK, semestr zimowy 2002

(2)

Plan wykładu

Sformułowanie problemu

Sortowanie przez porównywanie elementów

Sortowanie przez wstawianie Sortowanie przez selekcję

Operacja scalania ciągów uporządkowanych Sortowanie przez scalanie

(3)

Sformułowanie problemu

Dany jest ciąg e elementów e

1

,e

2

,... , e

n

należących do pewnej liniowo uporządkowanej przestrzeni <E, >.

Znaleźć taką permutację i

1

, i

2

,... ,i

n

liczb 1,..., n aby e

i1

e

i2

... e

in

Znaleźć taką funkcję różnowartościową i „na”

f : {1,2...,n}  {e

1

,e

2

,... , e

n

}, że dla każdego i<n, f(i)  f(i+1).

5 3 1 6 7 2 8

3 6 2 1 4 5 7

1 2 3 5 6 7 8

1 2 3 4 5 6 7

(4)

Sortowanie przez selekcję

Metoda Sortowanie odbywa się w n-1 przebiegach. W i-tym przebiegu szukamy i-tego najmniejszego elementu.

Algorytm

{ for i := 1 to n-1 do min := i; j := i+1;

while j < n+1 do

if e[j] < e[min] then min := j fi od;

swap(e[i],e[min]);

od }

Odcinek uporządkowany

(5)

Diagram przepływu

i := 1 i < n

Znajdź x takie, że

x = minimum( e[i],..., e[n])

Zamień

miejscami x i e[i]

i := i+1

tak

nie

e[1] ...  e[i-1]  {e[i],...,e[n]}

x  {e[i],...,e[n]}

e[1] ...  e[i-1]  e[i]  {e[i+1],...,e[n]}

e[1] ...  e[i-1]  {e[i],...,e[n]}

(6)

Koszt algorytmu

Twierdzenie Algorytm Selection_sort jest poprawnym

rozwiązaniem problemu sortowania. W dowolnej strukturze danych, której elementy są liniowo uporządkowane przez relację  , algorytm zatrzymuje się dla dowolnych danych i daje w wyniku ciąg uporządkowany niemalejąco.

A. Jeśli operacją dominującą jest porównywanie elementów:

T(n) = n-1 + n-2 + ... +2 + 1 = n(n-1)/2 = (n

2

)

B. Jeśli operacją dominującą jest zamiana elementów

T(n) = 1*(n-1) = n-1 = (n)

(7)

Sortowanie przez wstawianie

Sortowanie odbywa się w n -1 przebiegach. W i-tym przebiegu elementy na pozycjach 1...(i-1) są już uporządkowane, a

wstawiamy i-ty element przepychając go do przodu na właściwe miejsce, tak by stworzył wraz z innymi ciąg uporządkowany długości i.

Odcinek uporządkowany

i-ty element

X

4 8 5 3 9 6 4 5 8 3 9 6

5

4 5 3 8 9 6 4 3 5 8 9 6 3 4 5 8 9 6

3

9

3 4 5 8 9 6 6

itd

4 8

(8)

Schemat algorytmu

i := 2

i < n+1

Umieść e[i] wśród elementów e[1],e[2],...e[i-1],

przesuwając elementy większe o jedno miejsce w prawo, tak by ciąg i-pierwszych elementów był uporządkowany

start

Tak

Nie

i := i+1

stop

e[1]...  e[i-1] , i < n+2

e[ 1]...  e[i-1] , i<n +1

e[ 1]...  e[i-1]  e[i] , i<n +1 e[ 1]... e[i-2] e[i-1],

i<n +2

(9)

Algorytm Insertion_sort

{for i := 2 to n do

j := i; pom := e[i];

while ( j>1 andif e[j-1]> pom ) do

e[j] := e[j-1];

j := j-1 od;

e[j] := pom od}

e[ 1]...  e[i-1]

e[ 1]...  e[j-1] pom=e[i], j=i

pom< e[ j+1]...  e[i], pom <e[j-1]

Pom < e[ j]e[j+1]...  e[i]

pom< e[ j+1]...  e[i]

e[ 1]  ...  e[j-1]  pom< e[ j+1]...  e[i]

e[ 1]  ...  e[j-1]  e[j] < e[ j+1]...  e[i]

(10)

Poprawność sortowania przez wstawianie

Algorytm sortowania przez wstawianie poprawnie rozwiązuje problem sortowania w każdej liniowo uporządkowanej strukturze danych.

Algorytm sortowania przez wstawianie jest, w każdej liniowo uporządkowanej strukturze

danych, całkowicie poprawny ze względu na

warunek początkowy n>0 i warunek końcowy

(1<i n) e[i-1]  e[i] .

(11)

Koszt sortowania przez wstawianie

W(n) = 

i=2...n

(koszt maksymalny pętli wewnętrznej) =

i=2...n

(i-1) = n(n-1)/2 = O(n

2

)

A(n) = 

i=2...n

(koszt średni pętli wewnętrznej)=

Element pom z

prawdopodobieństwem 1/i może zająć dowolną z pozycji

od 1 do i.

Operacja dominująca - porównywanie elementów.

= 

i=2...n

(

j=1...i

j*(1/i)) = 

i=2...n

(1/i)(i (i+1))/2 =

(n+1)(n+2)/4 - 1.5 = (1/4)n

2

+O(n)

(12)

Sortowanie przez scalanie

(1) Dzielimy zadanie posortowania całego ciągu na dwa podzadania: posortowania jego lewej i prawej połowy.

(2) Gdy obie części tworzą już ciągi

uporządkowane, wtedy scalamy je otrzymując

rozwiązanie.

(13)

Przykład

16 5 12 4 10 6 1 13 15 7 1 14 9 3 8 11

16 5 12 4 10 6 1 13 15 7 1 14 9 3 8 11 16 5 12 4 10 6 1 13

16 5 12 4 5 16 4 12 4 5 12 16

10 6 6 10

1 6 10 13 1 13 1 13

1 4 5 6 10 12 13 16

15 7 1 14 9 3 8 11

1 3 7 8 9 11 14 15

1 3 4 5 6 7 8 9 10 11 12 13 14 15 16

(14)

Operacja scalania

Dane są dwa ciągi X i Y, uporządkowane niemalejąco, x1,...xn i y1,...ym. Utworzyć ciąg e=e1,...e n+m złożony z elementów obu ciągów uporządkowany niemalejąco.

Wp = {n>0 m>0, x1... xn i y1... ym }

Wk = { e1...  en+m , (in+m)( j)( ei=xj lub ei =yj)}

1

2 4 5 8 9 1 3 6 7

2 3 4 5 6 7 8 9

(15)

Algorytm scalania

{i:=1; j := 1;

k :=1,

while (i  n and j  m) do if x[i]< y[j] then

e[k] := x[i];

i := i +1 else

e[k] := y[j];

j := j +1 fi;

k := k+1;

od;

if ( j > m) then for i := i to n do

e[k] := x[i]; k := k+1 od

Else

for j := j to m do

e[k] := y[j]; k := k+1 od}

{k= i+j-1, e[1]...  e[k-1] i wszystkie elementy x[1],...,x[i-1] oraz y[1],...,y[j-1]

zostały już umieszczone na pozycjach od 1 do k-1 w ciągu e .}

O(n+m)

(16)

Specyfikacja procedury scal(k,x,l)

Wersja procedury scal (k,x,l) użyta w algorytmie Sortowania przez scalanie ma następującą specyfikację

Wp = {k  x  l  e[k]  e[k+1]  … e[x] 

e[x+1]  e[x+2] … e[l]}

Wk = {e[k] e[k+1]  …e[x] e[x+1] … e[l] }

Twierdzenie (*)

Procedura scal(k, x,l) zastosowana do dowolnego

ciągu e[1],...,e[n] jest całkowicie poprawna ze

względu na podaną wyżej specyfikację.

(17)

Sortowanie przez scalanie

procedure MS(k,l : integer);

begin

if l>k then

x := (k+l) div 2;

MS(k,x);

MS(x+1,l);

scal (k,x,l) fi

end MS;

Jeśli k=l, to jest tylko jeden element w naszym ciągu.

W tym wywołaniu rozważamy lewą „połowę” danego ciągu

Z założenia indukcyjnego : e[k] ...  e[x]

W tym wywołaniu rozważamy prawą „połowę” danego ciągu Z założenia indukcyjnego :e[x+1] ...  e[l]

Na mocy Tw (*) : e[k] ...  e[l]

(18)

Koszt algorytmu Merge_Sort

Załóżmy, że n = 2 p. wtedy T(n) = T(n/2) + T(n/2) + cn T(1) = 0

T(n) = (n lg (n))

Po podstawieniu mamy T(2 0) = 0

T(2 p) = 2 T(2 p-1) +c n T(2 p ) = 2 T(2 p-1) + c2 p = 2(2T(2 p-2) +c 2 p-1) + c2 p =

2 2 T(2p-2 ) + c2 p + c2 p = ...= 2 p T(2 0 ) + cp 2 p =

(

n lg n)

Cytaty

Powiązane dokumenty

Czas dostępu do danych w pamięci zewnętrznej jest zależny od położenia- zaleca się sekwencyjne czytanie i zapis danych, gdyż koszt dostępu niesekwencyjnego

(2.2.4) Wyznacz kolejne serie, po jednej o tym samym numerze z każdego niewyczerpanego pliku wejściowego;. (2.3) Zamień pliki wyjściowe

Zaleca się, aby każdy podprogram posiadał własną planszę (czyli plik o dowolnej nazwie nazwa.lis np.. Plik/Plansza/Nowa i następnie na planszy wywołanej

Zastosuj kod programu genTest.cpp do wygenerowania serii liczb wejsciowych. Za pomoca kodu sortTest.cpp utw´orz wzorcowy output posortowanych serii, kod u˙zywa funkcji

Zastosuj kod programu generatorTest.cpp do wygenerowania serii liczb wejsciowych. Za pomoca kodu wzorcowka.cpp wyprodukuj

Sortowanie w miejscu nie wymaga wykorzystania dodatkowej pamięci zależnej od ilości sortowanych danych, lecz tylko pewną stałą jej ilość.. Sortowanie stabilne zapewnia, iż

Sortowanie takiego pliku kart omawianą metodą polega na tym, że gracz stopniowo dokłada karty do uporządkowanej części kart (początkowo zawierającej jedną kartę)

• Ostatnim krokiem jest zamiana miejscami elementów tablicy: pierwszego i poprzedzającego wskazywany przez zmienną granica – chcemy, aby element osiowy był