background image

1

Wykład 4 

Sortowanie 

background image

2

Sortowanie - zadanie

Definicja (dla liczb):

   wejście: ciąg n liczb A = (a

1

a

2

, …, a

n

)

   wyjście: permutacja (a

1

,…, a’

n

) taka, że a’

≤ … ≤ a’

n   

Po co sortować?

– Podstawowy problem dla algorytmiki
– Wiele algorytmów wykorzystuje sortowanie jako procedurę 

pomocniczą

– Pozwala pokazać wiele technik
– Dobrze zbadane (czas)

background image

3

Sortowanie – taksonomia

 Wewnętrzne zewnętrzne

– Zależnie od miejsca przechowywania zbioru: (RAM czy dysk)

 Sortowanie tablic i sortowanie list łączonych

– zależnie od struktury danych (pliku);
– różny sposób dostępu (bezpośredni dla tablicy, sekwencyjny dla listy).

 „W miejscu” lub nie

– Nie wymaga dodatkowej pamięci

 Stabilne i niestabilne

– Kolejność elementów o tych samych wartościach klucza nie zmienia 

się. Inaczej kolejne sortowanie dla złożonych obiektów nie psuje 
efektów poprzedniego sortowania.

 Bezpośrednie i pośrednie

– zależnie od tego przemieszczamy całe obiekty, czy tylko wskaźniki 

(indeksy) do nich

background image

4

Zestawienie czasów działania

 Przez wybór:

O(N

2

) zawsze

 Bąbelkowe:

O(N

2

) najgorszy przypadek; O(N) 

najlepszy przyp.

 Wstawianie:

O(N

2

) średnio; O(N) najlepszy przypadek

 Shellsort: O(N

4/3

)

 Heapsort: O(NlogN) zawsze
 Mergesort: O(NlogN) zawsze
 Quicksort: O(NlogN) średnio; O(N

2

) najgorszy przypadek

 Zliczanie: O(N) zawsze
 Radix sort: O(N) zawsze

 zewnętrzne: 

O(b logb)) dla pliku o b „stronach”.

background image

5

Sortowanie przez wybór – pomysł

 Znajdujemy najmniejszy element ciągu i zamieniamy go 

z pierwszym elementem. Powtarzamy to dla podciągu 
bez pierwszego elementu, itd.

Znajdź minimum i zamień 
z pierwszym elementem

X

X

background image

6

Sortowanie przez wybór – pseudokod

     Selection_Sort(int A) 
1   for ← 1 to length[A]
2   do min ← i; 
3

 for ← i+1 to length[A

4      do if A[j] < A[min] then min ← j; 
5      Exchange A[min] ↔ A[i]

background image

7

ciąg: EASYQUESTION  - rozmiar 12 znaków

       

#porównań       #zamian

EASYQUESTION

     

A

ESYQUESTION

11 

1

AE

SYQUESTION

10 

1

AEE

YQUSSTION

  9 

1

AEEI

QUSSTYON 

  8 

1

AEEIN

USSTYOQ 

  7 

1

AEEINO

SSTYUQ 

  6       

1

AEEINOQ

STYUS 

  5     

1

AEEINOQS

TYUS 

  4     

1

AEEINOQSS

YUT 

  3     

1

AEEINOQSST

UY 

  2   

1

AEEINOQSSTU

  1   

1

Razem

             66                 11

  
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
1
0
1
1

Sortowanie przez wybór – przykład 

iteracj
a

background image

8

Sortowanie przez wybór – czas działania

 Zależność od danych wejściowych:

– Ilość przebiegów: nie (zawsze N-1)
– Ilość porównań: nie
– Ilość zamian: nie 

 O(N

2

) zawsze (bez znaczenia jaki jest układ elementów w 

danych – ważna tylko ilość)

background image

9

Sortowanie bąbelkowe (przez zamianę)

 Przechodzimy przez ciąg od jego końca, porównując sąsiadujące 

elementy i ewentualnie zamieniając je miejscami. Powtarzamy te 
procedurę aż do uporządkowania całego ciągu.

– Po pierwszym przejściu element minimalny znajduje się na początku –  a[0], 

po drugim na drugim miejscu znajduje się drugi co do wielkości – a[1], po itd.

Porównanie do 
wypływających bąbelków – 
stąd nazwa

.

background image

10

Sortowanie bąbelkowe – pseudokod 

    BUBBLE_SORT(A)
1  for ← 1 to length[A]
2  do for ← length[Adownto + 1
3       do if A[j] < A[- 1]
4             then exchange A[j] ↔ A[

1]

background image

11

Ciąg: EASYQUESTION, (12 znaków)

       

porównań

zamian

EASYQUESTION                     

(najgorszy przyp)

A

EESYQUISTNO

11     (11) 8     (11)

AE

EISYQUNSTO

10     (10) 6     (10)

AEE

INSYQUOST

  9       (9) 6       (9)

AEEI

NOSYQUST

  8       (8) 4       (8)

AEEIN

OQSYSUT 

  7       (7) 3       (7)

AEEINO

QSSYTU

  6       (6) 2       (6)

AEEINOQ

SSTYU

  5       (5) 1       (5)

AEEINOQS

STUY

  4       (4) 1       (4)

AEEINOQS

STUY

  3       (3) 

0

       (3)

           (2)          (2) 

(1)

         (1)

                              razem          63      (66)

31   (66)

iteracja

  1
  2
  3
  4
  5
  6
  7
  8
  9

Sortowanie bąbelkowe – przykład

background image

12

Sortowanie bąbelkowe – czas wykonania

 Zależność od danych wejściowych:

– Ilość potrzebnych przejść: tak

– Ilość porównań w jednym przejściu: nie

– Ilość zamian: tak

 Najgorszy przypadek: O(N

2

)

– Dane odwrotnie posortowane, np.: JIHGFEDCBA.

– N-1 przejść

– (N-1)N/2 porównań i  (N-1)N/2 zamian

 Najlepszy przypadek: O(N)

– Jeśli elementy są już posortowane, np.: ABCDEFGHIJ.

– Tylko jedno przejście. Stąd mamy N-1 porównań i 0 zamian.

background image

13

Sortowanie przez wstawianie – pomysł 

 Dla każdego elementu ciągu (od lewej do prawej), 

wstawiamy go we właściwe miejsce ciągu elementów 
poprzedzających go (już posortowanych).

background image

14

Sortowanie przez wstawianie – pseudokod 

INSERTION_SORT(A)
1   for ← 2 to length[A]
2   do key ← A[j]
3         ← j-1
4        while i>0 and A[i]>key
5        do A[i+1] ← A[i]
6            i ← i-1
7           A[i+1] ← key

background image

15

Ciąg: EASYQUESTION, (12 znaków)

       

porównań

zamian

                                                     (najgorszy przyp.)

E

ASYQUESTION

A

E

SYQUESTION

1     (1)

1     (1)

AE

S

YQUESTION

1     (2)

0     (2)

AES

Y

QUESTION

1     (3)

0     (3)

AE

Q

SY

UESTION

3     (4)

2     (4)

AEQS

U

Y

ESTION

2     (5)

1     (5)

AE

E

QSUY

STION

5     (6)

4     (6)

AEEQS

S

UY

TION

3     (7)

2     (7)

AEEQSS

T

UY

ION

3     (8)

2     (8)

AEE

I

QSSTUY

ON

7     (9)

6     (9)

AEEI

O

QSSTUY

N

7   (10)

6   (10)

AEEI

N

OQSSTUY

8   (11)

7   (11)

                   razem

          41   (66)          31   (66)

iteracja

    1
    2
    3
    4
    5
    6
    7
    8
    9
  10
  11

Sortowanie przez wstawianie – przykład

 

background image

16

Sortowanie przez wstawianie – czas 
działania

 Zależność od danych wejściowych:

– Ilość iteracji: nie (zawsze N-1)
– Ilość porównań: tak
– Ilość zamian: tak

 Najgorszy przypadek: O(N

2

)

– Elementy odwrotnie posortowane np.: JIHGFEDCBA.
– (N-1)N/2 porównań i (N-1)N/2 zamian.

 Najlepszy przypadek: O(N)

– Elementy już posortowane np.: ABCDEFGHIJ.
– Jedno porównanie i 0 zamian w każdej iteracji. Razem, N-1 

porównań i brak zamian.

background image

17

Shellsort – pomysł 

 Modyfikacja (rozszerzona wersja) sortowania przez 

wstawianie

 Dążymy do zmniejszenia ilości zamian – albo ciągi 

krótkie, albo lepsze („bliższe” posortowania).

 Shellsort wykonuje sortowanie podciągów:

– Wybieramy ciąg liczb (zwany ciągiem przyrostów) h

t

, …

 

h

2

, h

;

– h

1

=1; h

 > … > h

2

 >h

1

 ;

– Sortujemy ciągi elementów odległych o h

t

, h

t-1

, h

t-2

,…,h

1

.

background image

18

Shellsort – kod w C

void shellsort (int[ ] a, int n) 

 int i, j, k, h, v; 

 int[ ] cols = {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 

1968, 861, 336, 112, 48, 21, 7, 3, 1} 

 for (k=0; k<16; k++) 

                                 {

                                   h=cols[k]; 

                                   for (i=h; i<n; i++) 

                                                            { 

                                                              v=a[i]; 

                                                              j=i; 

                                                              while (j>=h && a[j-h]>v) 

                                                                                                   { 

                                                                                                     a[j]=a[j-

h]; 

                                                                                                     j=j-h; 

                                                                                                   } 

                                                              a[j]=v; 

                                                            } 

                                } 

background image

19

Shellsort – przykład

ciąg: EASYQUESTION  (12 znaków)
ciąg przyrostów 4, 1.

porównań zamian

EASYQUESTION

E

ASY

Q

UES

T

ION

   2

     0

E

A

SY

Q

I

ES

T

U

ON

   3

     1

E

A

E

Y

Q

I

O

S

T

U

S

N

   3

     2

E

A

E

N

Q

I

O

S

T

U

S

Y

   3

     3

Razem w tej fazie

  11

     6

faza 1: przyrost = 4

background image

20

Shellsort – przykład

porównań zamian

EAENQIOSTUSY

AE

ENQIOSTUSY 

   1

     1

AEE

NQIOSTUSY 

   1

     0

AEEN

QIOSTUSY 

   1

     0

AEENQ

IOSTUSY

   1

     0

AEEINQ

OSTUSY

   3

     2

AEEINOQ

STUSY

   2

     1

AEEINOQS

TUSY

   1

     0

AEEINOQST

USY

   1

     0

AEEINOQSTU

SY

   1

     0

AEEINOQSSTU

Y

   3

     2

AEEINOQSSTUY

   1

     0

Razem w tej fazie

  16

     6

faza 2: przyrost= 1

background image

21

Shellsort – przykład

 Razem 27 porównań i 12 zamian.
 Dla sortowania przez wstawiania odpowiednio 41 i 

31 !!! 

– Polepszenie dostajemy przez wstępne posortowanie, 

krótkich podciągów

 Zwykle stosuje się ciągi przyrostów o więcej niż 2 

elementach.

background image

22

Shellsort – czas działania

 Nie ma możliwości przeprowadzenie dokładnej analizy dla 

przypadki ogólnego (wyniki są oparte o badania 
empiryczne).

 Wybór ciągu przyrostów ma zasadniczy wpływ na czas 

sortowania.

– Dla ciągu podanego przez Shell’a: O(N

2

)

• I

max

 = Floor(N/2), I

k

 = Floor(I

k+1

/2). 

• np N=64:1, 2, 4, 8, 16, 32

– Dla ciągu podanego przez Knuth’a: O(N

3/2

)

• I

1

=1, I

k+1

 = 1+3*I

k

• 1, 4, 13, 40, 121, 364, …

background image

23

Mergesort – pomysł

 Dzielimy ciąg na podciągi, sortujemy te podciągi, a 

następnie łączymy zachowując porządek.

– Przykład algorytmu typu „dziel i zwyciężaj”.
– Potrzeba dodatkowego miejsca dla tych podciągów – nie 

jest to sortowanie „w miejscu”.

• Można realizować ten proces „w miejscu”, ale rośnie 

stopień komplikacji.

background image

24

Mergesort – przykład

ciąg: EASYQUESTION  (12 znaków)

EASYQUESTION

EASYQU

ESTION

EAS

YQU

EST

ION

E

AS

Y

QU

E ST I ON

A S

Q U

S T

O N

podział

background image

25

Mergesort – przykład

AEEINOQSSTUY

AEQSUY

EINOST

AES

QUY

EST

INO

E

AS

Y

QU

E

ST

I

NO

A S

Q U

S T

O N

łaczenie

A  E  S

Q  U  Y

C1

C2

C3

background image

26

Mergesort - pseudokod

MERGE-SORT(Apr)

1  if r

then ← ⌊(r)/2⌋

MERGE-SORT(Apq)

MERGE-SORT(A+ 1, r)

MERGE(Apqr)

background image

27

Mergesort - pseudokod

MERGE(Apqr)
1   n1 ← + 1
2   n2 ← q
3   create arrays L[1 ..n1 + 1] and R[1 ..n2 + 

1]

4  for ← 1 to n1
5  do L[i] ← A[- 1]
6   for ← 1 to n2
7  do R[j] ← A[j]
8  L[n1 + 1] ← ∞
9   R[n2 + 1] ← ∞
10  ← 1
11  ← 1
12  for ← to r
13  do if L[i] ≤ R[j]
14 

then A[k] ← L[i]

15 

← + 1

16      else A[k] ← R[j]
17              ← + 1

background image

28

Sortowanie w czasie 

liniowym 

background image

29

Przegląd

 Czy możliwe jest sortowanie w czasie lepszym niż dla 

metod porównujących elementy (poprzednio – najlepsze 
algorytmy dawały czas O(NlogN))?

 Algorytmy o liniowym czasie działania:

– Przez zliczanie (Counting-Sort)
– Radix-Sort
– Kubełkowe (Bucket-sort)

 Potrzeba dodatkowych założeń!

background image

30

Sortowanie o czasie liniowym

 Możliwe przy dodatkowych informacjach (założeniach) o 

danych wejściowych. 

 Przykłady takich założeń: 

– Dane są liczbami całkowitymi z przedziału [0..k] i k = O(n).
– Dane są liczbami wymiernymi z przedziału [0,1) o rozkładzie 

jednostajnym na tym przedziale

 Trzy algorytmy:

– Counting-Sort
– Radix-Sort
– Bucket-Sort

background image

31

Zliczanie (Counting sort)

   

wejście: n liczb całkowitych z przedziału [0..k], dla k = O(n).

   pomysł: dla każdego elementu wejścia x określamy jego 

pozycje (rank): ilość elementów mniejszych od x.

   jeśli znamy  pozycję elementu – umieszczamy go na r+1 

miejscu ciągu

  

 przykład: jeśli wiemy, że w ciągu jest 6 elementów mniejszych 

od 17, to 17 znajdzie się na 7 miejscu w ciągu wynikowym.

  

 powtórzenia: jeśli mamy kilka równych elementów 

umieszczamy je kolejno poczynając od indeksu pozycja

background image

32

Zliczanie (Counting sort)

1

3

2

4 5

Jeśli nie ma powtórzeń i n = k, 
Rank
[A[i]] = A[i] i B[Rank[A[i]] 
 A[i]

Dla każdego A[i], liczymy 

elementy ≤  od niego. Daje to 

rank (pozycję) elementu

4

1

2

5

A =

B =

Rank =

4

3

5

2

1

3

background image

33

Zliczanie (Counting sort)

5

1

2

3

A =

3

2

4

Rank =

Jeśli nie ma powtórzeń i n < 
k

Niektóre komórki tablicy 
rank pozostają 
niewykorzystane, ale 
algorytm działa.

B =

5

2

1

1

3

background image

34

Zliczanie (Counting sort)

4

1

2

2

A =

1

4

3

5

Rank =

Jeśli n > k i mamy 
powtórzenia, 

umieszczamy na wyjściu 
powtarzające się elementy 
w takiej kolejności, w jakiej 
występowały w oryginalnym 
ciągu (stabilność)

B =

3

3 4

2

1

2

2

background image

35

Zliczanie (Counting sort)

Counting-Sort(ABk)
1.

for i  0 to k 

2.

   do C[i]  0

3.

for j  1 to length[A] 

4.

   do C[A[j]]  C[A[j]] +1   

5.

 /* C zawiera ilości elementów równych i

6.

for i  1 to k

7.

   do C[i]  C[i] + C[i –1]

8.

 /* C zawiera ilości elementów ≤  i

9.

for j  length[A] downto 

10.

   do B[C[A[j]]]  A[j]

11.

        C[A[j]]  C[A[j]] – 1

A[1..n] – tablica wejściowa
[1..n] – tablica wyjściowa
[0..k] – pomocnicza tablica (do zliczania) 

background image

36

Sortowanie przez zliczanie – przykład  (1)

n = 8
k = 6

B[C[A[j]]]  A[j]

C[A[j]]  C[A[j]] – 1

po p. 11

C[A[j]]  C[A[j]] +1

po p.4

C =

 0      1      2       3     4      5

 

2

2

0

3 0 1

2

3

5

0 2 3 0 3

A =

 1      2       3     4      5      6      7      8

 

2

4

2

7 7 8

C =

 0      1      2       3     4      5

 

C[i]  C[i] + C[i –1]

po p. 7

2

4

2

7 8

C =

 0      1      2       3     4      5

 

7

 1      2       3     4      5      6      7      8

 

B =

3

6

background image

37

Sortowanie przez zliczanie – przykład  (2)

0

3

B =

2

4

2

6 7 8

C =

 0      1      2       3     4      5

 

 1      2       3     4      5      6      7      8

 

2

3

5

0 2 3 0 3

A =

 1      2       3     4      5      6      7      8

 

2

4

2

6 7 8

C =

 0      1      2       3     4      5

 

1

background image

38

Sortowanie przez zliczanie – przykład  (3)

0

3

B =

1

4

2

6 7 8

C =

 0      1      2       3     4      5

 

 1      2       3     4      5      6      7      8

 

2

3

5

0 2 3 0 3

A =

 1      2       3     4      5      6      7      8

 

2

4

2

6 7 8

C =

 0      1      2       3     4      5

 

3

5

background image

39

Counting sort – czas działania

 Pętla for w p.1-2 zajmuje czas Θ(k)
 Pętla for w p.3-4 zajmuje czas Θ(n)
 Pętla for w p.6-7 zajmuje czas Θ(k)
 Pętla for w p.9-11 zajmuje czas Θ(n)
 Stąd dostajemy łączny czas Θ(n+k)
 Ponieważ O(n), T(n) = Θ(n)       algorytm jest 

optymalny!!

 Konieczne jest założenie O(n). Jeśli k >> n to 

potrzeba to potrzeba dużej ilości pamięci. 

 Nie jest to sortowanie „w miejscu”. 

background image

40

Radix sort – sortowanie pozycyjne

wejście: n liczb całkowitych, d-cyfrowych, łańcuchów o d-

pozycjach

pomysł: zajmować się tylko jedną z cyfr (sortować 

względem kolejnych pozycji – cyfr/znaków). Zaczynamy 
od najmniej znaczącej 
cyfry/znaku, potem kolejne pozycje 
(cyfry/znaki), aż do najbardziej znaczącej
. Musimy 
stosować metodą stabilną. Ponieważ zbiór możliwych 
wartości jest mały (cyfry – 0-9, znaki ‘a’-’z’) możemy 
zastosować metodę zliczania, o czasie O(n)

Po zakończeniu ciąg będzie posortowany!!

background image

41

Radix sort – przykład 

7 2 

0

 3 2 

9
 4 3 

6
 8 3 

9
 3 5 

5
 4 5 

7
 6 5 

7

3 2 

9

 4 5 

7
 6 5 

7
 8 3 

9
 4 3 

6
 7 2 

0
 3 5 

5

7 2 

0

3 5 

5
4 3 

6
4 5 

7
6 5 

7
3 2 

9
8 3 

9

3 2 

9

 3 5 


 4 3 

6
 4 5 

7
 6 5 

7
 7 2 

0
 8 3 

9

background image

42

Radix-Sort – pseudokod 

Radix-Sort(A, d)
1. for i  1 to d 
2.    do  zastosuj stabilną metodę sortowania do cyfry dla 

tablicy A

uwagi: 

złożoność: T(n) = Θ(d(n+k))  Θ(n) dla stałego d i k = O(1)

wartości cyfr/znaków są z zakresu [0..k –1] dla k = O(1)

Metoda stosowana dla poszczególnych pozycji musi być 
stabilna!

background image

43

Sortowanie kubełkowe – Bucket sort

wejście: n liczb rzeczywistych z przedziału [0..1) ważne jest, 

aby były równomiernie rozłożone  (każda wartość równie 
prawdopodobna)

pomysł: dzielimy przedział [0..1) na podprzedziałów 

(„kubełków”):0, 1/n, 2/n. … (n–1)/n. Elementy do 
odpowiednich kubełków, a

i

: 1/i ≤ a

≤ 1/(i+1). Ponieważ 

rozkład jest równomierny to w żadnym z przedziałów nie 
powinno znaleźć się zbyt wiele wartości. Jeśli wkładamy je 
do kubełków zachowując porządek (np. przez wstawianie – 
Insertion-Sort), dostaniemy posortowany ciąg.   

background image

44

Bucket sort – przykład

.78

.17

.39

.26

.72

.94

. 21

.12

.23

.68

7

6

8

9

5

4

3

2

1

0

.17

.12

.26

.23

.21

.39

.68

.78

.72

.94

.68

.72

.78

.94

.39

.26

.23

.21

.17

.12

background image

45

Bucket-Sort

Bucket-Sort(A)
1.

 n  length(A)

2.

 for i  0 to n 

3.

   do wstaw A[i] do listy B[floor(nA[i])]

4.

for i  0 to n –1 

5.

   do Insertion-Sort(B[i])

6.

 Połącz listy B[0], B[1], … B[n –1]

A[i] tablica wejściowa
B
[0], B[1], … B[n –1]  lista „kubełków”

background image

46

Bucket-Sort – złożoność czasowa

 Wszystkie instrukcje z wyjątkiem 5 (Insertion-Sort) wymagają 

czasu O(n), w przypadku pesymistycznym.

 W przypadku pesymistycznym, O(n) liczb trafi do jednego 

„kubełka” czyli ich sortowanie zajmie czas O(n

2

). 

 Jednak w średnim przypadku stała ilość elementów wpada do 

jednego przedziału – stąd czas średni  wyniesie O(n). 


Document Outline