Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
Zasadę pracy algorytmu sortowania przez zliczanie jest najlepiej przedstawić za pomocą przykładu.
Posortować rosnąco zbiór danych:
{ 6 3 6 1 4 9 0 1 8 2 6 4 9 3 7 5 9 2 7 3 2 4 1 8 7 0 8 5 8 3 6 2 5 3 } |
Dla każdej wartości w zbiorze przygotowujemy licznik i ustawiamy go na 0.
[0:0] [1:0] [2:0] [3:0] [4:0] [5:0] [6:0] [7:0] [8:0] [9:0] |
Przeglądamy kolejne elementy zbioru i zliczamy ich wystąpienia w odpowiednich licznikach. Np. element 6 powoduje zwiększenie o 1 licznika nr 6. Po wykonaniu tego obiegu w poszczególnych licznikach mamy ilość wystąpień każdej wartości. W naszym przykładzie otrzymamy:
[0:2] [1:3] [2:4] [3:5] [4:3] [5:3] [6:4] [7:3] [8:4] [9:3] |
Teraz poczynając od drugiego licznika sumujemy zawartość licznika oraz jego poprzednika i otrzymujemy:
[0:2] [1:5] [2:9] [3:14] [4:17] [5:20] [6:24] [7:27] [8:31] [9:34] |
W wyniku tej operacji w każdym liczniku otrzymaliśmy ilość wartości mniejszych lub równych numerowi licznika, które występują w zbiorze wejściowym. Na przykład:
[0:2] - w zbiorze wejściowym są dwie wartości 0 [1:5] - w zbiorze wejściowym jest pięć wartości mniejszych lub równych 1 [2:9] - w zbiorze wejściowym jest dziewięć wartość mniejszych lub równych 2, itd. |
Zwróć uwagę, iż stan licznika określa teraz ostatnią pozycję w zbiorze
uporządkowanym, na której należy umieścić wartość równą numerowi licznika:
Wartość: | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 5 | 5 | 5 | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 8 | 8 | 8 | 8 | 9 | 9 | 9 |
Pozycja: | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
Przeglądamy jeszcze raz zbiór wejściowy idąc od ostatniego elementu do pierwszego (aby zachować stabilność sortowania). Każdy element umieszczamy w zbiorze wynikowym na pozycji równej zawartości licznika dla tego elementu. Po wykonaniu tej operacji licznik zmniejszamy o 1. Dzięki temu następna taka wartość trafi na wcześniejszą pozycję.
W naszym przykładzie rozpoczynamy od ostatniej liczby 3. Jej licznik ma zawartość [3:14]. Zatem liczbę 3 umieszczamy w zbiorze wynikowym na pozycji 14 i zmniejszamy o 1 stan licznika otrzymując [3:13]. Kolejna liczba 3 trafi teraz na pozycję 13, itd.
Dla liczby 5 stan licznika wynosi [5:20]. Umieszczamy ją zatem na 20 pozycji i licznik zmniejszamy o 1 otrzymując [5:19].
Postępujemy w ten sam sposób z pozostałymi elementami zbioru. W efekcie zbiór wynikowy będzie posortowany rosnąco:
{ 0 0 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 8 8 8 8 9 9 9 } |
Przyjrzawszy się dokładnie algorytmowi sortowania przez zliczanie możesz zastanawiać się, dlaczego postępujemy w tak dziwny sposób? Przecież mając zliczone wystąpienia każdej wartości w licznikach, możemy je od razu przepisać do zbioru wyjściowego, jak zrobiliśmy w pierwszej wersji algorytmu sortowania kubełkowego. Miałbyś rację, gdyby chodziło jedynie o posortowanie liczb. Jest jednak inaczej.
Celem nie jest posortowanie jedynie samych wartości elementów. Sortowane wartości są zwykle tzw. kluczami, czyli wartościami skojarzonymi z elementami, które wyliczono na podstawie pewnego kryterium Sortując klucze chcemy posortować zawierające je elementy. Dlatego do zbioru wynikowego musimy przepisać całe elementy ze zbioru wejściowego, gdyż w praktyce klucze stanowią jedynie część (raczej małą) danych zawartych w elementach. Zatem algorytm sortowania przez zliczanie wyznacza docelowe pozycje elementów na podstawie reprezentujących je kluczy, które mogą się wielokrotnie powtarzać. Następnie elementy są umieszczane na właściwym miejscu w zbiorze wyjściowym. Prześledź dokładnie podany poniżej algorytm oraz przykładowe programy, a wszystko powinno się wyjaśnić.
d[ ] | - | zbiór elementów do posortowania. Każdy element posiada pole klucz, wg którego dokonuje się sortowania. Pole klucz jest liczbą całkowitą. Indeksy elementów rozpoczynają się od 1. |
n | - | ilość elementów w zbiorze d[ ]. n ∈ N |
kmin | - | minimalna wartość klucza, kmin ∈ C |
kmax | - | maksymalna wartość klucza, kmax ∈ C |
b[ ] | - zbiór z posortowanymi elementami ze zbioru d[ ]. Indeksy elementów rozpoczynają się od 1. |
i | - | zmienna dla pętli iteracyjnych, i ∈ C |
L[ ] | - | tablica liczników wartości kluczy. Elementy są liczbami całkowitymi. Indeksy przebiegają kolejne wartości od kmin do kmax. |
K01: | Dla i =
kmin, kmin + 1,...,kmax: wykonuj: L[i] ← 0 |
K02: | Dla i = 1,2,...,n: wykonuj: L[d[i].klucz] ← L[d[i].klucz] + 1 |
K03: | Dla i =
kmin + 1, kmin + 2,...,kmax: wykonuj: L[i] ← L[i] + L[i - 1] |
K04: | Dla i =
n, n
- 1,...,1: wykonuj kroki K05...K06 |
K05: | b[ L[ d[i].klucz ] ] ← d[i] |
K06: | L[ d[i].klucz ] ← L[ d[i].klucz ] - 1 |
K07: | Zakończ |
Algorytm sortowania przez zliczanie zbudowany jest z kolejno następujących po sobie pętli iteracyjnych.
Zwróć uwagę, iż algorytm sortowania przez zliczanie nie porównuje ze sobą
żadnych elementów zbioru. Teoretycznie udowodniono, iż algorytmy sortujące,
które porównują ze sobą elementy zbioru nie mogą osiągać w przypadku ogólnym
lepszej klasy złożoności obliczeniowej
Aby wyznaczyć klasę złożoności obliczeniowej algorytmu sortowania przez zliczanie, przyjrzyjmy się mu bliżej.
Z tego porównania widzimy jasno, iż na czas wykonania algorytmu ma wpływ
zarówno m (ilość wartości kluczy)
jak i n (ilość sortowanych
elementów). Stąd klasa złożoności obliczeniowej wynosi
Prezentowane programy generują pseudolosowe ciągi 3-literowych wyrazów zbudowanych z liter A, B oraz C. Dla każdego wygenerowanego wyrazu jest wyliczany klucz określający jego alfabetyczną kolejność:
Wyraz | AAA | AAB | AAC | ABA | ABB | ... | CCA | CCB | CCC |
Klucz | 0 | 1 | 2 | 3 | 4 | ... | 24 | 25 | 26 |
Wyrazy są rosnąco sortowane wg wartości klucza.
C++// Sortowanie przez zliczanie //-------------------------------------------------------- // (C)2012 mgr Jerzy Wałaszek // I Liceum Ogólnokształcące // im. K. Brodzińskiego // w Tarnowie //-------------------------------------------------------- #include <iostream> #include <cstdlib> #include <time.h> using namespace std; int main() { const int N = 80; const int KMIN = 0; const int KMAX = 26; struct { unsigned klucz; char wyraz[3]; } d[N],b[N]; unsigned L[KMAX - KMIN + 1]; int i,j,v; cout << " Sortowanie Przez Zliczanie\n" "------------------------------\n" " (C)2005 mgr Jerzy Walaszek\n\n" "Przed sortowaniem:\n\n"; // Generujemy losowe elementy do sortowania oraz ich klucze srand((unsigned)time(NULL)); for(i = 0; i < N; i++) { for(j = 0; j < 3; j++) d[i].wyraz[j] = 65 + rand() % 3; d[i].klucz = 0; v = 1; for(j = 2; j >= 0; j--) { d[i].klucz += v * (d[i].wyraz[j] - 65); v *= 3; } } // Wyświetlamy wygenerowane elementy for(i = 0; i < N; i++) cout << ' ' << d[i].wyraz[0] << d[i].wyraz[1] << d[i].wyraz[2]; cout << endl; // Zerujemy liczniki for(i = KMIN; i <= KMAX; i++) L[i - KMIN] = 0; // Zliczamy wystąpienia kluczy for(i = 0; i < N; i++) L[d[i].klucz - KMIN]++; // Obliczamy pozycje końcowe elementów for(i = KMIN + 1; i <= KMAX; i++) L[i - KMIN] += L[i - KMIN - 1]; // Przepisujemy elementy z d[ ] do b[ ] for(i = N - 1; i >= 0; i--) b[(L[d[i].klucz - KMIN]--) - 1] = d[i]; // Wyświetlamy wyniki w b[ ] cout << "Po sortowaniu:\n\n"; for(i = 0; i < N; i++) cout << ' ' << b[i].wyraz[0] << b[i].wyraz[1] << b[i].wyraz[2]; cout << endl; return 0; } |
Pascal// Sortowanie przez zliczanie //-------------------------------------------------------- // (C)2012 mgr Jerzy Wałaszek // I Liceum Ogólnokształcące // im. K. Brodzińskiego // w Tarnowie //-------------------------------------------------------- const N = 80; KMIN = 0; KMAX = 26; // Tutaj definiujemy typ elementu type TElement = record klucz : cardinal; wyraz : string[3]; end; // Zmienne var d,b : array[1..N] of TElement; L : array[KMIN..KMAX] of cardinal; i,j,v : integer; s : string; begin writeln(' Sortowanie Przez Zliczanie '); writeln('------------------------------'); writeln(' (C)2005 mgr Jerzy Walaszek '); writeln; writeln('Przed sortowaniem:'); writeln; // Generujemy losowe elementy do sortowania oraz ich klucze randomize; for i := 1 to N do begin s := ''; for j := 1 to 3 do s := s + char(65 + random(3)); d[i].wyraz := s; d[i].klucz := 0; v := 1; for j := 3 downto 1 do begin inc(d[i].klucz, v * (ord(d[i].wyraz[j]) - 65)); v := 3 * v; end; end; // Wyświetlamy wygenerowane elementy for i := 1 to N do write(d[i].wyraz:4); writeln; // Zerujemy liczniki for i := KMIN to KMAX do L[i] := 0; // Zliczamy wystąpienia kluczy for i := 1 to N do inc(L[d[i].klucz]); // Obliczamy pozycje końcowe elementów for i := KMIN + 1 to KMAX do inc(L[i], L[i - 1]); // Przepisujemy elementy z d[ ] do b[ ] for i := N downto 1 do begin b[L[d[i].klucz]] := d[i]; dec(L[d[i].klucz]); end; // Wyświetlamy wyniki w b[ ] writeln('Po sortowaniu:'); writeln; for i := 1 to N do write(b[i].wyraz:4); writeln; writeln('Koniec. Nacisnij klawisz Enter...'); readln; end. |
Basic' Sortowanie przez zliczanie '-------------------------------------------------------- ' (C)2012 mgr Jerzy Wałaszek ' I Liceum Ogólnokształcące ' im. K. Brodzińskiego ' w Tarnowie '-------------------------------------------------------- OPTION EXPLICIT CONST N = 80 CONST KMIN = 0 CONST KMAX = 26 ' Tutaj definiujemy typ elementu TYPE TElement klucz AS UINTEGER wyraz AS STRING * 3 END TYPE ' Zmienne DIM AS TElement d(N),b(N) DIM AS UINTEGER L(KMIN TO KMAX) DIM AS INTEGER i,j,v DIM s AS STRING PRINT " Sortowanie Przez Zliczanie " PRINT "------------------------------" PRINT " (C)2005 mgr Jerzy Walaszek " PRINT PRINT "Przed sortowaniem:" PRINT ' Generujemy losowe elementy do sortowania oraz ich klucze RANDOMIZE FOR i = 1 TO N s = "" FOR j = 1 TO 3: s += CHR$(65 + INT(RND(1) * 3)): NEXT d(i).wyraz = s d(i).klucz = 0 v = 1 FOR j = 3 TO 1 STEP -1 d(i).klucz += v * (ASC(MID$(d(i).wyraz,j,1)) - 65) v *= 3 NEXT NEXT ' Wyświetlamy wygenerowane elementy FOR i = 1 TO N: PRINT " "; d(i).wyraz;: NEXT PRINT ' Zerujemy liczniki FOR i = KMIN TO KMAX: L(i) = 0: NEXT ' Zliczamy wystąpienia kluczy FOR i = 1 TO N: L(d(i).klucz) += 1: NEXT ' Obliczamy pozycje końcowe elementów FOR i = KMIN + 1 TO KMAX: L(i) += L(i - 1): NEXT ' Przepisujemy elementy z d[ ] do b[ ] FOR i = N TO 1 STEP -1 b(L(d(i).klucz)) = d(i) L(d(i).klucz) -= 1 NEXT ' Wyświetlamy wyniki w b[ ] PRINT "Po sortowaniu:" PRINT FOR i = 1 TO N: PRINT " ";b(i).wyraz;: NEXT PRINT PRINT "Koniec. Nacisnij dowolny klawisz..." SLEEP END |
JavaScript<html> <head> </head> <body> <form style="BORDER-RIGHT: #ff9933 1px outset; PADDING-RIGHT: 4px; BORDER-TOP: #ff9933 1px outset; PADDING-LEFT: 4px; PADDING-BOTTOM: 1px; BORDER-LEFT: #ff9933 1px outset; PADDING-TOP: 1px; BORDER-BOTTOM: #ff9933 1px outset; BACKGROUND-COLOR: #ffcc66" name="frmcountingsort"> <h3 style="text-align: center">Sortowanie Przez Zliczanie</h3> <p style="TEXT-ALIGN: center"> (C)2012 mgr Jerzy Wałaszek - I LO w Tarnowie </p> <hr> <p style="TEXT-ALIGN: center"> <input onclick="main()" type="button" value="Sortuj" name="B1"> </p> <p id="t_out" style="TEXT-ALIGN: center">...</p> </form> <script language=javascript> // Sortowanie przez zliczanie //-------------------------------------------------------- // (C)2012 mgr Jerzy Wałaszek // I Liceum Ogólnokształcące // im. K. Brodzińskiego // w Tarnowie //-------------------------------------------------------- var N = 80; var KMIN = 0; var KMAX = 26; var d = new Array(); var b = new Array(); var L = new Array; var i; for(i = 0; i < N; i++) { d[i] = new Object(); b[i] = new Object(); } function main() { var i,j,t,v; // Generujemy losowe elementy do sortowania oraz ich klucze for(i = 0; i < N; i++) { d[i].wyraz = String.fromCharCode(65 + Math.floor(Math.random() * 3)) + String.fromCharCode(65 + Math.floor(Math.random() * 3)) + String.fromCharCode(65 + Math.floor(Math.random() * 3)); d[i].klucz = 0; v = 1; for(j = 2; j >= 0; j--) { d[i].klucz += v * (d[i].wyraz.charCodeAt(j) - 65); v *= 3; } } // Wyświetlamy wygenerowane elementy t = "Przed sortowaniem:<BR><BR>"; for(i = 0; i < N; i++) t += " " + d[i].wyraz; t += "<BR><BR>"; // Zerujemy liczniki for(i = KMIN; i <= KMAX; i++) L[i - KMIN] = 0; // Zliczamy wystąpienia kluczy for(i = 0; i < N; i++) L[d[i].klucz - KMIN]++; // Obliczamy pozycje końcowe elementów for(i = KMIN + 1; i <= KMAX; i++) L[i - KMIN] += L[i - KMIN - 1]; // Przepisujemy elementy z d[ ] do b[ ] for(i = N - 1; i >= 0; i--) b[(L[d[i].klucz - KMIN]--) - 1] = d[i]; // Wyświetlamy wyniki w b[ ] t += "Po sortowaniu:<BR><BR>"; for(i = 0; i < N; i++) t += " " + b[i].wyraz; document.getElementById("t_out").innerHTML = t; } </script> </body> </html> |
Wynik: |
Sortowanie Przez
Zliczanie ------------------------------ (C)2005 mgr Jerzy Walaszek Przed sortowaniem: CAC CAA AAB BAB AAC CAB CBC BCC ACC AAA ACA BCC ABC CAC ACC CAA ACB BCC CAB CAA ACA CCB BAC BCA ABB ABB CAB CAC AAA BCA BCC ACB AAA BAA CAC AAB BCA CCB CAB CAA BCB BBB BBB BCB BCB CAA BAA CCC BAA BCC AAC CBC BAA BCA BAA CAC ABA ABC CAA CCC CBA ABC BCA BBA ACC BBB CBC ACA ABC ACC BBA CCC BBA CAB BBC BBB ABB AAC CCB BCA Po sortowaniu: AAA AAA AAA AAB AAB AAC AAC AAC ABA ABB ABB ABB ABC ABC ABC ABC ACA ACA ACA ACB ACB ACC ACC ACC ACC BAA BAA BAA BAA BAA BAB BAC BBA BBA BBA BBB BBB BBB BBB BBC BCA BCA BCA BCA BCA BCA BCB BCB BCB BCC BCC BCC BCC BCC CAA CAA CAA CAA CAA CAA CAB CAB CAB CAB CAB CAC CAC CAC CAC CAC CBA CBC CBC CBC CCB CCB CCB CCC CCC CCC |
Zobacz również na:
Sortowanie rozrzutowe | Sortowanie
kubełkowe 1 | Listy | Sortowanie
kubełkowe 2 | Sortowanie pozycyjne
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.