N IW ERSYTETKONOM IC ZNYWRAKOW IE Algorytmy sortujące i

Transkrypt

N IW ERSYTETKONOM IC ZNYWRAKOW IE Algorytmy sortujące i
Algorytmy i Struktury Danych
Algorytmy sortujące i wyszukujące
Zadaniem algorytmów sortujących jest ułożenie elementów danego zbioru w ściśle określonej kolejności. Najczęściej wykorzystywany jest porządek numeryczny lub leksykograficzny. Posortowane elementy wykorzystywane są w bardziej zaawansowanych algorytmach na przykład wyszukujących.
Przedstawione poniżej sposoby sortowania układają elementy w porządku rosnącym.
UNIWERSYTET EKONOMICZNY W KRAKOWIE
Sortowanie przez wybieranie
Sortowanie przez wybieranie polega na wybraniu z wektora elementu najmniejszego i zamianie go z
elementem bieżącym. Załóżmy, że chcemy posortować n-elementowy wektor dane[] o indeksach
od 0 do n-1.
for (int i = 0; i < n-1; i++ ) {
- przypisz zmiennej j indeks najmniejszego elementu spośród dane[i]...dane[n-1]
- dokonaj zamiany elementów dane[i] z dane[j]
}
Przykład, chcemy posortować następujący wektor dane[].
4 2 5 3 1
Poniżej wszystkie kroki, które zostaną wykonane przy sortowaniu. Zmienna i to kolejny numer kroku,
a j indeks najmniejszego elementu z zakresu od i do n-1 (n w naszym przykładzie wynosi 5).
i wektor wejściowy j wektor wyjściowy
0
4 2 5 3 1
4
1 2 5 3 4
1
1 2 5 3 4
1
1 2 5 3 4
2
1 2 5 3 4
3
1 2 3 5 4
3
1 2 3 5 4
4
1 2 3 4 5
Po posortowaniu otrzymamy poniższy wektor.
1 2 3 4 5
Sortowanie przez wstawianie
W sortowaniu przez wstawianie wektor zostaje podzielony na dwie części, część posortowaną oraz
część nieposortowaną. Istotą algorytmu jest pobieranie kolejnych elementów z części nieposortowanej i wstawianie ich na odpowiednie miejsce w części posortowanej (tak samo jak układanie kart w
dłoni). Podział wektora ustalamy zakładając, że w części posortowanej znajduje się jego pierszy element, a cała reszta to część nieposortowana. Załóżmy, że chcemy posortować n-elementowy wektor
dane[] o indeksach od 0 do n-1.
13
Algorytmy i Struktury Danych
for (int i = 1; i < n; i++) {
- pobierz pierwszy element z części nieposortowanej, e = dane[i]
- wstaw ten element w odpowiedne miejsce w części posortowanej dane[0]...dane[i]
}
Przykład, chcemy posortować następujący wektor dane[].
4 2 5 3 1
Poniżej wszystkie kroki, które zostaną wykonane przy sortowaniu. Zmienna i to kolejny numer kroku,
a e wartość pierwszego elementu z części nieposortowanej. Część posortowana zaznaczona jest kolorem niebieskim.
UNIWERSYTET EKONOMICZNY W KRAKOWIE
i wektor wejściowy
e = dane[i]
wektor wyjściowy
1
4 2 5 3 1
2
2 4 5 3 1
2
2 4 5 3 1
5
2 4 5 3 1
3
2 4 5 3 1
3
2 3 4 5 1
4
2 3 4 5 1
1
1 2 3 4 5
Po posortowaniu otrzymamy poniższy wektor.
1 2 3 4 5
Stosując algorytm sortowania przez wstawianie możemy sortować na bieżąco dane wejściowe (np. podczas
pobierania ich od użytkownika z konsoli czy też odczytu z pliku).
Sortowanie bąbelkowe
Ten sposób sortowania polega na porównywaniu ze sobą par sąsiadujących elementów i zamianie ich
kolejności jeśli nie spełniają warunku porządkowania. Załóżmy, że chcemy posortować n-elementowy
wektor dane[] o indeksach od 0 do n-1.
for (int i = 1; i < n; i++ ) {
- przeglądaj kolejno pary elementów:
(dane[n-1], dane[n-2])
(dane[n-2], dane[n-3])
...
(dane[i-1], dane[i])
- jeżeli elementy tworzące parę nie są prawidłowo uporządkowane, zamień je
}
Przykład, chcemy posortować następujący wektor dane[].
4 2 5 3 1
14
Algorytmy i Struktury Danych
UNIWERSYTET EKONOMICZNY W KRAKOWIE
Poniżej poszczególne kroki, które zostaną wykonane przy sortowaniu. Zmienna i to kolejny numer
kroku. Wektor brany pod uwagę jest uzależniony od wartości i od dane[n-1] do dane[i-1]. Elementy porównywane zaznaczone są kolorem niebieskim.
i wektor wejściowy
porównuję
uzyskuję
1
4 2 5 3 1
4
4
4
4
4
4
4
1
2
1 4 2 5 3
3
4
2
2
2
1
5
5
1
2
3
1
5
5
1
3
3
3
2
2
1
4
5
1
2
2
1
5
5
5
wektor wyjściowy
3
3
3
3
1 4 2 5 3
1 4 2 5 3
1 4 2 3 5
1 4 2 3 5
1 4 2 3 5
1 4 2 3 5
1 2 4 3 5
1 2 4 3 5
1 2 4 3 5
1 2 4 3 5
1 2 4 3 5
1 2 4 3 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Po posortowaniu otrzymamy poniższy wektor.
1 2 3 4 5
Sortowanie bąbelkowe jest mało wydajne dla większych zbiorów.
Sortowanie szybkie
Idea sortowania szybkiego (ang. quicksort) polega na podziale wektora na dwie części, jedna z nich zawiera elementy mniejsze od elementu dzielącego, druga większe. Każda z części jest znowu sortowana za pomocą algorytmu sortowania szybkiego (wywołania rekurencyjne).
- wybierz jeden element w wektorze (oznaczmy go jako p)
- dokonaj przemieszczenia elementów tak aby uzyskać
elementy < p
p
elementy >= p
- powtórz algorytm dla lewej (elementy mniejsze) i prawej (elementy większe) części
wektora
Element podziału może być pierwszym, ostatnim , środkowym czy też losowym elementem naszego
wektora (często ma on wartość mediany). Przykład, chcemy posortować następujący wektor dane[].
Jako element dzielący wybieramy ostatni element wektora wejściowego.
3 4 1 7 2 8 5 6
Poniżej wszystkie kroki, które zostaną wykonane przy sortowaniu. W metodzie dokonującej przemieszczenia elementów wykorzystujemy dwa indeksy i, j umożliwiające nam wyszukiwanie
elementów większych i mniejszych od elementu dzielącego (oznaczonego jako p). Początkowa wartość i to indeks pierwszego elementu wektora wejściowego, a j indeks przedostatniego elementu
15
Algorytmy i Struktury Danych
wektora wejściowego. Na ostatnim indeksie wektora wejściowego mamy element dzielący (zauważ,
że wektor wejściowy może być częścią wektora początkowego). Sama metoda realizująca podział
może wyglądać następująco.
i - indeks pierwszego elementu
j - indeks przedostatniego elementu
p - wartość ostatniego elementu (zapamiętujemy jego indeks w zmiennej k)
UNIWERSYTET EKONOMICZNY W KRAKOWIE
// dopóki indeks i jest mniejszy od j
while (i < j) {
while (wektor[i] < p) i++; // szukamy od początku elementu mniejszego od p
while (wektor[j] > p) j--; // szukamy od końca elementu większego od p
jeśli nie minęliśmy się indeksami (i<j) to zamieniamy wektor[i] z wektor[j]
}
zamieniamy miejscami elementy wektor[i] z wektor[k], dzięki temu element dzielący
znajdzie się na właściwej pozycji
zwracamy indeks i (czyli indeks podziału wektora na części)
Przykład algorytmu przemieszczającego elementy w naszym wektorze dane[]. Element dzielący p
został zaznaczony na niebiesko (jego indeks k wynosi 7).
i j wektor wejściowy
akcja
wektor wyjściowy
0 6
3 4 1 7 2 8 5 6
3 6
3 4 1 7 2 8 5 6
zamień dane[i] z dane[j]
3 4 1 5 2 8 7 6
5 4
3 4 1 5 2 8 7 6
zamień dane[i] z dane[k]
3 4 1 5 2 6 7 8
Metoda zwróci nam indeks i czyli wartość 5. Ta informacja jest nam potrzebna do kolejnego
wywołania algorytmu (dla lewej i prawej części wektora). Wszystkie wywołania zostały przedstawione
poniżej.
3 4 1 5 2
1
2
6
7 8
3 5 4
1
3
4
3
7
5
8
7
5
Po posortowaniu otrzymamy poniższy wektor.
1 2 3 4 5 6 7 8
16
Algorytmy i Struktury Danych
Sortowanie szybkie jest przykładem algorytmu typu “dziel i zwyciężaj”. W skrócie zadanie jest dzielone na
podzadania, które są przetwarzane na mniejszej ilości danych. Rozwiązania podzadań są składane w jedną
całośći stanowią rozwiązanie dla zadania głównego.
UNIWERSYTET EKONOMICZNY W KRAKOWIE
Wyszukiwanie wartości w wektorze
Mając dany zbiór elementów zazwyczaj chcemy znaleźć konkretną wartość. Do przeszukiwania wektora stosuje się zazwyczaj wyszukiwanie sekwencyjne bądź też binarne. Wyszukiwanie sekwencyjne
polega na sprawdzeniu kolejnych wartości (przeglądamy elementy od pierwszego do ostatniego indeksu). Wyszukiwanie binarne (ang. binary search) odbywa się na uporządkowanym ciągu
elementów. Polega na połowieniu ciągu i ponownym szukaniu w tej połowie, w której może występować poszukiwana wartość (analogia do szukania danych w książce telefonicznej czy też w encyklopedii).
Wyszukiwanie binarne najczęściej jest realizowane za pomocą rekurencji.
Zadania do wykonania
1. Napisz program, który utworzy n-elementowy wektor, wygeneruje n pseudolosowych liczb
całkowitych z przedziału [5, 67] (wartość n ma być określana w trakcie działania programu),
uzupełni nimi wektor, a następnie dokona posortowania wektora oraz wyświetli jego zawartość
pzed i po sortowaniu. Zastosuj algorytm sortowania przez wybieranie. Samo sortowanie ma się dokonywać za pomocą metody statycznej. Sortujemy w porządku rosnącym.
2. Dopisz do kodu zadania pierwszego metodę statyczną realizującą sortowanie za pomocą algorytmu
sortowania przez wstawianie.
3. Dopisz do kodu zadania pierwszego metodę statyczną realizującą sortowanie za pomocą algorytmu
sortowania bąbelkowego.
4. Dopisz do kodu zadania pierwszego metodę statyczną realizującą sortowanie za pomocą algorytmu
sortowania szybkiego.
5. Napisz program, który pozwoli na wczytanie n ciągów znaków (wartość n ma być określana w trakcie działania programu), a następnie uporządkuje je alfabetycznie i w takiej postaci wyświetli na ekranie monitora. Przyjmij, że ciągi znaków składają się wyłącznie z liter alfabetu łacińskiego. W trakcie sortowania program nie powinien rozróżniać małych i dużych liter. Zastosuj algorytm sortowania przez wybieranie.
Utwórz odpowiedni wektor oraz przypomnij sobie metody porównujące łańcuchy tekstowe (klasa
String).
6. Napisz program pozwalający na wczytanie n liczb. Wprowadzane liczby mają być od razu umieszczane w wektorze w porządku rosnącym. Wyświetl utworzony wektor.
17
Algorytmy i Struktury Danych
7. Napisz program pozwalający na wczytanie do wektora n wartości całkowitych i wyszukujący
podaną przez użytkownika wartość. Zastosuj wyszukiwanie liniowe.
8. Napisz program pozwalający na wprowadzenie do wektora n wartości całkowitych. Każdą
wprowadzaną liczbę należy umieścić w wektorze od razu w porządku rosnącym. Następnie program ma znaleźć wśród wartości znajdujących się w wektorze zadaną przez użytkownika liczbę. Zastosuj algorytm wyszukiwania binarnego
UNIWERSYTET EKONOMICZNY W KRAKOWIE
Wykorzystaj rozwiązanie zadania nr 7.
18