Implementacja algorytmu sortowania przez wstawianie w języku C++
1
Problem 1
Napisz program sortujący niemalejąco tablicę n liczb całkowitych. Wykorzystaj metodę sortowania przez wstawianie. Funkcja powinna sortować wejściową tablicę w miejscusortowanie w miejscuw miejscu. Przetestuj rozwiązanie dla danych:
Linia 1. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy.
Linia 2. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły.
Specyfikacja problemu:
Dane:
n – liczba naturalna
tab – tablica zawierająca n liczb całkowitych
Wynik:
posortowana niemalejąco tablica n liczb całkowitych tab
R1RP3GvjtdTAX
Polecenie 1
Porównaj swoje rozwiązanie z przedstawionym poniżej.
Naszym zadaniem jest napisanie programu, który posortuje podaną przez użytkownika tablicę n liczb naturalnych, używając algorytmu sortowania przez wstawianie.
Załączamy niezbędną bibliotekę i zapisujemy funkcję main().
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. zamknij nawias klamrowy.
Tworzymy cztery zmienne. Pierwsza z nich to zmienna tab, która jest tablicą przechowującą n liczb całkowitych. Druga to zmienna n przechowująca rozmiar tablicy tab. Kolejne dwie zmienne to zmienne pomocnicze pom oraz j.
W zmiennej pom będzie tymczasowo przechowywany analizowany element tablicy.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. zamknij nawias klamrowy.
Aby posortować tablicę, konieczne jest przeiterowanie po jej elementach. W tym celu zapiszemy pętlę for, która wykona się o jeden raz mniej niż wynosi liczba elementów do posortowania. Zatem początkowa wartość zmiennej i wynosi 1. Pętla for wykonuje się, dopóki nie zostaną posortowane wszystkie elementy tablicy (czyli i < n).
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. for otwórz nawias okrągły int i znak równości 1 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 13. zamknij nawias klamrowy.
Linia 15. zamknij nawias klamrowy.
W pętli for zmiennej pom przypiszemy wartość elementu tablicy tab o indeksie i, natomiast wartość zmiennej j ustawimy na i - 1.
W zmiennej j będziemy przechowywać indeksy poszczególnych elementów znajdujących się w lewej części tablicy (czyli tych, które porównujemy z elementem przechowywanym w zmiennej pom).
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. for otwórz nawias okrągły int i znak równości 1 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 13. pom znak równości tab otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 14. j znak równości i minus 1 średnik.
Linia 16. zamknij nawias klamrowy.
Linia 18. zamknij nawias klamrowy.
Następnie definiujemy pętlę wewnętrzną while, która będzie wykonywana, dopóki spełnione będą naraz dwa warunki (warunki połączone operatorem logicznym &&).
Pierwszy warunek to j >= 0. Oznacza porównanie wartości elementów wszystkich tablicy z wartością przechowywaną przez zmienną pom.
W momencie, gdy warunek nie będzie już spełniony (j < 0), będzie to oznaczać, że każda liczba w posortowanej części tablicy została porównana z wartością zmiennej pom i była od niej mniejsza, czyli dotarliśmy na początek tablicy.
Drugi warunek (tab[j] > pom) sprawdza, czy element tablicy tab o indeksie j jest większy od elementu, którego wartość jest przechowywana w zmiennej pom. Jeśli warunki są spełnione, wykonywane jest przesunięcie elementu na miejsce j + 1.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. for otwórz nawias okrągły int i znak równości 1 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 13. pom znak równości tab otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 14. j znak równości i minus 1 średnik.
Linia 16. while otwórz nawias okrągły j zamknij nawias ostrokątny znak równości 0 ampersant ampersant tablica otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias ostrokątny a zamknij nawias okrągły otwórz nawias klamrowy.
Linia 18. zamknij nawias klamrowy.
Linia 20. zamknij nawias klamrowy.
Linia 22. zamknij nawias klamrowy.
W pętli while przypisujemy elementowi tablicy tab o indeksie j + 1 wartość elementu o indeksie j. Wykonujemy tę operację, by mieć możliwość zapisania wartości wstawianego elementu do części posortowanej, nie tracąc danych. Pętla jest wykonywana do momentu odnalezienia odpowiedniego miejsca w tablicy dla wstawianego elementu lub do momentu, gdy natrafimy na początek tablicy (czyli j = 0).
Zmniejszamy wartość zmiennej j o jeden i przechodzimy do ponownego sprawdzenia warunku pętli.
Ostatnią operacją wykonywaną w pętli for jest podstawienie w miejsce zmiennej zapisanej pod indeksem j + 1 wartości zmiennej pomocniczej pom. W ten sposób wstawiamy obecnie sprawdzaną liczbę na odpowiednie miejsce.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. for otwórz nawias okrągły int i znak równości 1 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 13. pom znak równości tab otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 14. j znak równości i minus 1 średnik.
Linia 16. while otwórz nawias okrągły j zamknij nawias ostrokątny znak równości 0 ampersant ampersant tab otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias ostrokątny pom zamknij nawias okrągły otwórz nawias klamrowy.
Linia 17. tab otwórz nawias kwadratowy j plus 1 zamknij nawias kwadratowy znak równości tab otwórz nawias kwadratowy j zamknij nawias kwadratowy średnik.
Linia 18. minus minus j średnik.
Linia 19. zamknij nawias klamrowy.
Linia 20. tab otwórz nawias kwadratowy j plus 1 zamknij nawias kwadratowy znak równości pom średnik.
Linia 21. zamknij nawias klamrowy.
Linia 23. zamknij nawias klamrowy.
Tym samym posortowaliśmy tablicę liczb przez wstawianie. Teraz pozostaje wypisać posortowaną tablicę za pomocą pętli for.
Oto kod całego programu:
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. using namespace std średnik.
Linia 4. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 6. int tab otwórz nawias kwadratowy zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 15 przecinek 9 przecinek 7 przecinek minus 1 przecinek 1 przecinek 2 przecinek 3 przecinek 4 przecinek 8 przecinek 5 przecinek 7 przecinek 3 przecinek 3 przecinek 0 przecinek minus 3 zamknij nawias klamrowy średnik.
Linia 7. int n znak równości sizeof otwórz nawias okrągły tab zamknij nawias okrągły prawy ukośnik sizeof otwórz nawias okrągły tab otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 8. int pom średnik.
Linia 9. int j średnik.
Linia 11. for otwórz nawias okrągły int i znak równości 1 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 13. pom znak równości tab otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 14. j znak równości i minus 1 średnik.
Linia 16. while otwórz nawias okrągły j zamknij nawias ostrokątny znak równości 0 ampersant ampersant tab otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias ostrokątny pom zamknij nawias okrągły otwórz nawias klamrowy.
Linia 17. tab otwórz nawias kwadratowy j plus 1 zamknij nawias kwadratowy znak równości tab otwórz nawias kwadratowy j zamknij nawias kwadratowy średnik.
Linia 18. minus minus j średnik.
Linia 19. zamknij nawias klamrowy.
Linia 20. tab otwórz nawias kwadratowy j plus 1 zamknij nawias kwadratowy znak równości pom średnik.
Linia 21. zamknij nawias klamrowy.
Linia 23. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny n średnik i plus plus zamknij nawias okrągły.
Linia 24. cout otwórz nawias ostrokątny otwórz nawias ostrokątny tab otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów cudzysłów średnik.
Linia 25. zamknij nawias klamrowy.
Przetestujmy działanie programu dla przykładowych danych.
Wynik działania programu:
Linia 1. minus 3 minus 1 0 1 2 3 3 3 4 5 7 7 8 9 15.
Porównania
Liczba potrzebnych porównań elementów tablicy jest wyrażona wzorami:
przypadek optymistyczny: ,
przypadek pesymistyczny: .
Uwaga! Dwa porównania na początku pętli while liczymy jako jedno.
Już wiesz
Złożoność czasowa algorytmu dla przypadku typowego to .
W tabeli przedstawiono porównania.
n
optymistyczna liczba porównań
pesymistyczna liczba porównań
20
19
190
30
29
435
40
39
780
50
49
1225
60
59
1770
70
69
2415
80
79
3160
90
89
4005
100
99
4950
W tabeli przedstawiono przestawienia.
n
optymistyczna liczba przestawień
pesymistyczna liczba przestawień
20
19
209
30
29
464
40
39
819
50
49
1247
60
59
1829
70
69
2484
80
79
3239
90
89
4094
100
99
5049
RyflWAEXWWCOg
Słownik
przypadek optymistyczny
przypadek optymistyczny
przypadek, w którym podczas sortowania zostanie wykonana najmniejsza możliwa liczba operacji; tablica uporządkowana w oczekiwanej kolejności - czyli dla sortowania w porządku rosnącym będzie to np. tablica {2, 3, 4, 5}
przypadek pesymistyczny
przypadek pesymistyczny
przypadek, w którym podczas sortowania zostanie wykonana największa możliwa liczba operacji; tablica uporządkowana w kolejności odwrotnej od oczekiwanej - czyli dla sortowania w porządku rosnącym będzie to np. tablica {5, 4, 3, 2, 1 }
sortowanie w miejscu
sortowanie w miejscu
inaczej in situ; sortowanie, w którym niezależnie od rozmiaru danych wejściowych potrzebna jest stała ilość pamięci komputera