Algorytmy i struktury danych – zajęcia 7

advertisement
Algorytm Countsort
Zadanie 1
Dane: tablica t[N] zawierająca liczby naturalne z przedziału od 0 do m-1.
Problem: Skonstruować tablicę przechowującą liczby wystąpień w tablicy t[] dla każdej z
liczb od 0 do m-1.
Rozwiązanie:
Tablicę wynikową nazwijmy count (od ang. zlicz). Oczywiście jej rozmiar to m.
Chcemy, aby element count[k] przechowywał liczbę elementów równych k w tablicy t[].
// Najpierw wyzerujemy zawartość tablicy count:
for (i=0; i<m; i++) count[i] = 0;
// ilość wystąpień liczby k przechowujemy w count[k], zatem ich zliczanie można zapisać tak:
for (i=0; i<N; i++) {
k = t[i];
count[k]++;
}
Zadanie 2
Zmodyfikować tablicę count z Zadania 1 tak, aby element count[k] przechowywał liczbę
elementów nie większych od k w tablicy t[] (czyli liczbę elementów mniejszych lub
równych k).
Jeśli założymy, że count[k-1] spełnia już warunki zadania, wtedy dla k wystarczy podstawić
count[k] = count[k-1] + count[k]. Zapis ustawienia właściwych wartości dla każdego k (czyli
całej tablicy count) może wyglądać np. tak:
for (k=1; k<m; k++)
count[k] = count[k-1] + count[k];
Zadanie 3 - Sortowanie metodą zliczania – Countsort
Po wykonaniu instrukcji zawartych w dwóch poprzednich zadaniach łatwo można poustawiać
elementy tablicy t[] w kolejności np. rosnącej. Załóżmy, że na i-tym miejscu w t[] mamy
liczbę k. Wystarczy wtedy zajrzeć do k-tego elementu tablicy count[k]. Powinna być tam
informacja ile jest elementów mniejszych lub równych k. Jednocześnie jest to pozycja w
tablicy wyjściowej, na której powinien się znaleźć element t[i] (oczywiście przy
indeksowaniu od zera indeks tego miejsca wynosi count[k] – 1). Powtarzając rozumowanie
dla każdego elementu tablicy t[] zapiszemy to w postaci pętli:
for (i=n-1; i >= 0; i--)
{
k = t[i];
count[k]--;
out[count[k]] = k;
}
Tablicę t[] analizowaliśmy od prawej, aby zapewnić stabilność algorytmu. Gdy mamy dwa
równe elementy, to najpierw weźmiemy ten bardziej z prawej. Zatem następny (równy)
powinien być na lewo od niego (na pozycji oznaczonej mniejszym indeksem), aby algorytm
był stabilny. Stąd w pętli instrukcja count[k]--;
Cały algorytm countsort:
// 1
for (i=0; i < m; i++) count[i] = 0 ;
for (i=0; i < N; i++) {
k = t[i];
count[k]++;
}
// 2
for (k=1; k < m; k++)
count[k] = count[k-1] + count[k];
// 3
for (i=N-1; i >= 0; i--)
{
k = t[i];
count[k]--;
out[count[k]] = k;
}
Zadania do countsort.
1. Przeanalizuj algorytm countsort sortując tablicę:
t[]={2,3,2,3,0,2,0,3,1,5,3,2,0}
N=13
m=6
Fragment pierwszy: wypełnia tablicę count
Indeks
Wartość
0
3
1
1
2
4
3
4
4
0
5
1
Dokończ ...
2. Oszacuj złożoność algorytmu countsort. Odp: Złożoność: O(n+m)
3. Wymień główne wady tej metody sortowania
Odp: Wady:
a. Niezbędna pamięć robocza wielkości O(n+m)
b. Klucze muszą być szczególnej postaci: reprezentowalne liczbami całkowitymi
ograniczonej wielkości.
4. Przekształć trzecią część algorytmu tak, aby tablicę t[] analizować od lewej przy
zachowaniu stabilności algorytmu.
Analiza algorytmu radixsort
Zadanie 4
Za pomocą algorytmu countsort posortuj tablicę:
t[]={12, 154, 184, 200, 98, 45, 111, 86}
wg ostatniej cyfry.
Gdyby następnie wykonać sortowanie wg drugiej i pierwszej cyfry to tablica byłaby
posortowana. Ten typ sortowania nazywamy radixsort.
Schemat algorytmu (b – maksymalna liczba cyfr dla elementów w tablicy t[]):
//radixsort (z wykładu)
for (k=0; k < b; k++)
countsort (A, k);
// wywołanie funkcji countsort(a,k) sortującej
// metodą zliczania, używającej jako klucza do
// porównań k-tego bajtu każdego elementu t[i]
Przykład:
102 220 120 012 210 011 100 121 021 202 022
po sortowaniu względem ostatniej cyfry:
220 120 210 100 200 011 121 021 201 102 012
otrzymany wynik sortujemy względem środkowej cyfry:
100 200 201 102 202 210 011 012 220 120 121
a ten z kolei względem cyfry najbardziej znaczącej:
011 012 021 022 100 102 120 121 200 201 202
Zadania do countsort.
1. Uzasadnij złożoność radixsort:
Złożoność czasowa: O(b * (n+m)), odp. ponieważ b razy wykonany countsort,
200 201
202 022
021 022
210 220
Złożoność pamięciowa: O(n+m), odp. tablica do zliczania i do przepisywania,
2. Napisz funkcję dającą w wyniku k-tą z prawej (numerując od zera) cyfrę w liczbie
całkowitej X. Jeśli X ma mniej cyfr funkcja powinna zwracać zero.
int cyfra(int x, int k)
{
return (x / 10^k) mod 10
}
3. Zmodyfikuj algorytm countsort tak, aby sortował wg jednej cyfry (zapisz go w postaci
funkcji countsort(t[], k) tak, aby wywołanie w podanym algorytmie radixsort było poprawne).
4. Napisz radixsort działający w oparciu o reprezentację binarną liczb (sortowanie „bit po
bicie”).
Download