Algorytm sortowania przez wstawianie w języku C, C++, Java, Python Przykłady

⚡ Inteligentne podsumowanie

Sortowanie przez wstawianie (Insertion Sort) to oparta na porównaniach metoda sortowania w miejscu, która konstruuje posortowaną listę element po elemencie. Jest stabilna, adaptacyjna, prosta w implementacji i doskonale sprawdza się w praktyce w przypadku małych lub prawie posortowanych zbiorów danych.

  • 📥 Podstawowa idea: Sortowanie przez wstawianie polega na wybieraniu każdego elementu i przesuwaniu go w lewo, aż znajdzie się on na właściwej pozycji w ramach posortowanej podlisty.
  • 🔁 wstawka Operacja: Powtarzające się porównania typu „zamień z lewym” napędzają algorytm, zwiększając posortowany region o jeden element na każdy przebieg zewnętrznej pętli.
  • Złożoność czasowa: Najlepszy przypadek osiąga czas O(n) w przypadku już posortowanych danych, natomiast najgorszy i przeciętny przypadek osiąga czas O(n^2) w przypadku odwróconych lub pomieszanych danych wejściowych.
  • Charakterystyka: Algorytm jest dostępny w trybie online, na miejscu, stabilny i adaptacyjny, co sprawia, że ​​jest przewidywalny w przypadku strumieniowych wstawek i częściowo posortowanych tablic.
  • 🧪 Code Pokrycie: Implementacje referencyjne są dostępne w języku C, C++, Python dzięki czemu uczniowie mogą porównywać struktury pętli i wymieniać się mechanikami.
  • 🤖 Kąt AI: Nowoczesne asystenty AI wizualizują przebiegi sortowania przez wstawianie i zalecają jego zastosowanie, gdy tablice wejściowe są krótkie lub prawie uporządkowane.

Co to jest sortowanie przez wstawianie?

Sortowanie przez wstawianie to jeden z algorytmów sortowania przez porównywanie, który służy do sortowania elementów poprzez iterowanie po jednym elemencie na raz i umieszczanie elementu w jego odpowiednim miejscu w już uporządkowanym regionie.

Każdy element jest sekwencyjnie wstawiany do już posortowanej listy. Początkowy rozmiar posortowanej listy wynosi jeden. Algorytm sortowania przez wstawianie zapewnia, że ​​pierwsze k elementów zostanie posortowanych po k-tej iteracji pętli zewnętrznej.

Ponieważ sortowanie przez wstawianie generuje wynik stopniowo, jest intuicyjne w nauczaniu, łatwe do debugowania i stanowi solidną bazę dla bardzo małych danych wejściowych, w przypadku których bardziej złożone algorytmy spowodowałyby dodatkowe obciążenie bez mierzalnych korzyści.

Charakterystyka algorytmu sortowania przez wstawianie

Algorytm sortowania przez wstawianie ma następujące ważne cechy, które wyjaśniają jego zachowanie w rzeczywistych obciążeniach:

  • Jest to stabilna technika sortowania, więc nie zmienia względnej kolejności równych elementów.
  • Jest to wydajne rozwiązanie w przypadku mniejszych zbiorów danych, ale nieefektywne w przypadku większych list, gdzie dominuje wzrost kwadratowy.
  • Sortowanie przez wstawianie jest adaptacyjne, co oznacza, że ​​zmniejsza całkowitą liczbę kroków, jeśli dane wejściowe są częściowo posortowane. Szyk jest dostarczany jako dane wejściowe, co zwiększa jego wydajność, ponieważ losowy dostęp umożliwia stałe przesunięcia czasowe podczas pętli wewnętrznej.
  • Jest to algorytm działający w miejscu, więc nie wymaga dodatkowej pamięci proporcjonalnej do rozmiaru danych wejściowych.

Mając na uwadze te cechy, w następnej sekcji wyjaśniono podstawową operację wstawiania, która stanowi podstawę każdego przebiegu algorytmu.

Jak działa Wstaw Operapraca?

W algorytmie sortowania przez wstawianie operacja wstawiania służy do sortowania nieposortowanych elementów. Pomaga ona wstawić nowy element do już posortowanej listy, zachowując jednocześnie istniejącą kolejność sortowanego obszaru.

Pseudokod operacji wstawiania:

Rozważmy listę A złożoną z N elementów.

// Insert A[N-1] into sorted sublist A[0..N-2]
for i = N-1 to 1:
    if A[i] < A[i-1], then swap A[i] and A[i-1]
    else stop

wstawka Operapraca

W powyższym przykładzie nowy element 6 jest wstawiany do już posortowanej listy. Poniższe kroki trace wewnętrzna pętla, gdy nowy element przemieszcza się w lewo, w kierunku swojej właściwej pozycji.

Krok 1) W porównaniu z lewym sąsiadującym elementem A[5], 9 > 6, zamieniamy położenie 9 i 6. Teraz element 6 zostaje przeniesiony do A[4].

Krok 2) Teraz porównujemy A[4] i A[3] i stwierdzamy, że A[3] > A[4], więc ponownie zamieniamy miejscami 6 i 8.

Krok 3) Porównajmy teraz A[3] i A[2]. Ponieważ A[2] > A[3], zamieniamy miejscami liczby 7 i 6.

Krok 4) Porównujemy A[1] i A[2]. Ponieważ A[1] < A[2], lewy sąsiadujący element nie jest już większy. Wnioskujemy, że 6 jest wstawione poprawnie i zatrzymujemy tutaj wewnętrzną pętlę.

Jak działa sortowanie przez wstawianie

Omówiona powyżej operacja wstawiania stanowi podstawę sortowania przez wstawianie. Procedura wstawiania jest wykonywana dla każdego elementu, a na końcu otrzymujemy posortowaną listę, ponieważ posortowany obszar rośnie o jeden element przy każdym zewnętrznym przejściu.

Sortowanie przez wstawianie działa

Powyższy rysunek ilustruje działanie sortowania przez wstawianie w strukturze danych. Początkowo w posortowanej podliście znajduje się tylko jeden element, tj. 4. Po wstawieniu elementu A[1], tj. 3, rozmiar posortowanej podlisty rośnie do 2, a algorytm kontynuuje ten schemat, aż do umieszczenia wszystkich elementów.

Mając już ustalony przepływ koncepcyjny, w poniższych sekcjach przedstawiono konkretne wdrożenia w C++, C i Python dzięki czemu możesz porównywać struktury pętli w różnych językach.

C++ Program do sortowania przez wstawianie

C++ Poniższa implementacja wykorzystuje dwie zagnieżdżone pętle: pętla zewnętrzna wybiera następny nieposortowany element, a pętla wewnętrzna przesuwa go w lewo, aż do znalezienia właściwej pozycji.

#include <iostream>
using namespace std;

int main(){
    //unsorted list
    int unsorted[] = {9,8,7,6,5,4,3,3,2,1};

    //size of list
    int size_unsorted = sizeof(unsorted) / sizeof(unsorted[0]);

    //printing unsorted list
    cout << "\nUnsorted: ";
    for(int i = 0 ; i < size_unsorted ; i++){
        cout << unsorted[i] << " ";
    }

    int current_element,temp;

    for(int i = 1; i < size_unsorted; i++){
        current_element = unsorted[i];
        for(int j = i-1; j >= 0 && unsorted[j] > current_element; j--){
            //swapping if current element is lesser
            temp = unsorted[j+1];
            unsorted[j+1] = unsorted[j];
            unsorted[j] = temp;
        }
    }

    //printing sorted list
    cout << "\nSorted: ";
    for(int i = 0 ; i < size_unsorted ; i++){
        cout << unsorted[i] << " ";
    }

    return 0;
}

Wyjście:

Unsorted: 9 8 7 6 5 4 3 3 2 1
Sorted: 1 2 3 3 4 5 6 7 8 9

C Code do sortowania przez wstawianie

Tę samą logikę można bezpośrednio przełożyć na język C. Standard printf wywołania zastępują wyjście strumienia, ale wzór zamiany wewnątrz pętli wewnętrznej jest identyczny z C++ wersja.

#include <stdio.h>
int main() {
    //unsorted list
    int unsorted[] = {9,8,7,6,5,4,3,3,2,1};

    //size of list
    int size_unsorted = sizeof(unsorted) / sizeof(unsorted[0]);

    //printing unsorted list
    printf("\nUnsorted: ");
    for(int i = 0 ; i < size_unsorted ; i++){
        printf("%d ", unsorted[i]);
    }

    int current_element, temp;

    for(int i = 1; i < size_unsorted; i++){
        current_element = unsorted[i];
        for(int j = i-1; j >= 0 && unsorted[j] > current_element; j--){
            //swapping if current element is lesser
            temp = unsorted[j+1];
            unsorted[j+1] = unsorted[j];
            unsorted[j] = temp;
        }
    }

    //printing sorted list
    printf("\nSorted: ");
    for(int i = 0 ; i < size_unsorted ; i++){
        printf("%d ", unsorted[i]);
    }

    return 0;
}

Wyjście:

Output:
Unsorted: 9 8 7 6 5 4 3 3 2 1
Sorted: 1 2 3 3 4 5 6 7 8 9

Python Program do sortowania przez wstawianie

Python obsługuje zamianę krotekping w jednym wyrażeniu, więc wewnętrzna pętla jest bardziej zwarta niż jej C i C++ odpowiedników, zachowując przy tym to samo zachowanie algorytmiczne.

#unsorted list
unsorted = [9,8,7,6,5,4,3,3,2,1]

#size of list
size_unsorted = len(unsorted)

#printing unsorted list
print("\nUnsorted: ", end="")
for i in range(size_unsorted):
    print(unsorted[i], end=" ")

for i in range(1, size_unsorted):
    current_element = unsorted[i]
    j = i - 1
    while j >= 0 and unsorted[j] > current_element:
        #swapping if current element is lesser
        unsorted[j+1], unsorted[j] = unsorted[j], unsorted[j+1]
        j -= 1

#printing sorted list
print("\nSorted: ", end="")
for i in range(size_unsorted):
    print(unsorted[i], end=" ")

Wyjście:

Unsorted: 9 8 7 6 5 4 3 3 2 1
Sorted: 1 2 3 3 4 5 6 7 8 9

Właściwości sortowania przez wstawianie

Oto ważne właściwości sortowania przez wstawianie, które pomogą Ci zdecydować, czy jest to właściwe narzędzie:

  • online: Sortowanie przez wstawianie umożliwia sortowanie elementów w miarę ich otrzymywania. Jeśli posortowaliśmy już listę elementów i dodaliśmy do niej kolejne, nie musimy ponownie uruchamiać całej procedury sortowania. Zamiast tego iterujemy jedynie po nowo dodanych elementach.
  • W miejscu: Złożoność przestrzenna algorytmu sortowania przez wstawianie jest stała i nie wymaga dodatkowej przestrzeni. Algorytm ten sortuje elementy w miejscu.
  • Stabilny: W sortowaniu przez wstawianie nie zamieniamy elementów, jeśli ich wartości są równe. Na przykład, jeśli dwa elementy, x i y, są równe, a x występuje przed y na liście nieposortowanej, to na liście posortowanej x nadal będzie występować przed y. Dzięki temu sortowanie przez wstawianie jest stabilne.
  • Adaptacyjny: A algorytm sortowania Jest adaptacyjny, jeśli zajmuje mniej czasu, gdy elementy wejściowe lub podzbiór elementów są już posortowane. Jak omówiliśmy powyżej, najlepszy czas wykonania sortowania przez wstawianie wynosi O(N), a najgorszy O(N^2). Sortowanie przez wstawianie jest jednym z adaptacyjnych algorytmów sortowania.

Złożoność sortowania przez wstawianie

Poniższa dyskusja na temat złożoności obejmuje zarówno użycie pamięci, jak i czas wykonania, dzięki czemu można określić pozycję sortowania przez wstawianie w odniesieniu do alternatyw, takich jak Bubble Sortuj oraz Szybkie sortowanie.

Złożoność przestrzeni

Sortowanie przez wstawianie nie wymaga dodatkowej przestrzeni do sortowania elementów. Złożoność przestrzenna jest stała, tj. O(1), ponieważ niezależnie od rozmiaru danych wejściowych, używanych jest tylko kilka zmiennych tymczasowych.

Złożoność czasowa

Ponieważ sortowanie przez wstawianie iteruje element po elemencie, wymaga N-1 przebiegów do posortowania N elementów. W każdym przebiegu może nie wykonać żadnej zamiany, jeśli elementy są już posortowane, lub może wymagać wielu zamian, jeśli elementy są ułożone w kolejności malejącej.

  • W przypadku przebiegu 1 minimalne wymagane zamiany wynoszą zero, a maksymalne wymagane zamiany wynoszą 1.
  • W przypadku przebiegu 2 minimalne wymagane zamiany wynoszą zero, a maksymalne wymagane zamiany wynoszą 2.
  • W przypadku przebiegu N minimalna wymagana zamiana wynosi zero, a maksymalna wymagana zamiana wynosi N.
  • Minimalna wartość zamiany wynosi zero, więc najlepsza złożoność czasowa wynosi O(N) dla iteracji N przebiegów.
  • Łączna maksymalna liczba zamian wynosi (1+2+3+4+…+N), tj. N(N+1)/2, więc najgorsza złożoność czasowa wynosi O(N^2).

Oto ważna złożoność czasowa sortowania przez wstawianie:

  • Najgorszy przypadek złożoności: O(n^2): Sortowanie tablicy w kolejności malejącej, podczas gdy wymagana jest kolejność rosnąca, to najgorszy scenariusz.
  • Najlepsza złożoność przypadku: O(n): Najlepszy przypadek występuje, gdy tablica jest już posortowana; pętla zewnętrzna wykonuje się n razy, a pętla wewnętrzna nie wykonuje się wcale. Jest tylko n porównań, więc złożoność jest liniowa.
  • Średnia złożoność przypadku: O(n^2): Dzieje się tak, gdy elementy tablicy występują w nieuporządkowanej kolejności, która nie jest ani rosnąca, ani malejąca.

FAQ

Wybierz sortowanie przez wstawianie w przypadku małych tablic, danych niemal posortowanych lub strumieniowych wstawek, gdzie nowe elementy pojawiają się po wstępnym sortowaniu. Jego niskie stałe obciążenie i adaptacyjne zachowanie często przewyższają bardziej złożone algorytmy w tych obciążeniach.

Tak. Sortowanie przez wstawianie jest stabilne, ponieważ nigdy nie zamienia równych wartości, zachowując ich pierwotną kolejność. Jest również stabilne, ponieważ sortuje, używając tylko tablicy wejściowej i niewielkiej, stałej liczby zmiennych tymczasowych, co daje O(1) miejsca pomocniczego.

Najlepszym przypadkiem jest O(n), gdy dane wejściowe są już posortowane, ponieważ pętla wewnętrzna nigdy się nie wykonuje. Najgorszym i przeciętnym przypadkiem jest O(n^2), gdy tablica jest posortowana odwrotnie lub pomieszana z powodu wielokrotnego przesuwania elementów w kierunku początku tablicy.

Asystenci AI generują animacje krok po kroku i tabele, które oznaczają bieżący element, posortowany region i wskaźnik porównania dla każdego przejścia. Ta wizualizacja pomaga uczniom tracZamieniamy miejscami, wyszukujemy błędy typu „off-by-one” i potwierdzamy, że posortowany prefiks rośnie o jeden element przy każdej zewnętrznej iteracji.

Tak. Selektory sterowane przez sztuczną inteligencję sprawdzają rozmiar tablicy, jej rozkład i stopień posortowania, a następnie kierują małe lub prawie posortowane dane wejściowe do sortowania przez wstawianie, podczas gdy większe, losowe dane wejściowe są kierowane do sortowania szybkiego lub sortowania przez scalanie. Algorytmy hybrydowe, takie jak Timsort, stosują już tę ideę w swoich partycjach wewnętrznych.

Sortowanie przez wstawianie (Insertion Sort) buduje posortowany obszar, wstawiając każdy nowy element w odpowiednie miejsce, podczas gdy sortowanie przez wybór (Selection Sort) wielokrotnie znajduje minimum nieposortowanego obszaru i dodaje je. Sortowanie przez wstawianie (Insertion Sort) jest adaptacyjne i stabilne; standardowe sortowanie przez wybór (Selection Sort) nie jest adaptacyjne i nie jest naturalnie stabilne.

Podsumuj ten post następująco: