Sortowanie Gnoma to metoda sortowania danych, która wymaga jedynie jednej pętli. Implementacja częściowo opiera się na pomyśle z sortowania bąbelkowego. Złożoność tego algorytmu to Θ(n2). W najlepszym przypadku złożoność może być liniowa. Algorytm wymaga tylko zmiennej do zapamiętania aktualnej pozycji sortowania, więc złożoność pamięciowa to Θ(1).
Sortowanie rozpoczyna się od pierwszego elementu na liście. Jeśli aktualnie rozpatrywany element jest pierwszym elementem na liście, albo spełnia warunki posortowania to należy zwiększyć numer indeksu. W przeciwnym wypadku należy zamienić aktualny element z poprzednim i zmniejszyć indeks o 1.
Istnieje jeszcze zoptymalizowana wersja tego algorytmu. Podczas rozpoczęcia cofania elementu algorytm zapamiętuje aktualną pozycję i po przesunięciu elementu na jego właściwą pozycję wraca do zapamiętanej pozycji. W ten sposób pomijany jest proces przechodzenia element po elemencie do opuszczonej pozycji.
Weźmy przykładowo listę L:=[1, 5, 2, 4, 3]. Początkowy indeks pos = 0 (wskazuje na pierwszy element na liście). Lista będzie sortowana rosnąco:
pos | Lista | Warunki | Akcja |
---|---|---|---|
0 | [1, 5, 2, 4, 3] | indeks wynosi 0 | zwiększenie pos o 1 |
1 | [1, 5, 2, 4, 3] | element 5 ≥ 1 | zwiększenie pos o 1 |
2 | [1, 5, 2, 4, 3] | element 2 < 5 | zamiana 2 z 5, zmniejszenie pos o 1 |
1 | [1, 2, 5, 4, 3] | element 2 ≥ 1 | zwiększenie pos o 1 |
2 | [1, 2, 5, 4, 3] | element 5 ≥ 2 | zwiększenie pos o 1 |
3 | [1, 2, 5, 4, 3] | element 4 < 5 | zamiana 4 z 5, zmniejszenie pos o 1 |
2 | [1, 2, 4, 5, 3] | element 4 ≥ 2 | zwiększenie pos o 1 |
3 | [1, 2, 4, 5, 3] | element 5 ≥ 4 | zwiększenie pos o 1 |
4 | [1, 2, 4, 5, 3] | element 3 < 5 | zamiana 3 z 5, zmniejszenie pos o 1 |
3 | [1, 2, 4, 3, 5] | element 3 < 4 | zamiana 3 z 4, zmniejszenie pos o 1 |
2 | [1, 2, 3, 4, 5] | element 3 ≥ 2 | zwiększenie pos o 1 |
3 | [1, 2, 3, 4, 5] | element 4 ≥ 3 | zwiększenie pos o 1 |
4 | [1, 2, 3, 4, 5] | element 5 ≥ 4 | zwiększenie pos o 1 |
5 | [1, 2, 3, 4, 5] | pos = długość listy | Lista została posortowana |
W podanym przykładzie algorytm cofał się łącznie cztery razy i dokonał tyle samo niepotrzebnych ruchów do przodu. Nadmiarowe kroki w wersji zoptymalizowanej są pomijane poprzez zapamiętanie pozycji na której algorytm znalazł nie ustawiony element. Warto zauważyć, że podczas ustawiania elementu algorytm zachowuje się jak algorytm sortowania bąbelkowego.
Do zaimplementowania sortowania Gnoma wystarczy tylko jedna pętla oraz indeks, który będzie wskazywał dokąd zaszło sortowanie. Poniżej znajduje się gotowa implementacja algorytmu:
(2.) Rozpocznij sortowanie od pozycji 0. (3.) Dopóki indeks nie wykroczy poza granice tabeli (4.) podejmij decyzję jaką akcję wykonać. W przypadku, gdy indeks wynosi 0 lub dany element jest posortowany względem poprzedniego to (5.) przejdź do następnej pary elementów. (6.) W przeciwnym wypadku: (7.) zamień aktualny element z poprzednim i (8.) zmniejsz indeks o 1.
Jak wcześniej zostało wspomniane algorytm wykonuje zbędne kroki po ustawieniu elementu w posortowanej części listy. Można temu zapobiec dodając dodatkowy indeks. W poniższym rozwiązaniu jego rolę spełnia zmienna last_pos.
Ważne jest to, aby zauważyć, że ostatnią pozycję należy zapamiętać przed pierwszą zamianą, a następnie można wrócić do zapamiętanego indeksu dopiero jak następi zwiększenie indeksu. Wtedy można przejść nawet o jedną pozycję dalej niż wartość zapamiętana. Zadanie realizuje poniższy kod:
Zoptymalizowana wersja nie zmienia samej struktury algorytmu, ale dodaje dodatkowe warunki. (2.) Ponownie sortowanie zaczyna się od pierwszego elementu i (3.) należy zaznaczyć, że zapamiętana pozycja też ma tę samą wartość. W dalszej części algorytmu podczas zwiększania wartości (6.) należy przejść o jedną pozycję dalej niż zapamiętana oraz (7.) zapamiętać nową wyliczoną wartość jako ostatnią wartość. Podczas przesuwania elementów pozycja ost_pos nie jest modyfikowana, więc algorytm wróci do niej jak tylko zakończy ustawianie elementu.
W celu przetestowania działania każdej z implementacji można skorzystać z poniższej funkcji main(). Wczyta ona od użytkownika potrzebne dane, a następnie wypisze posortowaną listę na ekran.
Napisz funkcję o nagłówku double* sortuj(const double* lista, int n), która posortuje element na liście lista malejąco. Przykładowo dla tablicy L:=[45, 12, 42, 33, 34] program wypisze: