- 27 kwietnia 2024
- Posted by: Daria
- Category: Baza wiedzy
Algorytmy sortujące okazują się fundamentem jeśli chodzi o naukę programowania. Pozwalają opanować wiele ciekawych rozwiązań stosowanych w kodach aplikacji. Jednym z podstawowych algorytmów sortujących, który każdy uczeń informatyki czy uczestnik korepetycji z informatyki powinien znać, jest sortowanie przez wstawianie.
Co to jest sortowanie przez wstawianie?
Sortowanie przez wstawianie (insertion sort) to algorytm wstawiający kolejne elementy na odpowiednie miejsca do posortowanej części zbioru danych. Pierwszy element jest uznawany za uporządkowany, następnie bierze się pod uwagę drugi i ustawia się go przed lub po pierwszej wartości. Każdy kolejny cykl wygląda podobnie, następne elementy są porównywane z uporządkowanymi wartościami i wstawiane na odpowiednie miejsca. Okazuje się efektywny dla niewielkiej ilości danych. Co ciekawe, jest wykorzystywany jako część zaawansowanego algorytmu sortującego Shella.
Na czym polega sortowanie przez wstawianie – Przykład
Tak naprawdę sortowanie przez wstawianie to intuicyjna metoda sortowania. Zasada działania tego algorytmu znajduje odzwierciedlenie przy sortowaniu kart, więc zdołasz ją szybko zrozumieć.
Poniżej znajdziesz proces sortowania przez wstawianie tablicy o ilości elementów n = 5. Początkowy zbiór danych prezentuje się tak:
4 2 5 1 3
Z automatu uznaje się pierwszą liczbę za posortowaną. Dlatego też sortowanie rozpoczyna się od drugiej wartości.
4 2 5 1 3
(4 2) 5 1 3 – nawiasy oznaczają porównywane liczby
Druga liczba jest porównywana z pierwszą (a więc z częścią posortowaną), a skoro 2 jest mniejsze od 4, to następuje zamiana miejsc (sortujemy rosnąco).
2 4 5 1 3
2 4 5 1 3
2 (4 5) 1 3
2 4 5 1 3
Kolejny cykl porównywania, bierze pod uwagę liczbę 5 i porównuje ją z częścią posortowaną, w tym przypadku z 4. Jako, że 5 jest większe od 4, obie liczby pozostają na swoim miejscu.
2 4 5 1 3
2 4 (5 1) 3
W tym momencie następuje kolejny cykl i bierze się pod uwagę następny nieposortowany element, a więc 1. Po porównaniu z najbliższym elementem z części posortowanej, okazuje się, że 1 jest mniejsze od 5. Dlatego następuje zamiana ich miejsc.
2 4 1 5 3
2 (4 1) 5 3
2 1 4 5 3
Teraz porównuje się 1 z liczbą 4. Ponownie okazuje się, że wartość jest mniejsza, więc ulegają one zamianie.
2 1 4 5 3
(2 1) 4 5 3
1 2 4 5 3
Kolejne porównanie, czyli 1 z wartością 2. Liczba jest mniejsza, także następuje zamiana. Skoro nie ma kolejnych liczb do porównania, następuje koniec tego cyklu.
1 2 4 5 3
1 2 4 (5 3)
1 2 4 3 5
Ostatni już cykl, bierze pod uwagę liczbę 3. Po porównaniu z wartością 5, okazuje się, że jest mniejsza, więc następuje zamiana.
1 2 4 3 5
1 2 (4 3) 5
1 2 3 4 5
Kolejne porównanie wskazuje, że 3 jest mniejsze od 4, także oznacza to kolejną zamianę liczb.
1 2 3 4 5
1 (2 3) 4 5
1 2 3 4 5
W tym momencie, algorytm porównuje 3 oraz 2, jako że liczba 3 jest większa, pozostaje ona na swoim miejscu. Sortowanie przez wstawianie jest w tym miejscu zakończone, po czterech cyklach (ilość cykli jest zawsze mniejsza o jeden od ilości sortowanych danych).
Jak widać proces sortowania jest prosty, możesz śmiało z niego korzystać w przypadku niewielkich zbiorów danych.
Ważne!
W przedstawionym tłumaczeniu oraz gifie przedstawiane jest uproszczenie dla łatwiejszego zrozumienia tego sortowania. W ramach kodu zapisuje się aktualnie zmienianą liczbę do dodatkowej zmiennej, a następnie sprawdza się czy jest mniejsza od poprzednich wartości (po lewej), dopiero gdy znajdzie się odpowiednie miejsce, wstawia się tam tę liczbę. Z kolei na gifie oraz przykładzie, liczba jest ciągle zamieniana z mniejszymi od niej. Zmniejsza się więc liczbę operacji (wartość jest zapisywana tylko raz, w miejsce w którym powinna być).
Zalety i wady – sortowanie przez wstawianie
Zrozumienie zalet oraz wad danego algorytmu, pozwala znacznie łatwiej określić jego użyteczność w ramach tworzonego kodu.
Zalety:
- Prostota – z łatwością go zrozumiesz i zaimplementujesz,
- Idealny do małych zbiorów danych – w przypadku niewielkiej ilości danych, jego wydajność jest wysoka,
- Stabilny – elementy o identycznej wartości, pozostają na swoich miejscach względem siebie.
Wady:
- Nie nadaje się do dużych zbiorów danych – jego wydajność wtedy zauważalnie spada.
Sortowanie przez wstawianie – Jak zrobić implementację algorytmu?
Utworzenie implementacji sortowania przez wstawianie nie jest trudne. Poniższe opisy pozwolą Ci zrozumieć w jaki sposób działa, dzięki czemu zastosowanie go w przypadku poszczególnych programów okaże się łatwiejsze.
Sortowanie przez wstawianie – Schemat blokowy i pseudokod
1 2 3 4 5 6 7 8 | funkcja sortowanie_przez_wstawianie(tablica, n) Dla i = 2, 3, 4, … n wykonuj temp ← tablica[i] j ← i - 1 Dopóki j > 0 i tablica[j] > temp wykonuj tablica[j + 1] ← tablica[j] j ← j - 1 tablica[j + 1] ← temp |
Opis sortowania przez wstawianie – Pseudokod
- 1 linia – Rozpoczęcie funkcji i przyjęcie argumentów tablica (lista danych) oraz n (ilość sortowanych elementów).
- 2 linia – Pętla iteruje przez elementy tablicy, zaczynając od drugiego elementu (o indeksie 2) aż do ostatniego elementu (o indeksie n).
- 3 linia – Aktualny element tablicy, o indeksie i, jest zapisywany w zmiennej tymczasowej temp.
- 4 linia – Zmienna j przyjmuje wartość (i – 1), którą wykorzystamy do porównania w linii 5 (w pętli dopóki, czyli odpowiedniku while) aktualnego elementu z poprzednim.
- 5 linia – Pętla dopóki (while) sprawdza, czy indeks j jest większy od zera oraz czy wartość tablicy[j] jest większa niż wartość temp.
- 6 linia – Jeśli warunki są spełnione, to przesuwamy element w tablicy o jedno miejsce w prawo, aby zrobić miejsce dla elementu temp.
- 7 linia – Zmniejszamy wartość j o 1, aby porównać temp z poprzednim elementem.
- 8 linia – Po zakończeniu pętli dopóki (while), aktualny element temp jest wstawiany na właściwe miejsce w posortowanej części tablicy.
Sortowanie przez wstawianie – Python, C++ i Java
Sortowanie przez wstawianie – Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def SortowaniePrzezWstawianie(tab, n): # Można też usunąć argument n i sprawdzić wewnątrz funkcji jaką długość posiada lista tab for i in range(1, n): temp = tab[i] j = i - 1 # Przesuwanie elementów większych od temp, aby zrobić miejsce dla temp while j >= 0 and tab[j] > temp: tab[j + 1] = tab[j] j -= 1 # Wstawienie temp na odpowiednie miejsce w posortowanej części listy (tablicy) tab[j + 1] = temp # Deklaracja tablicy tab = [5, 3, 8, 2, 1, 7] n = len(tab) # Sprawdzanie ilości elementów w liście (tablicy) - len zwraca ilość elementów w liście (tablicy) # Wywołanie funkcji sortującej SortowaniePrzezWstawianie(tab, n) # Wyświetlanie posortowanej listy (tablicy) print("Posortowana tablica:", end=" ") for element in tab: print(element, end=" ") |
Sortowanie przez wstawianie – C++
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 35 36 | #include <iostream> using namespace std; // Funkcja sortująca void SortowaniePrzezWstawianie(int tab[], int n) { int i, j, temp; for (i = 1; i < n; i++) { temp = tab[i]; j = i - 1; // Przesuwanie elementów większych od temp, aby zrobić miejsce dla temp while (j >= 0 && tab[j] > temp) { tab[j + 1] = tab[j]; j--; } // Wstawienie temp na odpowiednie miejsce w posortowanej części tablicy tab[j + 1] = temp; } } int main() { // Deklaracja tablicy int tab[] = {5, 3, 8, 2, 1, 7}; int n = sizeof(tab) / sizeof(tab[0]); // Sprawdzanie ilości elementów w tablicy, sizeof zwraca wielkość pamięci danego elementu, najpierw całej tablicy, a następnie dzieli się wielkość całej pamięci przez wielkość pojedynczego elementu, co zwraca ilość elementów // Wywołanie funkcji sortującej SortowaniePrzezWstawianie(tab, n); // Wyświetlanie posortowanej tablicy cout << "Posortowana tablica: "; for (int i = 0; i < n; i++) { cout << tab[i] << " "; } return 0; } |
Sortowanie przez wstawianie – Java
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 | public class Main { // Funkcja sortująca przez wstawianie static void SortowaniePrzezWstawianie(int[] tab, int n) { int i, j, temp; for (i = 1; i < n; i++) { temp = tab[i]; j = i - 1; // Przesuwanie elementów większych od temp, aby zrobić miejsce dla temp while (j >= 0 && tab[j] > temp) { tab[j + 1] = tab[j]; j--; } // Wstawienie temp na odpowiednie miejsce w posortowanej części tablicy tab[j + 1] = temp; } } public static void main(String[] args) { // Deklaracja tablicy int[] tab = {5, 3, 8, 2, 1, 7}; int n = tab.length; // Sprawdzanie ilości elementów w tablicy - funkcja length zwraca ilość elementów w tablicy // Wywołanie funkcji sortującej SortowaniePrzezWstawianie(tab, n); // Wyświetlanie posortowanej tablicy System.out.print("Posortowana tablica: "); for (int i = 0; i < n; i++) { System.out.print(tab[i] + " "); } } } |
Sortowanie przez wstawianie dla zaawansowanych – złożoność obliczeniowa
Złożoność algorytmu sortowanie przez wstawianie wynosi O(n2).
Wynika to ze względu na wstawienie dwóch pętli przechodzących po tablicy. Jednak warto zauważyć, że jest on częściej używany niż sortowanie bąbelkowe czy przez wybieranie. Dlaczego, skoro wszystkie trzy algorytmy mają podobną złożoność?
Otóż popatrz na sytuację, gdy nasza tablica przed wykonaniem algorytmu jest już poprawnie ułożona. Sortowanie przez wybieranie jak i sortowanie bąbelkowe będą w całości wykonywać obie pętle zawarte w ich kodzie, przez co układanie posortowanej już tablicy będzie miało nadal złożoność kwadratową. Aby temu zapobiec, należy umieścić w kodzie specjalne zabezpieczenie, które dla danych posortowanych nie wykona niepotrzebnych operacji.
Co w przypadku sortowania przez wstawianie? Łatwo zauważyć, że jeśli chcesz dla uogólnienia problemu uporządkować trzeci element z pierwszymi dwoma, to skoro tablica jest posortowana to pętla zatrzyma się po pierwszym porównaniu trzeciego elementu z drugim i nie będzie iść dalej w głąb tablicy. Co z tego wynika?
Jeśli każdy element w tablicy będziemy porównywać tylko raz z jego poprzednikiem to okaże się, że w takim przypadku będziemy mieli złożoność rzędu O(n) (czyli liniową).
Jest to diametralna różnica oraz przewaga sortowania przez wstawianie nad sortowaniem bąbelkowym i przez wybieranie. Co więcej, warto również wspomnieć, że ten algorytm jest też używany do przyspieszenia działania szybkiego sortowania. Gdy w tablicy jest mało elementów (z reguły określa się to na około 20) to wtedy zastępuje się sortowanie szybkie sortowaniem przez wstawianie, ponieważ działa szybciej, szczególnie w optymistycznym przypadku podania tablicy uporządkowanej lub prawie uporządkowanej zadziała najlepiej. Oczywiście istnieje także pesymistyczny przypadek, czyli podanie do sortowania elementów ułożonych malejąco.
Sortowanie przez wstawianie to z pewnością jeden z prostszych rodzajów algorytmów, który okazuje się idealny dla początkujących. Zrozumienie w jaki sposób działa pomaga szybciej opanować podobne rozwiązania, a przy tym jest wstępem do bardziej zaawansowanych algorytmów sortujących (np. shella). W przypadku małych zbiorów liczb to metoda z której warto skorzystać.
Najczęściej zadawane pytania o sortowanie przez wstawianie
Czy sortowanie przez wstawianie jest stabilne?
Tak, sortowanie przez wstawianie jest stabilne, więc identyczne wartości w zbiorze pozostają na swoich miejscach względem siebie.
Kiedy użyć sortowania przez wstawianie?
Przede wszystkim w momencie gdy lista (tablica) posiada niewielką ilość elementów. Wtedy można oczekiwać wysokiej wydajności po tym algorytmie. Dodatkowo też jeśli lista jest już w dużej mierze posortowana, warto użyć sortowania przez wstawianie, bo okaże się jeszcze efektywniejszy. Nie bez powodu ten algorytm jest stosowany jako część bardziej złożonych rozwiązań.
Czy sortowanie przez wstawianie może być zaimplementowane w sposób rekurencyjny?
Jak najbardziej jest to możliwe, zamiast pętli stosowana jest po prostu rekurencja. Każde wywołanie sortuje coraz mniejsze podlisty, jednak trzeba pamiętać o tym, że taki sposób wykonania tego algorytmu jest mało wydajny oraz wymaga dużej ilości pamięci.
Czy sortowanie przez wstawianie jest szybsze niż sortowanie bąbelkowe?
Zazwyczaj tak, z tego względu, że ten rodzaj sortowania wykonuje mniejszą liczbę operacji niż bąbelkowe. Dlatego sortowanie przez wstawianie okazuje się być praktyczniejsze w przypadku różnego rodzaju programów. Dodatkowo istnieje możliwość drobnej optymalizacji tego algorytmu. Chodzi tu o zastosowanie wyszukiwania binarnego zamiast iteracji po każdej posortowanej części. Dzięki temu ilość operacji zostanie zmniejszona, co oczywiście wpłynie pozytywnie na wydajność algorytmu.
Wpisy, które mogą Cię zainteresować: