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”).