Sortowanie – przypomnienie

Sortowaniem nazywamy porządkowanie elementów w pewien ustalony sposób.

Istnieje wiele metod sortowania, różniących się zarówno sposobem działania, jak i efektywnością. W związku z tym algorytmy sortujące, w zależności od swojej złożoności algorytmicznej, różnią się czasem rozwiązywania danego problemu.

Do czego służy sortowanie?

Sortowanie to inaczej porządkowanie danych uwzględniające jakąś ich cechę. Jeżeli sortujemy liczby, taką cechą jest zazwyczaj ich wartość, więc sortujemy je rosnąco, nierosnąco, malejąco oraz niemalejąco. Sortować możemy nie tylko liczby, ale również litery czy ciągi znaków.

Algorytmy stabilne i niestabilne

Algorytmy stabilne to takie, w których elementy o takiej samej wartości nie zmienią pozycji względem siebie, natomiast algorytmy niestabilne mogą zmienić ich kolejność. Jeżeli algorytm niestabilny napotka dwa elementy o wartości 7, nie musi zamieniać ich miejscami, aby uzyskać posortowany zbiór. W zależności od implementacji, może to jednak zrobić.

Sortowanie przez wybieranie

Metoda sortowania przez wybieranie w porządku rosnącym polega na znalezieniu najmniejszego elementu zbioru i umieszczeniu go na pierwszym miejscu. Obiekt, który się tam wcześniej znajdował, trafia na miejsce zajmowane dotychczas przez element o najmniejszej wartości klucza.

Następnie wśród pozostałych (jeszcze nieposortowanych) elementów znowu wyszukuje się ten o najmniejszej wartości klucza i umieszcza go na drugim miejscu (ponownie dokonując zamiany z dotychczasowym obiektem) itd.

W każdym cyklu zmniejsza się liczba nieposortowanych elementów. Opisane czynności wykonuje się aż do momentu, w którym pozostanie tylko jeden element w części nieposortowanej – na pewno wartość jego klucza jest największa w całym zbiorze.

Kiedy sortujemy tablicę malejąco, rozpoczynamy od znalezienia elementu największego. Zamieniamy go miejscami z elementem, który znajdował się na pierwszej pozycji.

Kolorem zielonym zaznaczono miejsce przeznaczone dla pierwszego elementu. Ponieważ sortujemy zbiór malejąco, powinna się tu znaleźć największa liczba.

R1Dm91lmIEDDk
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.

Jest nią zaznaczony kolorem czerwonym element o wartości 9. Zamieniamy go miejscami z będącą na pierwszej pozycji liczbą 5.

RzyLZ4eGpPJ3d
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.

Na razie umieściliśmy jeden element we właściwym miejscu. Elementy już posortowane oznaczymy barwą żółtą. Teraz musimy znaleźć obiekt o największej wartości klucza w nieposortowanej części i zamienić go miejscami z liczbą 2 (pole to ma obecnie barwę zieloną).

RogX1CwwaYTN3
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.

Element o wartości 8 zamieniamy miejscami z liczbą 2. Rozpoczynamy szukanie wartości, która powinna znaleźć się na trzeciej pozycji.

R18pUWBg1i5g3
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.
RdWVzeAuD84F6
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.

Cały proces trwa aż do odnalezienia przedostatniego elementu. Ostatnia wartość na pewno jest najmniejsza:

RBsTRR4QHiZ4l
Źródło: Contentplus.pl Sp. z o.o., licencja: CC BY-SA 3.0.

Algorytm w pseudokodzie

Zanim przejdziemy do przełożenia opisanego algorytmu na  język C++, przedstawimy go w postaci pseudokodu. Załóżmy, że sortujemy zbiór liczb w porządku rosnącym.

Użyjemy przy tym mechanizmu pętli zagnieżdżonychzagnieżdżona pętlapętli zagnieżdżonych. Pierwsza z nich, zewnętrzna, będzie odpowiadać za wskazywanie kolejnych pozycji w tablicy. Zapełnimy je liczbami o coraz większych wartościach.

O tym, która liczba powinna znaleźć się w miejscu wskazanym przez zewnętrzną pętlę, poinformuje nas pętla wewnętrzna. Dzięki niej wyszukamy najmniejsze liczby w nieposortowanej części tablicy.

Zaczniemy od zdefiniowania zmiennych. Będzie nam potrzebna tablica zawierająca elementy do posortowania:

Linia 1. zbior otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze n.

Następnie tworzymy pierwszą, zewnętrzną pętlę. Wskaże ona kolejne elementy tablicy oprócz ostatniego. Jeżeli poprzednie liczby zostaną ułożone we właściwym porządku, to ostatnia na pewno znajdzie się tam, gdzie być powinna.

Linia 1. zbior otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze n. Linia 3. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj.

Dla każdej wartości i należy przeszukać nieposortowaną część tablicy i znaleźć element, który powinien zostać umieszczony w miejscu wskazywanym przez zmienną i. W pierwszym cyklu będzie to pierwsze miejsce tablicy, w drugim drugie itd.

Zdefiniujemy teraz zmienną tymczasową  najmniejszyIndeks. Ma ona wskazywać najmniejszy odnaleziony element; wstępnie przypiszemy jej wartość i. Zrobimy tak, ponieważ najmniejsza liczba od razu może znajdować się w miejscu wskazywanym przez zmienną i (w przypadku omówionej wcześniej przykładowej tablicy liczba 5 była tam, gdzie powinna zostać umieszczona).

Pora uruchomić pętlę wewnętrzną. Posłuży ona do odnalezienia najmniejszej liczby w nieposortowanej jeszcze części tablicy. Poszukiwania zaczną się od elementu o indeksie i + 1:

Linia 1. zbior otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze n. Linia 3. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj. Linia 4. najmniejszyIndeks znak równości i. Linia 6. dla j znak równości i plus 1 przecinek i plus 2 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły wykonuj.

Aby znaleźć najmniejszy element, musimy porównać każdy obiekt w nieposortowanej części tablicy z najmniejszą odszukaną dotychczas liczbą:

Linia 1. zbior otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze n. Linia 3. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj. Linia 4. najmniejszyIndeks znak równości i. Linia 6. dla j znak równości i plus 1 przecinek i plus 2 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj. Linia 7. jeżeli zbior otwórz nawias kwadratowy j zamknij nawias kwadratowy otwórz nawias ostrokątny zbior otwórz nawias kwadratowy najmniejszyIndeks zamknij nawias kwadratowy to. Linia 8. najmniejszyIndeks znak równości j.

Jeżeli okaże się, że sprawdzany właśnie element jest jeszcze mniejszy, uznajemy go za najmniejszą obecnie liczbę. Przenosimy ją na miejsce wskazane przez zmienną i. Oto gotowy algorytm zapisany w pseudokodzie:

Linia 1. zbior otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości tablica o rozmiarze n. Linia 3. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj. Linia 4. najmniejszyIndeks znak równości i. Linia 6. dla j znak równości i plus 1 przecinek i plus 2 przecinek kropka kropka kropka przecinek długość otwórz nawias okrągły zbior zamknij nawias okrągły minus 1 wykonuj. Linia 7. jeżeli zbior otwórz nawias kwadratowy j zamknij nawias kwadratowy otwórz nawias ostrokątny zbior otwórz nawias kwadratowy najmniejszyIndeks zamknij nawias kwadratowy to. Linia 8. najmniejszyIndeks znak równości j. Linia 10. zamienMiejscami otwórz nawias okrągły zbior otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek zbior otwórz nawias kwadratowy najmniejszyIndeks zamknij nawias kwadratowy zamknij nawias okrągły.

Gdybyśmy chcieli natomiast posortować zbiór w porządku malejącym, należałoby wyszukiwać największe liczby w nieposortowanej części zbioru.

Słownik

algorytmy niestabilne
algorytmy niestabilne

algorytmy, w których elementy o równej wartości nie występują po posortowaniu w tej samej kolejności jaką miały w zbiorze nieposortowanym

algorytmy stabilne
algorytmy stabilne

w przypadku algorytmów stabilnych w uporządkowanej tablicy nie zmienia się kolejność elementów o tych samych wartościach klucza – przykładowo, gdy w tablicy znajdą się obok siebie dwie liczby o wartości 6, to nie zostaną one zamienione miejscami

sortowanie szybkie
sortowanie szybkie

algorytm rekurencyjny wynaleziony w 1962 r. przez brytyjskiego informatyka Tony'ego Hoare'a; opiera się na zasadzie dziel i zwyciężaj

wyszukiwanie binarne
wyszukiwanie binarne

metoda odnajdowania elementów w uporządkowanych zbiorach; polega ona na wielokrotnym dzieleniu przeszukiwanego zbioru na dwie części i porównywania wartości szukanej z elementem znajdującym się w środku dzielonego obszaru

zagnieżdżona pętla
zagnieżdżona pętla

pętla działająca wewnątrz innej pętli