|
Serwis Edukacyjny Nauczycieli w I-LO w Tarnowie
Materiały głownie dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 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 |
| kmin | - | minimalna wartość klucza, |
| kmax | - | maksymalna wartość klucza, |
| b[ ] | - zbiór z posortowanymi elementami ze zbioru |
| i | - | zmienna dla pętli iteracyjnych, |
| L[ ] | - | tablica liczników wartości kluczy. Elementy są liczbami całkowitymi.
Indeksy przebiegają kolejne wartości |
| 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
// 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 << 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 << endl;
system("pause");
return 0;
}
|
Pascal// Sortowanie przez zliczanie
//---------------------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// 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;
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;
writeln('Nacisnij Enter...');
readln;
end.
|
Basic' Sortowanie przez zliczanie
'---------------------------
' (C)2012 mgr Jerzy Wałaszek
' I Liceum Ogólnokształcące
' w Tarnowie
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
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
PRINT "Nacisnij dowolny klawisz..."
SLEEP
END
|
Python
(dodatek)# Sortowanie przez zliczanie
#---------------------------
# (C)2026 mgr Jerzy Wałaszek
# I Liceum Ogólnokształcące
# w Tarnowie
import random
n = 80
kmin = 0
kmax = 26
class List:
def __init__(self):
self.klucz = 0
self.wyraz = []
d = [List() for _ in range(n)]
b = [List() for _ in range(n)]
l = [0] * (kmax - kmin + 1)
print("Sortowanie Przez Zliczanie")
print("--------------------------")
print("(C)2026 mgr Jerzy Wałaszek")
print()
print("Przed sortowaniem:")
print()
# Generujemy losowe elementy
# do sortowania oraz ich klucze
for i in range(n):
for j in range(3):
d[i].wyraz.append(random.randrange(65,68))
v = 1
for j in reversed(range(3)):
d[i].klucz += v*(d[i].wyraz[j]-65)
v *= 3
# Wyświetlamy wygenerowane elementy
for i in range(n):
print(" ",
chr(d[i].wyraz[0]),
chr(d[i].wyraz[1]),
chr(d[i].wyraz[2]),
sep="",end="")
print()
print()
# Zliczamy wystąpienia kluczy
for i in range(n):
l[d[i].klucz - kmin] += 1
# Obliczamy pozycje końcowe elementów
for i in range(kmin+1,kmax+1):
l[i - kmin] += l[i - kmin - 1]
# Przepisujemy elementy z d[] do b[]
for i in reversed(range(n)):
b[l[d[i].klucz-kmin] - 1] = d[i]
l[d[i].klucz - kmin] -= 1
# Wyświetlamy wyniki w b[]
print("Po sortowaniu:")
print()
for i in range(n):
print(" ",
chr(b[i].wyraz[0]),
chr(b[i].wyraz[1]),
chr(b[i].wyraz[2]),
sep="", end="")
print()
print()
input("Naciśnij Enter...")
|
| Wynik: |
Sortowanie Przez Zliczanie -------------------------- (C)2026 mgr Jerzy Wałaszek Przed sortowaniem: ACA ACA ACB CCA BCC CBB BCB CAB BCA ABB BBC ABA BBC BAA ABA AAC CCA CCA ACC ABB CBA CCA ACA CCA ABC ACA AAA BAA AAA CAA CBB CCB CAB ABC BBB BBB ABB ABC BBC BAC ACB AAC ACB ACC ABA AAB BCA BBB CBC ACB CAC CAB AAC BBA CBA ABC CBC AAC CAA CAA CAC BCA CCA BBB AAC BBA CCA CBB AAB AAA ABC AAC CCA CCB BCB CCA CBA BBB ABB ACA Po sortowaniu: AAA AAA AAA AAB AAB AAC AAC AAC AAC AAC AAC ABA ABA ABA ABB ABB ABB ABB ABC ABC ABC ABC ABC ACA ACA ACA ACA ACA ACB ACB ACB ACB ACC ACC BAA BAA BAC BBA BBA BBB BBB BBB BBB BBB BBC BBC BBC BCA BCA BCA BCB BCB BCC CAA CAA CAA CAB CAB CAB CAC CAC CBA CBA CBA CBB CBB CBB CBC CBC CCA CCA CCA CCA CCA CCA CCA CCA CCA CCB CCB Naciśnij Enter... |
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
// 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> |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 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.