Programowanie w VB Proste algorytmy sortowania Sortowanie
Transkrypt
Programowanie w VB Proste algorytmy sortowania Sortowanie
Programowanie w VB Proste algorytmy sortowania Sortowanie bąbelkowe Algorytm sortowania bąbelkowego polega na porównywaniu par elementów leżących obok siebie i, jeśli jest to potrzebne, zmienianiu ich kolejności. Czyli w pierwszym przebiegu porównujemy (i ewentualnie zamieniamy): • Element pierwszy i drugi • Element drugi i trzeci • ... • Element (n-1)-wszy i n-ty Każdy element jest tak długo przesuwany w ciągu, aż napotkany zostanie element większy od niego, wtedy w następnych krokach przesuwany jest ten większy element. Po pierwszym przebiegu ciąg nie musi być jeszcze uporządkowany, ale na pozycji n znajdzie się maksymalny element ciągu. Zatem w drugim przebiegu można porządkować ciąg krótszy, czyli tylko elementy na pozycjach od 1 do n-1. Po drugim przebiegu, dwa ostatnie elementy są na swoich miejscach, czyli pozostaje posortować ciąg o dwa elementy krótszy, itd. Można jeszcze bardziej usprawnić ten algorytm. Jeżeli w pewnym przebiegu algorytmu ostatnia zamiana nastąpiła na pozycji i, to w następnym przebiegu wystarczy porządkować tylko elementy na pozycjach od 1 do i-1. W takiej wersji ten algorytm jest zrealizowany w demonstracji. Jeżeli dane wejściowe są uporządkowane, to algorytm wykonuje tylko jeden przebieg (nie jest wykonywana żadna zamiana). Option Base 1 Const N = 10 Const MAXVALUE = 20 Dim a(N) As Integer Sub SortBubble() Dim i As Integer, j As Integer, v As Integer For i = 1 To N For j = 1 To N - i If a(j) > a(j + 1) Then v = a(j) a(j) = a(j + 1) a(j + 1) = v End If Next j Next i End Sub Sortowanie przez wstawianie W algorytmie sortowania przez wstawianie ciąg danych jest dzielony na dwie części: • już uporządkowaną (przed uruchomieniem procedury nie zawiera ona żadnych elementów), • jeszcze nie uporządkowaną (na początku zawiera wszystkie elementy). Sposób porządkowania można opisać następująco: 1. weź pierwszy element z części nieuporządkowanej (jeśli jest pusta to zakończ działanie algorytmu), 2. wstaw go w odpowiednie miejsce w części uporządkowanej (po takiej operacji część nieuporządkowana jest jeden element krótsza, a część posortowana zyskuje jeden element). Pozostaje jeszcze do rozstrzygnięcia, w jaki sposób wyznaczyć prawidłowe położenie nowego elementu w części uporządkowanej. Najprostszy sposób polega na porównaniu tego elementu z kolejnymi elementami części uporządkowanej. Jeżeli element na pozycji i jest większy od wstawianego, to ten nowy element należy wstawić między elementy na pozycjach i-1 i i. Inna strategia wstawiania elementu do uporządkowanego ciągu jest zastosowana w sortowaniu przez wstawianie z binarnym umieszczaniem. Algorytm ten działa w czasie pesymistycznym 1/2 N^2 - O(N), oczekiwanym 1/4 N^2 + O(N). Ilość wykonanych porównań jest równa liczbie inwersji, tzn. takich par że a[i] > a[j] dla i < j, zatem działa bardzo szybko dla tablic niemal uporządkowanych. Algorytm ten jest stabilny, prosty i łatwo implementowalny. Option Base 1 Const N = 10 Const MAXVALUE = 20 Dim a(N) As Integer ' Znajdowanie indeksu dla nowej wartosci v w tablicy posortowanej rosnaco ' algorytm iteracyjny Function SearchIdxIter(ByVal l As Integer, ByVal p As Integer, ByVal v As Integer) As Integer Dim k As Integer For k = l To p If a(k) >= v Then Exit For End If Next k SearchIdxIter = k End Function ' Znajdowanie indeksu dla nowej wartosci v w tablicy posortowanej rosnaco ' iteracyjny algorytm przeszukiwania binarnego Function SearchIdxBinIter(ByVal l As Integer, ByVal p As Integer, ByVal v As Integer) As Integer Dim k As Integer While p - l >= 0 If a(l) >= v Then SearchIdxBinIter = l Exit Function End If If a(p) < v Then SearchIdxBinIter = p + 1 Exit Function End If k = (l + p) \ 2 If a(k) < v Then l=k+1 Else p=k End If Wend End Function Sub SortInsertBinIter() Dim i As Integer, j As Integer, k As Integer, v As Integer For i = 2 To N v = a(i) k = SearchIdxBinIter(1, i - 1, v) If k < i Then For j = i To k + 1 Step -1 a(j) = a(j - 1) Next j a(k) = v End If Next i End Sub Sub SortInsertBinRek() Dim i As Integer, j As Integer, k As Integer, v As Integer For i = 2 To N v = a(i) k = SearchIdxBinRek(1, i - 1, v) If k < i Then For j = i To k + 1 Step -1 a(j) = a(j - 1) Next j a(k) = v End If Next i End Sub Sub SortInsertIter() Dim i As Integer, j As Integer, k As Integer, v As Integer For i = 2 To N v = a(i) k = SearchIdxIter(1, i - 1, v) If k < i Then For j = i To k + 1 Step -1 a(j) = a(j - 1) Next j a(k) = v End If Next i End Sub ' Znajdowanie indeksu dla nowej wartosci v w tablicy posortowanej rosnaco ' rekurencyjny algorytm przeszukiwania binarnego Function SearchIdxBinRek(ByVal l As Integer, ByVal p As Integer, ByVal v As Integer) As Integer Dim k As Integer If a(l) >= v Then SearchIdxBinRek = l Exit Function End If If a(p) < v Then SearchIdxBinRek = p + 1 Exit Function End If If p <= l + 1 Then SearchIdxBinRek = p Exit Function End If k = (l + p) \ 2 If a(k) < v Then SearchIdxBinRek = SearchIdxBinRek(k, p, v) Else SearchIdxBinRek = SearchIdxBinRek(l, k, v) End If End Function Sortowanie przez selekcję Jest to chyba najbardziej intuicyjny algorytm sortowania. Polega on na wielokrotnym wyborze minimalnego elementu z coraz krótszego podciągu danych. Dokładnie ma to następujący przebieg: • Wybierz minimum z ciągu elementów na pozycjach od 1 do n i zamień go z pierwszym elementem. • Wybierz minimum z ciągu elementów na pozycjach od 2 do n i zamień go z drugim elementem (po tym kroku elementy na pozycjach od 1 do 2 są uporządkowane). • ... • Wybierz minimum z ciągu elementów na pozycjach n-1 i n i zamień go z elementem na pozycji n-1 (po tej operacji elementy na pozycjach od 1 do n-1 są uporządkowane, a element na pozycji n jest maksymalny, czyli ciąg elementów na pozycjach od 1 do n jest uporządkowany) Znalezienie minimum w ciągu wymaga m-1 porównań, gdzie m jest długością ciągu. Algorytm sortowania przez wybór wykonuje n-1 takich operacji, a długość ciągu, z którego wybierany jest element minimalny zmienia się od n do 2. Option Base 1 Const N = 10 Const MAXVALUE = 20 Dim a(N) As Integer ' Znajdowanie indeksu najmniejszego elementu w tablicy nieposortowanej Function SearchIdxMin(ByVal l As Integer, ByVal p As Integer) As Integer Dim Min As Integer, k As Integer SearchIdxMin = l Min = a(l) For k = l + 1 To p If a(k) < Min Then SearchIdxMin = k Min = a(k) End If Next k End Function Sub SortSelection() Dim i As Integer, v As Integer For i = 1 To N - 1 v = a(i) k = SearchIdxMin(i, N) a(i) = a(k) a(k) = v Next i End Sub Algorytm ten działa w czasie stałym 1/2 N^2 - O(N); zawsze wykonujemy ten sam ciąg porównań. Algorytm ten dokonuje tylko N-1 przestawień. Algorytm ten nie jest stabilny. Sortowanie szybkie W przypadku tej metody sortowania jest wykorzystywana strategia "dziel i zwyciężaj". Jest to bardzo efektywna technika algorytmiczna (wykorzystana jest także w algorytmie sortowania przez scalanie). Przypuśćmy, że potrafimy podzielić dany ciąg na dwie takie części, że elementy pierwszego ciągu są mniejsze od elementów drugiego ciągu, czyli nieformalnie mówiąc, na elementy "małe" i "duże". Mając taki podział ciągu, możemy każdą z części uporządkować osobno (pomińmy na razie, w jaki sposób to zrobić). Otrzymamy ciąg składający się z uporządkowanych elementów "małych", a po nich następują uporządkowane elementy "duże" - czyli cały ciąg jest już uporządkowany! Algorytm służący do dzielenia ciągu na dwie części, spełniające opisany warunek, ma następującą postać: • Weź pierwszy element ciągu (oznaczmy go przez x). • Podziel ciąg tak, aby w pierwszej części znalazły się elementy mniejsze lub równe x, a w drugiej większe lub równe x Można teraz podać pełny algorytm sortujący: • Jeżeli liczba elementów w ciągu jest większa od 1, to podziel ciąg na dwie części tak, aby elementy z pierwszej części były nie większe niż elementy z drugiej części. • Wywołaj procedurę sortującą dla pierwszej części ciągu. • Wywołaj procedurę sortującą dla drugiej części ciągu. Dla poprawności działania powyższego algorytmu nie ma znaczenia, który element zostanie wybrany jako element rozdzielający ciąg na dwie części. Ma to jednak wpływ na efektywność algorytmu. W naszym przypadku wybierany jest element środkowy. Czas działania tego algorytmu sortowania zależy od wielkości podziałów wykonywanych przez procedurę dzielącą ciąg. Jeżeli podziały te są zrównoważone, czyli wielkości powstających części są sobie równe, to algorytm ten jest praktycznie najszybszą metodą sortowania – stąd jego nazwa: sortowanie szybkie (ang. quicksort). Jeżeli natomiast otrzymane w wyniku podziału ciągi mają bardzo różne długości, to złożoność algorytmu jest większa. Option Base 1 Const N = 10 Const MAXVALUE = 20 Dim a(N) As Integer Sub QuickSort(ByVal l As Integer, ByVal p As Integer) Dim v As Integer, i As Integer, j As Integer, temp As Integer v = a((l + p) \ 2) i=l j=p Do While a(i) < v i=i+1 Wend While v < a(j) j=j-1 Wend If i <= j Then temp = a(i) a(i) = a(j) a(j) = temp i=i+1 j=j-1 End If Loop While i <= j If l < j Then QuickSort l, j End If If i < p Then QuickSort i, p End If End Sub