ďťż

ciĄgda~1

Lemur zaprasza

 CIĄG DALSZY ALGORYTMÓW SORTOWANIA

Sortowanie
przez proste wybieranie
Sortowanie
przez prostą zamianę
Sortowanie
mieszane
Sortowanie
przez podział


Sortowanie przez proste wybieranie.Przyjmijmy w procesie
sortowania następującą zasadę:

wybieramy obiekt o najmniejszym kluczu,
wymieniamy go z pierwszym obiektem a1. Operacje te powtarzamy
kolejno z pozostałymi n-l, n-2 obiektami do momentu, gdy pozostanie tylko jeden,
największy obiekt. Algorytm realizujący tę strategię przedstawiony jest poniżej:
 



for i:=1 to n-l do 
begin    " przypisz k indeks
najmniejszego obiektu wsrod a[i]..a[n] "    "
dokonaj zamiany a[i] i a[k] " 
end Ilustruje to poniższy
przykład:  



i=1
^44
55
12
42
94
18
06
67

i=2
06
^55
12
42
94
18
44
67

i=3
06
12
^55
42
94
18
44
67

i=4
06
12
18
^42
94
55
44
67

i=5
06
12
18
42
^94
55
44
67

i=6
06
12
18
42
44
^55
94
67

i=7
06
12
18
42
44
55
^94
67

i=8
06
12
18
42
44
55
67
^94Metoda prostego wybierania jest w pewnym sensie
odwrotna do prostego wstawiania. W metodzie prostego wstawiania w każdym kroku
rozważa się jeden obiekt ciągu źródłowego i wszystkie obiekty tablicy wynikowej;
w metodzie prostego wybierania rozważa się wszystkie elementy tablicy źródłowej,
wybiera ten z najmniejszym kluczem by wstawić go w określone miejsce ciągu
wynikowego. Mamy więc do czynienia ze zmniejszeniem liczby przestawień.
Procedura realizująca ten algorytm przedstawiona jest poniżej:



procedure ProsteWybieranie; 
var    i,j,k  :
Indeks;    x      :
Obiekt;  begin   
for i:=l to n-l do     { petle po
pozycjach, na ktore przestawiamy }   
begin     
k:=i;               
{ startowy indeks najmniejszego wyrazu } 
   
x:=a[i];            
{ startowa wartosoc najmniejszego wyrazu } 
    for j:=i+l to n do  
{ petla przemieszczania sie po tablicy } 
      if a[j].Klucz<x.Klucz
then     { czy znaleziono mniejszy wyraz
}       
begin             
{ jezeli znaleziono to wtedy. . . } 
       
k:=j;            {
indeks aktualnie najmniejszego } 
       
x:=a[j]          { wartosc
aktualnie najmniejszego } 
      end; 
   
a[k]:=a[i];          { wyraz
i-ty na miejsce najmniejszego }     
a[i]:=x             
{ najmniejszy przechodzi na i-ta pozycje }   
end  end;Algorytm
ten jest przeważnie lepszy od prostego wstawiania, chociaż w wypadkach, w
których klucze są choćby częściowo posortowane, wstawianie proste jest ciągle
nieco szybsze.
Nie istnieje jednoznaczna klasyfikacja metod sortowania. Omówione poprzednie
techniki bazują na zamianie, prezentowana poniżej ma podobny punkt wyjścia, tj.
zamianę dwóch obiektów. Dotyczy to jednak obiektów bezpośrednio ze sobą
sąsiadujących. Proces powtarzany jest dopóki nie zostaną posortowane wszystkie
elementy. Nosi on nazwę...
Sortowania przez prostą zamianę (bąbelkowego)Sortowanie
babelkowe  polega na powtarzaniu przejścia przez tablicę i przesuwaniu za
każdym razem najmniejszego z pozostałych obiektów na jej lewy koniec (początek).
Jeżeli  "obrócimy" tablicę o 90° (lewy koniec do góry) możemy podać prostą
i zabawną  interpretację zachodzącego procesu. Najmniejsze (najlżejsze)
elementy będą przesuwać się do góry jak bąbelki w naczyniu z cieczą,
najcięższe  (największe) będą opadać na dno. Procedura realizująca ten
algorytm ma prostą budowę.



procedure SortowanieBabelkowe; 
var     i,j  :
Indeks;    x    : Obiekt; 
begin     for i:=2 to
n
do           
{ kolejne przegladania tablicy }   
begin       for
j: =n downto i do     { przegladamy
tablice od samego dolu }       
if a[j-l].Klucz>a[j].Klucz then     {
czy wyzszy jest wiekszy? } 
     
begin                  
{ jezeli tak, to bedziemy go "spychac" w dol } 
       
x:=a[j-l];           
{ ten wyraz pojdzie oczko do dolu } 
       
a[j-l]:=a[j];         { babelek
idzie do gory o oczko w gore ...  } 
       
a[j]:=x              
{ ten wyraz z kolei "opada" do dolu } 
     
end                    
{ koniec pojedynczego " spychania" i awansu w gore } 
  end  
end;  Ilustracją tego
algorytmu będzie nasz stały przykład wzorcowy obrócony o 90o
 



start



i=2



i=3
i=4
i=5
i=6
i=7
i=8


44
44
44
44
44
44
44
06
06
06
06
06
06
06
06

55
55
55
55
55
55
06
44
12
12
12
12
12
12
12

12
12
12
12
12
06
55
55
44
18
18
18
18
18
18

42
42
42
42
06
12
12
12
55
44
42
42
42
42
42

94
94
94
06
42
42
42
42
18
44
44
44
44
44
44

18
18
06
94
94
94
94
94
42
55
55
55
55
55
55

06
06
18
18
18
18
18
18
94
67
67
67
67
67
67

67
67
67
67
67
67
67
67
67
94
94
94
94
94
94

j=8
j=7
j=6
j=5
j=4
j=3
j=2







Istnieje powiedzenie, rozpowszechnione wśród
informatyków, że każdy,  absolutnie każdy, program można poprawić. Łatwo
spostrzec, że trzy ostatnie  przejścia w analizowanym przykładzie nie mają
żadnego wpływu na kolejność obiektów - są one już po prostu posortowane.

Pierwsze usprawnienie algorytmu przyniesie nam zapamiętanie, czy dokonano
w czasie danego przejścia zmian czy nie. Przejście bez zmian oznacza, że można
zakończyć wykonywanie algorytmu.
Drugie, dodatkowe usprawnienie, to zapamiętanie nie tylko samego faktu ale
także pozycji ostatniej zamiany. Będzie można dzięki temu zakończyć kolejne
przejście wcześniej niż na indeksie i.
Trzecie usprawnienie, to zmiana kierunków kolejnych przejść. Fakt ten jest
następstwem swoistej asymetrii występującej podczas sortowania i wymagającej
szerszego omówienia. Wyobraźmy sobie tylko jeden źle ustawiony wyraz:

mały w ciężkim końcu (tu wystarczy jedno przejscie!!!)



12 18 42 44 55 67 94 06
duży w lekkim końcu (tu potrzeba aż siedmiu przejsć!!!)



94 06 12 18 42 44 55
67 Wprowadzenie tych trzech usprawnień
prowadzi do algorytmu sortowania mieszanego.
Sortowanie mieszane



procedure SortowanieMieszane; 
var     j,k,l,p   :
Indeks;   
x         : Obiekt; 
begin    
i:=2;     { lewy koniec przedzialu, w ktorym sa
zamiany }    p:=n;     { prawy
koniec tego przedzialu }   
k:=n;     { tu zapamietujemy pozycje ostatniej zamiany
}    repeat    { pytanie
podstawowe - jak dlugo bedzie trwala zamiana? } 
    for j:=p downto 1
do     { petla zamian taka jak w algorytmie
babelkowym }        if
a[j-l].Klucz>a[j].Klucz
then           
{ czy "wyzszy" wyraz jest wiekszy } 
     
begin                 
{ jezeli tak, to wtedy dokonamy zamiany miejscami } 
       
x:=a[j-l];           {
ten wyraz pojdzie o oczko do dolu } 
       
a[j-l]:=a[j];        { lekki babelek
idzie o oczko do ggry } 
       
a[j]:=x.            
{ ten wyraz z kolei opada oczko do dolu } 
       
k:=j;               
{ nowosc! zapamietujemy pozycje przestawienia } 
     
end;                  
{ koniec zamian "do gory" }     
l:=k+l;                 
{ modyfikacja lewego konca przedzialu przestawien } 
    for j.=l to p
do         { tu petla
zamian "do dolu" - modyfikacja! } 
      if
a[j-l].Klucz>a[j].Klucz then     { znow: czy
"wyzszy" jest wiekszy }       
begin                 
{ jezeli tak, to bedzie zamiana miejscami } 
       
x:=a[j-l];           {
ten wyraz bedzie przestawiany "dg dolu" } 
       
a[j-l]:=a[j];        { wedrowka oczko
do gory }         
a[j]:=x;            
{ wedrowka oczko do dolu } 
       
k:=j                
{ zapamietanie pozycji przestawienia } 
     
end;                  
{ koniec zamian "do dolu" }     
p:=k-l                  
{ modyfikujemy prawy koniec przedzialu przestawien } 
  until
l>p                 
{ dopoki przedzial przestawiania bedzie mial dlugosc >O } 
end;                        
{ czyli innymi slowy dopoki l>p (ten chwyt swietnie znamy) } 
 Funkcjonowanie tego algorytmu ilustruje nasz
już prawie klasyczny przykład.



l=
2
3
3
4
4

p=
8
8
7
7
4


^

^

^

1
44
06
06
06
06

2
55
44
44
12
12

3
12
55
12
44
18

4
42
12
42
18
42

5
94
42
55
42
44

6
18
94
18
55
55

7
06
18
67
67
67

8
67
67
94
94
94Dokładna analiza metod sortowania wykazuje, że
metoda sortowania przez zamianę jak i jej ulepszenie - metoda mieszana są gorsze
od sortowania przez wstawienie i wybieranie. Usprawnienia tych metod w żaden
sposób nie wpływają na liczbę przesunięć obiektów. Obniżeniu ulega jedynie
liczba porównań. Ponieważ przestawienie jest znacznie kosztowniejsze od
porównania często intuicyjnie błyskotliwe usprawnienia mają marginalne znaczenie
praktyczne.
Średnia odległość, jaką każdy z n sortowanych obiektów musi przebyć wynosi
n/3. Fakt ten jest drogowskazem dla poszukiwań efektywnych metod sortowania. W
metodach prostych w każdym kroku przesuwa się obiekt de facto o jedno miejsce.
Stąd ogólny koszt metody rzędu n2. Ulepszenia muszą opierać się na założeniu
przesuwania obiektów w pojedynczym kroku na większą odległość.
Sortowanie przez podział.Jedną z najbardziej efektywnych
i nowoczesnych metod sortowania jest metoda, w której stosuje się zasadę
zamiany. Ulepszenia wprowadzone do metody sortowania przez zamianę dały w
efekcie jedną z najlepszych metod sortowania  tablic. Ze względu na jej
efektywność jej twórca C.A.R. Hoare określił ją mianem sortowania szybkiego.
W metodzie tej w celu zapewnienia efektywności zamienia się miejscami obiekty
znajdujące się daleko od siebie. Algorytm postępowania jest następujący.

wybieramy pewien obiekt x (na przykład środkowy),
przeglądamy tablicę od lewej strony, aż znajdziemy obiekt a[i]>x,
przeglądamy tablicę od prawej strony, aż znajdziemy obiekt a[j]<x,
wymieniamy te dwa obiekty i . . .
kontynuujemy proces przeglądania i zamiany aż do spotkania w
okolicach  środka tablicy. Efektem tego algorytmu będzie tablica
podzielona na dwie części:

lewą, z kluczami mniejszymi od x,
prawą, z kluczami większymi od x. Proces ten realizuje poniższa
procedura.



procedure Podzial;  
var     i,j :
Indeks;   { robocze indeksy }    
x,y : Obiekt;   { robocze zmienne typu sortowany obiekt
}   begin    
i:=l;                   
{ i : = minimalny klucz }    
j:=n;                   
{ j : = maksymalny klucz }     x:=a[(l+r) div
2];       { x - wyraz srodkowy sortowanej
tablicy }    
repeat                  
{ cala historie bedziemy powtarzac tak dlugo jak ... }  
    while a[i].Klucz < x.Klucz
do    { dopoki jestesmy na lewo od srodkowego
}        
i:=i+l;                       
{ . . . powiekszamy indeks i }      
while x.Klucz < a[j].Klucz do    { dopoki
na prawo od srodkowego }  
     
j:=j-l;                       
{ ... zmniejszamy indeks j }      
if i<=j
then                    
{ jezeli i <= j wtedy : }      
begin                           
{ zamieniamy miejscami wyrazy i, j }  
     
y:=a[i];                      
{ podstawienie do zmiennej roboczej }  
     
a[i]:=a[j];                   
{ pierwszy etap zamiany }  
     
a[j]:=y;                      
{ drugi etap zamiany }  
     
i:=i+1;                       
{ zwiekszenie indeksu i }  
     
j:=j-1;                       
{ zmniejszenie indeksu j }      
end;     until
i>j;                        
{ nie zostanie spelniony warunek i>j }  
end. Działanie algorytmu
zilustrujemy na klasycznym już przykładzie. Aby otrzymać tablicę podzieloną
trzeba dokonać dwóch zamian:  



44


55
12
42
94
06
18
67



18
06
12
42
94
55
44



i=5
j=3Efektem działania procedury Podzial jest
sytuacja, w której:

klucze a[1]. ..a[i-l] są mniejsze bądź równe kluczowi x,
klucze a[j-l]...a[n]są większe bądź równe kluczowi x. Otrzymaliśmy
więc podział tablicy na dwie części:

k=l..i-l a[k].klucz <= x.klucz,
k=j+l..n a[k].klucz >= x.klucz oraz

k=j+l..i-l a[k].klucz = x.klucz. Algorytm podziału tablicy
prowadzi bezpośrednio do posortowania tablicy. Po dokonaniu pierwszego podziału
przeprowadzamy ten sam proces dla obu części. Obliczenia kontynuujemy
dopóty, dopóki każda z części nie będzie składać się  tylko z jednego
obiektu. Ten sposób postępowania ilustruje poniższa procedura.



procedure SzybkieSortowanie;  
procedure Sortuj(l, p : Indeks);  
var     i,j :
Indeks;   { robocze indeksy }    
x,y : Obiekt;   { robocze zmienne typu sortowany obiekt
}   begin    
i:=l;           { i : =
minimalny klucz }    
j:=n;           { j : =
maksymalny klucz }     x:=a[(l+r) div 2]; { x
- wyraz srodkowy sortowanej tablicy }    
repeat          { cala
historie bedziemy powtarzac tak dlugo jak . . . }  
    while a[i].Klucz < x.Klucz
do   { dopoki jestesmy na lewo od srodkowego
}        
i:=i+l;                      
{ ...powiekszamy indeks i }      
while x.Klucz < a[j].Klucz do   { dopoki na
prawo od srodkowego }  
     
j:=j-l;                      
{ ...zmniejszamy indeks j }      
if i<=j
then                   
{ jezeli i <= j wtedy : }  
   
begin                          
{ zamieniamy miejscami wyrazy i, j }  
     
y:=a[i];                     
{ podstawienie do zmiennej roboczej }  
     
a[i]:=a[j];                  
{ pierwszy etap zamiany }  
     
a[j]:=y.                     
{ drugi etap zamiany }  
     
i:=i+l;                      
{ zwiekszenie indeksu i }  
     
j:=j-l;                      
{ zmniejszenie indeksu j }      
end;     until
i>j;      { nie zostanie spelniony warunek
i>j }     if 1<j
then       Sortuj(l,
j);     if i<p
then       Sortuj(i,
p);   end.  
begin     Sortuj(l,
n)  
end. Procedura Sortuj
wywołuje siebie rekurencyjnie. Rekurencja jest bardzo silnym narzędziem
programistycznym. Ten sam algorytm można zapisać w postaci nierekurencyjnej
zastępując rekurencję przez iterację.
Na zakończenie rozważań dotyczących algorytmów sortowania porównamy ich
efektywność. Wszystkie cytowane procedury zostały zaprojektowane przez autora
Pascala, Pana Niklausa Wirtha i pochodzą z książki Algorytmy + struktury
danych = programy. Ich działanie testowano na losowym zestawie danych.
Wykorzystano mikrokomputer 386DX 40MHz z koprocesorem. Nieco szokujące wyniki
czasy obliczeń w sekundach - są zestawione w poniższej tabeli.  



Liczba elementów

10

100

1000

5000

10000

15000

20000

25000

30000

Proste wstawianie

.00

.00

.44

9.83

40.75

91.78

162.53

-

-

Wstawianie połówkowe

.00

.00

.33

8.28

32.84

74.42

132.59

-

-

Proste wybieranie

.00

.00

.71

17.41

69.53

156.37

278.09

-

-

Sortowanie babelkowe

.00

.00

1.16

29.33

117.60

-

-

-

-

Sortowanie mieszane

.00

.00

.99

24.67

100.29

-

-

-

-

Szybkie sortowanie

.00

.00

.00

.11

.27

.44

.61

.83

.98Jeszcze raz potwierdziła się
prawda, że o efektywności programu zależy przede wszystkim algorytm obliczeń.
Można używać coraz szybszych procesorów, szukać lepszych języków programowania i
sprawniejszych kompilatorów. Są to jedynie półśrodki. Podstawowe "rezerwy" tkwią
jednak ciągle w sposobie wykonywania obliczeń, czyli wykorzystywanym algorytmie.
Starałem się Was o tym przekonać na kartach tej książki. Wierzę, że skutecznie.
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • teen-mushing.xlx.pl
  • Wątki
    Powered by wordpress | Theme: simpletex | © Lemur zaprasza