Sortowanie Dane wejściowe: ciąg n-liczb (kluczy) (a 1, a 2, a 3,..., a n 1, a n ) Dane wyjściowe: permutacja ciągu wejściowego (a 1, a 2, a 3,..., a n 1, a n) taka, że a 1 a 2 a 3... a n 1 a n. Będziemy zakładać, że ciąg ten stanowią elementy tablicy A[1...n]. Zadanie 1 Przygotuj algorytm programu - sortowanie przez wstawianie. a) Przeanalizuj algorytm programu - sortowanie przez wstawianie. Schemat blokowy tego algorytmu: Dane wejściowe: tablica A[1...n], którą należy przesortować, Len([A]) oznacza liczbę elementów tablicy. i := 2; while i < Len([A]) + 1 do key := A[i]; j := i 1; while j > 0 and key < A[j] do A[j + 1] := A[j]; j := j 1; A[j + 1] := key; i := i + 1; Dane wyjściowe: przesortowana tablica A[n]. b) Niech A oznacza napis SORTOWANIE, Len[A] = 10. Podaj stan tablicy [A] po kolejnych wyjściach z pętli głównej. 1
i key j A[j] A 2 O 1 S SSRTOWANIE OSRTOWANIE 3 R 2 S ORRTOWANIE 1 O ORSTOWANIE 4 T 3 S ORSTOWANIE 5 O 4 T ORSTTWANIE 3 S ORSSTWANIE 2 R ORRSTWANIE 1 O OORSTWANIE 6 W 5 T OORSTWANIE 7 A AOORSTWNIE 8 N ANOORSTWIE 9 I AINOORSTWE 10 E AINOORSTWE c) Jaka jest złożoność tego algorytmu? Jak często ze sprawdzenia warunku j > 0 wyniknie, że j = 0?? Co najwyżej raz. w C# można zmienić kolejność sprawdzania while key < A[j] and j > 0 do Ile razy wykonywana jest operacja porównania? Jaka jest minimalna, a jaka maksymalna liczba przesunięć A[j + 1] A[j]? Czy algorytm jest stabilny? Rozwiązanie Złożoność obliczeniowa Pamięciowa algorytm sortuje w miejscu. Czasowa: Liczba porównań koszt pesymistyczny W (n) = n(n 1) 2 Liczba porównań koszt oczekiwany A(n) = n(n+1) 4 Liczba półzamian = Liczba porównań. Zalety Algorytm sortowanie przez wstawianie jest stabilny. d) Zaimplementuj ten algorytm w języku C# dla listy liczbowej. 2
e) Zaimplementuj w C# algorytm sortowania przez wstawianie ze strażnikiem: min := 1; for i := 2 to Len([A]) do if A[i] < A[min] then min := i; zamień(a[1], A[min]); for i := 2 to Len([A]) do key := A[i]; j := i 1; while key < A[j] do {A[1] strażnik} A[j + 1] := A[j]; j := j 1; A[j + 1] := key; 3
Zadanie 2 Sortowanie przez wstawianie z wyszukiwaniem binarnym. wazniak.mimuw.edu.pl W algorytmie sortowania przez wstawianie, jeden z kroków polega na wstawieniu elementu A[i] do uporządkowanego podciągu A[1,..., i 1]. Należy wyszukać największy taki indeks j i, taki że A[j 1] x = A[i]. Miejsce, w które należy wstawić element A[i], można znaleźć za pomocą wyszukiwania binarnego. Przygotuj algorytm takiego programu i przeanalizuj go na przykładzie listy [1, 6, 5, 7, 9, 6]. Rozwiązanie. Możliwe są dwa przypadki: 1. j<i A[j] x = A[i], czyli klucz x jest na właściwym miejscu 2. x < A[i 1]. W takim przypadku należy wyszukać binarnie największy taki indeks j < i, taki że A[j 1] x = A[i]. W przypadku konieczności zastosowania wyszukiwania binarnego x w liście A[0 : i] możliwe są przypadki: 1. x nie występuje na tej liście, należy znaleźć j < i, A[j 1] < x < A[j] 2. x występuje co najmniej raz na tej liście, należy znaleźć j < i, A[j 1] = x A[j] > x. Oznacza to, że powinien być zwracany prawy skrajny element lewej podlisty, a warunek porównania powinien być postaci if x <= A[k] then return k. l := 0; p := len(a) 1; while (l < p) do k := (l + p) div 2; if x > A[k] then l := k + 1; else p := k; ; if x = A[p] then p = p + 1 return p; W tym algorytmie liczbę wykonywanych porównań można wyznaczyć następująco: w iteracji o numerze i zewnętrznej pętli for wykonuje się co najwyżej log i porównań pomiędzy elementami sortowanego ciągu czyli złożoność obliczeniowa jest równa log i = n log n 2 log n + 1. W algorytmie tym, 4
liczba porównań została zmniejszona do liniowo-logarytmicznej, ale liczba przestawień elementów w tablicy, koniecznych do zrobienia tych miejsc, w dalszym ciągu jest w pesymistycznym przypadku kwadratowa. Ta obserwacja pokazuje, że do analizy złożoności algorytmu, dobór operacji dominujących jest kluczowy dla jakości tej analizy. Zadanie 3 Pokaż, że lg i = n lg n 2 lg n + 1. Rozwiązanie. Rozważmy sumę lg i. Niech p = lg n, p + 1 = lg n, czyli 2 p < n 2 p=1. 2 k+1 Widać, że lg i = 2 k log(2 k + i) = 2 k (k + 1). czyli lg i = k +1 2 k+1 k +1 Ile wynosi suma lg i + (n 2 p ) lg n = 2 k (k + 1)? Sprawdźmy to dla p = 4 : 1 2 0 + 2 2 1 + 3 2 2 + 4 2 3 = 2 0 + 2 1 + 2 2 + 2 3 = 2 1 + 2 2 + 2 3 = 2 2 + 2 3 = 2 3 = (2 4 1) + 2 (2 3 1) + 2 2 (2 2 1) + 2 3 = 3 2 4 + 2 3 (1 + 2 + 2 2 ) = 3 2 4 + 2 3 (2 3 1) = 3 2 4 + 1 Twierdzenie 2 k (k + 1) = (p 1)2 p + 1. 2 k (k + 1) + (n 2 p ) lg n. Dowód przez indukcję. lg i = ( lg n 1)2 lg n + 1 + (n 2 lg n ) lg n ) = ( lg n 2)2 lg n + 1 + (n 2 lg n ) lg n ) = n lg n 2 lg n + 1. 5