KOPCE KOLEJKI PRIORYTETOWE - PRZYPOMNIENIE KOPCE WYSOKOŚĆ KOPCA KOPCE I KOLEJKI PRIORYTETOWE PROJEKTOWANIE ALGORYTMÓW I METODY SZTUCZNEJ INTELIGENCJI

Podobne dokumenty
Algorytmy i Struktury Danych

Rekurencja. Dla rozwiązania danego problemu, algorytm wywołuje sam siebie przy rozwiązywaniu podobnych podproblemów. Przykład: silnia: n! = n(n-1)!

Strategia "dziel i zwyciężaj"

ZASADY PROGRAMOWANIA KOMPUTERÓW ZAP zima 2014/2015. Drzewa BST c.d., równoważenie drzew, kopce.

Sortowanie. Kolejki priorytetowe i algorytm Heapsort Dynamiczny problem sortowania:

Wykład 2. Drzewa zbalansowane AVL i 2-3-4

Kolejka priorytetowa. Często rozważa się kolejki priorytetowe, w których poszukuje się elementu minimalnego zamiast maksymalnego.

Sortowanie bąbelkowe

Sortowanie. Bartman Jacek Algorytmy i struktury

Sortowanie - wybrane algorytmy

Algorytmy sortujące i wyszukujące

Analiza algorytmów zadania podstawowe

Algorytmy i Struktury Danych, 2. ćwiczenia

Wykład 8. Drzewa AVL i 2-3-4

Wykład 5. Sortowanie w czasie liniowologarytmicznym

Podstawowe algorytmy i ich implementacje w C. Wykład 9

Wykład 3. Złożoność i realizowalność algorytmów Elementarne struktury danych: stosy, kolejki, listy

Algorytmy i struktury danych Sortowanie IS/IO, WIMiIP

Porządek symetryczny: right(x)

Zadanie 1 Przygotuj algorytm programu - sortowanie przez wstawianie.

Podstawy programowania 2. Temat: Drzewa binarne. Przygotował: mgr inż. Tomasz Michno

Drzewa poszukiwań binarnych

WSTĘP DO INFORMATYKI. Drzewa i struktury drzewiaste

Wstęp do programowania

Algorytm selekcji Hoare a. Łukasz Miemus

Podstawy Informatyki. Metody dostępu do danych

Programowanie w VB Proste algorytmy sortowania

Algorytmy i Struktury Danych.

Algorytmy i struktury danych

Wysokość drzewa Głębokość węzła

Definicja. Ciąg wejściowy: Funkcja uporządkowująca: Sortowanie polega na: a 1, a 2,, a n-1, a n. f(a 1 ) f(a 2 ) f(a n )

Struktury danych: stos, kolejka, lista, drzewo

Algorytmy i struktury danych. Co dziś? Tytułem przypomnienia metoda dziel i zwyciężaj. Wykład VIII Elementarne techniki algorytmiczne

Zadanie projektowe 1: Struktury danych i złożoność obliczeniowa

Sortowanie przez scalanie

Wykład 3. Metoda dziel i zwyciężaj

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Algorytmy i struktury danych Laboratorium 7. 2 Drzewa poszukiwań binarnych

Drzewa binarne. Drzewo binarne to dowolny obiekt powstały zgodnie z regułami: jest drzewem binarnym Jeśli T 0. jest drzewem binarnym Np.

prowadzący dr ADRIAN HORZYK /~horzyk tel.: Konsultacje paw. D-13/325

Sortowanie danych. Jolanta Bachan. Podstawy programowania

Algorytmy i struktury danych. wykład 5

Drzewa czerwono-czarne.

ALGORYTMY I STRUKTURY DANYCH

Algorytmy i. Wykład 5: Drzewa. Dr inż. Paweł Kasprowski

Drzewo. Drzewo uporządkowane ma ponumerowanych (oznaczonych) następników. Drzewo uporządkowane składa się z węzłów, które zawierają następujące pola:

liniowa - elementy następują jeden za drugim. Graficznie możemy przedstawić to tak:

Jeszcze o algorytmach

Definicja pliku kratowego

Wstęp do programowania

Wykład 6. Drzewa poszukiwań binarnych (BST)

EGZAMIN - Wersja A. ALGORYTMY I STRUKTURY DANYCH Lisek89 opracowanie kartki od Pani dr E. Koszelew

Analiza algorytmów zadania podstawowe

Algorytmy i Struktury Danych, 2. ćwiczenia

INFORMATYKA SORTOWANIE DANYCH.

Drzewa BST i AVL. Drzewa poszukiwań binarnych (BST)

Laboratorium nr 7 Sortowanie

Sortowanie. LABORKA Piotr Ciskowski

Lista liniowa dwukierunkowa

BAZY DANYCH. Microsoft Access. Adrian Horzyk OPTYMALIZACJA BAZY DANYCH I TWORZENIE INDEKSÓW. Akademia Górniczo-Hutnicza

Algorytmy i Struktury Danych, 9. ćwiczenia

Algorytmy i struktury danych

Zaawansowane algorytmy i struktury danych

Wykład 2. Drzewa poszukiwań binarnych (BST)

ALGORYTMY I STRUKTURY DANYCH

Wyszukiwanie w BST Minimalny i maksymalny klucz. Wyszukiwanie w BST Minimalny klucz. Wyszukiwanie w BST - minimalny klucz Wersja rekurencyjna

Każdy węzeł w drzewie posiada 3 pola: klucz, adres prawego potomka i adres lewego potomka. Pola zawierające adresy mogą być puste.

Struktury Danych i Złożoność Obliczeniowa

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 9. Karol Tarnowski A-1 p.

Wstęp do programowania

Algorytmy i Struktury Danych. Co dziś? Drzewo decyzyjne. Wykład IV Sortowania cd. Elementarne struktury danych

Teoretyczne podstawy informatyki

. Podstawy Programowania 2. Drzewa bst - część druga. Arkadiusz Chrobot. 12 maja 2019

Drzewa poszukiwań binarnych

Efektywna metoda sortowania sortowanie przez scalanie

Wstęp do programowania. Drzewa podstawowe techniki. Piotr Chrząstowski-Wachtel

Algorytmy sortujące 1

Zofia Kruczkiewicz, Algorytmu i struktury danych, Wykład 14, 1

Wstęp do Informatyki zadania ze złożoności obliczeniowej z rozwiązaniami

Drzewo binarne BST. LABORKA Piotr Ciskowski

Laboratoria nr 1. Sortowanie

Problemy porządkowe zadania

Egzamin, AISDI, I termin, 18 czerwca 2015 r.

Algorytmy i str ruktury danych. Metody algorytmiczne. Bartman Jacek

Teoretyczne podstawy informatyki

[12] Metody projektowania algorytmów (dziel i rządź, programowanie dynamiczne i algorytmy zachłanne).

Równoległe algorytmy sortowania. Krzysztof Banaś Obliczenia równoległe 1

Kolejka Priorytetowa. Algorytmy i Struktury Danych. (c) Marcin Sydow. Kolejka priorytetowa. implementacja. Kopiec Binarny. Tablicowa.

Złożoność obliczeniowa zadania, zestaw 2

Koszt zamortyzowany. Potencjał - Fundusz Ubezpieczeń Kosztów Algorytmicznych

TEORETYCZNE PODSTAWY INFORMATYKI

Luty 2001 Algorytmy (4) 2000/2001

Algorytmy i struktury danych. Wykład 4 Tablice nieporządkowane i uporządkowane

Algorytmy i Struktury Danych

Zaawansowane algorytmy i struktury danych

Sortowanie w czasie liniowym

Uwaga: Funkcja zamień(a[j],a[j+s]) zamienia miejscami wartości A[j] oraz A[j+s].

Bazy danych - BD. Indeksy. Wykład przygotował: Robert Wrembel. BD wykład 7 (1)

Podstawy algorytmiki i programowania - wykład 6 Sortowanie- algorytmy

Wstęp do Programowania potok funkcyjny

Transkrypt:

PROJEKTOWANIE ALGORYTMÓW I METODY SZTUCZNEJ INTELIGENCJI KOPCE, ALGORYTMY SORTOWANIA KOPCE Wykład dr inż. Łukasz Jeleń Na podstawie wykładów dr. T. Fevensa KOLEJKI PRIORYTETOWE - PRZYPOMNIENIE Możemy wykorzystać kolejkę priorytetową do posortowania zbioru porównywalnych Algorytm PriorityQueueSort(S, P) Wejście: sekwencja S, kolejka elementów priorytetowa P wykorzystująca. Pojedynczo umieść elementy w metodę całkowitego uporządkowania kolejce kluczy. Usuń elementy z wykorzystaniem Output: posortowana sekwencja S z serii operacji removemin zastosowaniem metody całkowitego uporządkowania Nieposortowana lista prowadzi do while!s.isempty() do sortowania przez wybór: e S.removeFirst () czas O(n ) P.insert (e, null) Posortowana lista prowadzi do sortowania while!p.isempty() do przez wstawianie: e P.removeMin().getKey() czas O(n ) S.addLast(e) Czy możemy sortować szybciej? KOPCE Kopiec jest drzewem binarnym, które w węzłach przechowuje klucze i spełnia następujące właściwości: Ostatni węzeł kopca jest węzłem najbardziej po prawej na poziomie h Właściwość kopca: dla każdego węzła wewnętrznego v, różnego od korzenia klucz(v) klucz(ojciec(v)) Pełne drzewo binarne: niech h będzie wysokością kopca i dla i =,, h, istnieje węzłów o poziomie i na poziomie h, węzły wewnętrzne są na lewo od węzła zewnętrznego Ostatni węzeł WYSOKOŚĆ KOPCA KOPCE I KOLEJKI PRIORYTETOWE Twierdzenie: Kopiec przechowujący n kluczy ma wysokość O(log n) Dowód: (wykorzystamy właściwość kompletnego drzewa binarnego) Niech h będzie wysokością kopca przechowującego n kluczy i Ponieważ mamy kluczy na poziomie i =,, h- i przynajmniej jeden klucz na poziomie h, mamy h- n + + + + + h zatem n, tj. h log n Możemy wykorzystać kopiec do zaimplementowania kolejki priorytetowej Będziemy przechowywać (klucz, wartość) element w każdym węźle wewnętrznym Będziemy śledzić pozycję ostatniego węzła Dla uproszczenia na schematach będziemy pokazywać tylko klucze poziom klucze h h h (, Alicja) (, Piotr) (, Jan) (, Marek) (, Anna)

WSTAWIANIE ELEMENTÓW DO KOPCA Metoda insert(k, x) w kolejce priorytetowej odnosi się do wstawienia klucza k do kopca Algorytm wstawiania składa się z trzech kroków: Znajdź pozycję dla nowego węzła z (nowy ostatni węzeł) Przenieś k do z Przywróć właściwość kopca (za chwilę ) z wstawiany węzeł z ALGORYTM UPHEAP Po umieszczeniu nowego klucza k właściwość kopca może nie być zachowana Algorytm upheap przywraca właściwość kopca poprzez zamianę k w górę kopca rozpoczynając od wstawianego węzła. Algorytm kończy działanie jeśli klucz k dojdzie do korzenia lub do węzła, którego ojciec posiada klucz mniejszy lub równy k Ponieważ kopiec posiada wysokość O(log n), upheap działa w czasie O(log n) z z USUWANIE ELEMENTU Z KOPCA Metoda kolejki priorytetowej removemin() odnosi się do usuwania klucza w korzeniu kopca. Algorytm usuwający składa się z trzech kroków: Zastąp klucz korzenia kluczem ostatniego węzła w Usuń w Przywróć właściwość kopca (za chwilę ) w w ostatni węzeł nowy ostatni węzeł ALGORYTM DOWNHEAP Po zamianie klucza w korzeniu z kluczem k ostatniego węzła właściwość kopca może nie być zachowana Algorytm downheap przywraca właściwość kopca poprzez zamianę k w dół kopca rozpoczynając od korzenia. Algorytm kończy działanie jeśli klucz k dojdzie do liścia lub do węzła, którego synowie posiadają klucze mniejsze lub równe k. Ponieważ kopiec posiada wysokość O(log n), downheap działa w czasie O(log n) w w UAKTUALNIANIE OSTATNIEGO WĘZŁA SORTOWANIE PRZEZ KOPCOWANIE Pozycja węzła wstawianego może zostać wyznaczona poprzez wyznaczenie ścieżki dla O(log n) węzłów Jeśli ostatni węzeł jest lewym synem, to wróć do ojca Dopóki bieżący węzeł jest prawym synem, idź do ojca Jeśli bieżący węzeł jest lewym synem, idź do prawego syna Dopóki bieżący węzeł jest wewnętrzny, idź do lewego syna Weźmy pod uwagę kolejkę priorytetową z n elementami zaimplementowaną za pomocą kopca Zajmowane miejsce to O(n) metody wstaw i removemin zabierają O(log n) czasu metody size, isempty i min zabierają O() czasu Zastosowanie kolejki bazującej na kopcu pozwala nam posortować listę n-elementową w czasie O(n log n) Otrzymany algorytm jest nazywany sortowaniem przez kopcowanie Sortowanie to jest znacznie szybsze niż algorytmy sortujące w czasie kwadratowym jak sortowanie przez wybór i przez wstawianie

KOPIEC BAZUJĄCY NA TABLICY ŁĄCZENIE DWÓCH KOPCÓW Możemy przedstawić kopiec za pomocą tablicy o długości n + Dla węzła o indeksie i lewy syn znajduje się na indeksie i prawy syn znajduje się na indeksie i + Linki między węzłami nie są przechowywane w sposób bezpośredni Komórka o indeksie nie jest wykorzystywana Operacje wstawiania odpowiada zapisowi na indeksie n + Operacja removemin odpowiada usunięciu elementu na indeksie n Może być stosowana do sortowania przez kopcowanie in-situ Mamy dane dwa kopce i klucz k Tworzymy nowy kopiec z korzeniem zawierającym k i z dwoma kopcami jako poddrzewa Stosujemy technikę downheap do przywrócenia właściwości kopca TWORZENIE KOPCA TECHNIKĄ OD DOŁU DO GÓRY (BOTTOM-UP) Możemy zbudować kopiec przechowujący n kluczy z zastosowaniem techniki bottomup składającej się z log n kroków W kroku i, para kopców z i kluczami jest łączona w jeden kopiec z i+ kluczami i i i+

- KONIEC ANALIZA Zobrazujemy najgorszy czas techniki downheap za pomocą zastępczej ścieżki, która na początku idzie na prawo, a następnie systematycznie idzie w lewo do momentu zejścia na dół kopca (może się różnić od typowej ścieżki downheap Ponieważ każdy węzeł jest odwiedzany maksymalnie razy, całkowita ilość węzłów w ścieżce zastępczej wynosi O(n). Zatem budowa kopca techniką bottom - up zajmuje czas O(n). Technika ta jest szybsza od wykonania n wstawień do kolejki i dlatego pozwala na przyspieszenie pierwszej fazy sortowania przez kopcowanie Mając daną tablicę integerów, A = {,,,,,,,,,,, }, stwórz kopiec H z zastosowaniem techniki bottom-up Rozpoczniemy od przedstawienia tablicy integerów jako kompletne drzewo ( zakładając, że pozycja o indeksie jest pusta): Należy zastosować algorytm downheap poziom po poziomie: Należy zastosować algorytm downheap poziom po poziomie: Należy zastosować algorytm downheap poziom po poziomie:

Należy zastosować algorytm downheap poziom po poziomie: Otrzymany kopiec: Wykorzystując kopiec z poprzedniego przykładu wywołaj H.removeMin(). Zamieniamy korzeń z ostatnim węzłem zewnętrznym: Rozpoczniemy od przedstawienia tablicy integerów jako kompletne drzewo zachowując właściwość kopca: przechowaj kopię klucza Teraz należy przeprowadzić downheap poziom po poziomie aby naprawić pozycję : Wykorzystując poprzedni kopiec wywołaj H.insert(). Rozpoczniemy od przedstawienia tablicy integerów jako kompletne drzewo

Należy umieścić w nowym węźle zewnętrznym: Teraz należy przeprowadzić operację upheap w celu naprawienia pozycji. Mając daną tablicę n integerów A, podaj algorytm wyznaczający k najmniejszych integerów w czasie mniejszym od O(n log n) dla k << n. Mając daną tablicę n integerów A, podaj algorytm wyznaczający k najmniejszych integerów w czasie mniejszym od O(n log n) dla k << n. int smalest(int A[], int k) { Stwórz kopiec H z zastosowaniem bottom-up // złożoność obliczeniowa O(n) for i to k do wyświetl H.removeMin(); // złożoność O(k log n) } SORTOWANIA SORTOWANIE PRZEZ SCALANIE

TECHNIKA DZIEL I ZWYCIĘŻAJ SORTOWANIE PRZEZ SCALANIE Dziel i zwyciężaj jest ogólnym paradygmatem projektowania algorytmów: Podział: podziel dane wejściowe S na dwa rozłączne podzbiory S i S Rekurencja: rozwiąż problem dla S i S Scalanie: połącz rozwiązania dla S i S w jedno rozwiązanie dla S Krokiem podstawowym rekurencji są podproblemy o rozmiarze lub Sortowanie przez scalanie jest algorytmem sortującym bazującym na technice dziel i zwyciężaj Podobnie jak dla sortowania kopcowego wykorzystuje komparator Posiada złożoność O(n log n) Inaczej niż dla sortowania kopcowego Nie wykorzystuje zewnętrznej kolejki priorytetowej Pobiera dane w sposób sekwencyjny (odpowiedni do sortowania danych na dysku zewnętrznym) Algorytm mergesort(s, C) Sortowanie przez scalanie listy S Wejście lista S z n elementami, zawierającej n elementów składa komparator C Wyjście lista S posortowana się z trzech kroków: zgodnie z komparatorem C Podział: podział S na dwie if S.size() > (S, S ) podziel(s, n/) sekwencje S i S zawierającymi mergesort(s, C) ok. n/ elementów każda mergesort(s, C) S pusta lista Rekurencja: posortuj połącz(s, S, S) rekurencyjnie S i S return S Scalanie: połącz S i S w jedną & n % # n! posortowaną listę S = and S = #! #! $ " ŁĄCZENIE DWÓCH POSORTOWANYCH SEKWENCJI Ostatni krok sortowania przez scalanie składa się ze scalania dwóch posortowanych sekwencji S i S zaimplementowanych jako lista w jedną posortowaną sekwencję S zawierającą połączenie elementów z S i S Scalanie dwóch posortowanych sekwencji zawierających po n/ elementów i zaimplementowane z zastosowaniem listy dwukierunkowej zabiera O(n) czasu Algorytm merge(s, S, S) Wejście sekwencje S i S zawierające po n/ elementów, pusta sekwencja S Wyjście posortowana sekwencja S: S S while ~S.isEmpty() ~S.isEmpty() if S.first().element() S.first().element() S.addLast(S.remove(S.first())) else S.addLast(S.remove(S.first())) while ~S.isEmpty() S.addLast(S.remove(S.first())) while ~S.isEmpty() S.addLast(S.remove(S.first())) DRZEWO SORTOWANIA PRZEZ SCALANIE Działanie sortowania przez scalanie jest zobrazowane przez drzewo binarne każdy węzeł reprezentuje wywołanie rekurencyjne sortownia i zawiera nieposortowaną sekwencję przez wywołaniem i podziałem posortowaną sekwencję po zakończeniu wywołania korzeń jest początkowym wywołaniem liście są wywołaniami podsekwencji o rozmiarze lub Podział Wywołanie rekurencyjne, podział

Wywołanie rekurencyjne, podział Wywołanie rekurencyjne, podział Wywołanie rekurencyjne, krok podstawowy Scalanie Wywołanie rekurencyjne,, krok podstawowy, scalanie Scalanie

Wywołanie rekurencyjne,, krok podstawowy, scalanie Scalanie ANALIZA SORTOWANIA PRZEZ SCALANIE PODSUMOWANIE ALGORYTMÓW SORTOWANIA Wysokość drzewa sortowania to O(log n) przy każdym wywołaniu rekurencyjnym dzielimy sekwencję na pół Ilość operacji wykonywanych na węzłach na poziomie i to O(n) dzielimy i scalmy i sekwencji o rozmiarze n/ i wykonujemy i+ wywołań rekurencyjnych Zatem, całkowita złożoność obliczeniowa sortownia przez scalanie wynosi O(n log n) poziom #sekw rozmiar n n/ i i n/i Algorytm Złożoność Uwagi przez wybór O(n ) przez wstawianie O(n ) przez kopcowanie O(n log n) przez scalanie O(n log n) wolne in-situ dla małych tablic (< K) wolne in-situ dla małych tablic (< K) szybkie in-situ (impl. na tablicy) dla średnich tablic (K M) szybkie sekwencyjny dostęp do danych dla b. dużych tablic (> M) SORTOWANIE SZYBKIE SORTOWANIE SZYBKIE Sortowanie szybkie jest (losowym) algorytmem sortującym bazującym na technice dziel i zwyciężaj: Podział: wybierz losowy element x (nazywany piwotem) i podziel S na L - elementy mniejsze od x E - elementy równe x G - elementy większe od x Rekurencja: posortuj L i G Scalanie: połącz L, E i G L E x x x G

PODZIAŁ DRZEWO SORTOWANIA Dzielimy sekwencję wejściową w następujący sposób: Usuwamy element y z S i Wstawiamy y do L, E lub G w zależności od porównania z piwotem x Wszystkie operacje wstawiania i usuwania wykonywane są na początku lub na końcu sekwencji, a zatem ich czas działania wynosi O() Zatem czas działania kroku dzielącego sortowania szybkiego wyniesie O(n) Algorytm partition(s, p) Wejście sekwencja S, pozycja p piwota Wyjście podsekwencje L, E, G z elementami z S mniejszymi, równymi, lub większymi od piwota L, E, G puste sekwencje x S.remove(p) while ~S.isEmpty() y S.remove(S.first()) if y < x L.addLast(y) else if y = x E.addLast(y) else { y > x } G.addLast(y) return L, E, G Działanie sortowania szybkiego może być zilustrowane za pomocą drzewa binarnego Każdy węzeł reprezentuje wywołanie rekurencyjne i przechowuje: Nieposortowaną sekwencję przed wywołaniem oraz piwot Posortowaną sekwencję po wywołaniu Korzeń jest wywołaniem pierwotnym Liście są wywołaniami podsekwencji o rozmiarze lub Wybór piwota Podział, wywołanie rekurencyjne, wybór piwota Podział, wywołanie rekurencyjne, wybór piwota Wywołanie rekurencyjne,, krok podstawowy, scalanie

Wywołanie rekurencyjne, wybór piwota Podział, wywołanie rekurencyjne, wybór piwota Scalanie, scalanie NAJGORSZA ZŁOŻONOŚĆ OBLICZENIOWA Z najgorszym czasem sortowania szybkiego mamy do czynienia, gdy piwot jest unikalnym minimalnym lub maksymalnym elementem Jedna z list L i G ma rozmiar n, a druga ma rozmiar Złożoność obliczeniowa jest proporcjonalna do sumy: n + (n ) + + + Zatem najgorszy czas tego sortowania to O(n ) poziom czas n n n OCZEKIWANA ZŁOŻONOŚĆ OBLICZENIOWA Rozważmy wywołanie rekurencyjne sortowania szybkiego na sekwencji o rozmiarze s Dobre wywołanie: rozmiary L i G są mniejsze od s/ Złe wywołanie: jedna z sekwencji ma rozmiar większy niż s/ Wywołanie jest dobre z prawdopodobieństwem / / z możliwych piwotów skutkuje dobrym wywołaniem Dobre wywołanie Złe piwoty Złe wywołanie Dobre piwoty Złe piwoty OCZEKIWANA ZŁOŻONOŚĆ OBLICZENIOWA Fakt probabilistyczny: Oczekiwana ilość rzutów monetą wymagana do wyrzucenia k reszek wynosi k Dla węzła na poziomie i, możemy oczekiwać: i/ potomków będzie dobrym wywołaniem Rozmiar sekwencji wejściowej dla danego wywołania wynosi najwyżej (/) i/ n Mamy zatem: Dla węzła o poziomie log / n, oczekiwany rozmiar wejścia to jeden Oczekiwana wysokość drzewa sortowania to O(log n) Ilość obliczeń wykonywanych w węzłach o tym samym poziomie wynosi O(n) Zatem oczekiwana złożoność obliczeniowa sortowania szybkiego jest w O(n log n) expected height O(log n) s(a) s(r) s(b) s(c) s(d) s(e) s(f) time per level O(n) O(n) O(n) total expected time: O(n log n)

SORTOWANIE SZYBKIE IN-SITU Sortowanie szybkie może być zaimplementowane techniką in-situ. W kroku dzielącym zmodyfikujemy operacje tak, aby przeorganizować elementy w tablicy w taki sposób, że elementy <= piwot będą posiadały indeks < l piwot posiada indeks l elementy >= piwot będą posiadały indeks > l Wywołanie rekurencyjne będzie zawierać elementy z indeksami < l elementy z indeksami > l Algorytm inplacequicksort(s, a, b) Wejście lista S, indeksy a i b Wyjście lista S z elementami o indeksach między a i b przeorganizowana w sposób rosnący if a b return i losowy integer między a i b S.swapElements(i, b) {piwot na końcu} l inplacepartition(a, b) inplacequicksort(s, a, l ) inplacequicksort(s, l +, b) PODZIAŁ IN-SITU Najpierw należy wybrać piwot na indeksie i między a i b. a Zamień piwot z elementem na indeksie b. Umieść indeks startowy I na indeksie a, a indeks r na indeksie b-. l i r b (piwot = ) (piwot = ) PODZIAŁ IN-SITU PODZIAŁ IN-SITU Dokonaj podziału z zastosowaniem dwóch indeksów do rozdzielenia S na L i G (pozostałe wartości = piwot mogą się znajdować zarówno w L jak i w G). l r Powtarzaj dopóki l i r się nie przetną: Przeskanuj indeksy w prawo aż do odnalezienia elementu > x. Przeskanuj r w lewo aż do odnalezienia elementu < x. Jeśli l < r, zamień elementy na indeksach l i r l r (piwot = ) Kiedy l i r miną się w taki sposób, że l > r, możemy zamienić piwot z elementem na pozycji l r l a Wywołaj krok rekurencyjny dla podsekwencji od indeksu a do l- i podsekwencji dla indeksów l+ do b a l- l l+ b b PODSUMOWANIE ALGORYTMÓW SORTOWANIA Algorytm Czas Uwagi przez wybór O(n ) przez wstawianie O(n ) szybkie O(n log n) oczekiwany O(n ) najgorszy in-situ wolne (dobre dla małych wejść) in-situ wolne (dobre dla małych wejść) in-situ, losowe najszybsza (dobra dla dużych danych) SORTOWANIE KUBEŁKOWE I POZYCYJNE przez kopcownie O(n log n) przez scalanie O(n log n) in-situ szybka (dobra dla dużych danych) sekwencyjny dostęp do danych szybka (dobra dla b. dużych danych) B, c, a, b, d, g, e

SORTOWANIE KUBEŁKOWE Niech S będzie sekwencją n wpisów (klucz, wartość) z kluczami w przedziale [, N ] Sortowanie kubełkowe (Bucket-sort) wykorzystuje klucze jako indeksy w zewnętrznej tablicy B sekwencji (kubełki) Faza : Przenosimy wszystkie wpisy (k,o) S do kubła B[k] Faza : Dla i =,, N, przenieś wpisy kubła B[i] na koniec sekwencji S Analiza: Faza zabiera O(n) Faza zabiera O(n + N) Sortowanie kubełkowe zabiera czas O(n + N) Algorytm bucketsort(s, N) Wejście lista S z wpisami o kluczach w przedziale [, N ] Wyjście sekwencja S posortowana rosnąco względem kluczy B tablica z N pustymi sekwencjami for każda pozycja p w S do e S.remove(p) k e.getkey() B[k].addLast(e) for i to N for każdy wpis e w B[i] do p B[i].first() e B[i].remove(p) S.addLast(e) Zakres kluczy [, ] B, d, c, a, g, b, e Faza, c, a, b, d, g, e Faza, c, a, b, d, g, e WŁAŚCIWOŚCI I ROZSZERZENIA UPORZĄDKOWANIE LEKSYKOGRAFICZNE Właściwości typu kluczy Klucze są wykorzystywane jako indeksy tablicy i nie mogą być dowolnymi obiektami Brak zewnętrznego komparatora Właściwość stałości sortowania Relatywne uporządkowanie dowolnych dwóch wpisów o tym samym kluczu jest zachowane po zakończeniu działania algorytmu Rozszerzenia Klucze są integerami w przedziale [a, b] Umieść wpis (k, o) w kuble B[k a] Klucze z łańcuchami znakowymi ze zbioru D możliwych łańcuchów, gdzie D ma stały rozmiar (e.g., nazwy krajów członkowskich UE) Posortuj D i wyznacz indeks r(k) dla każdego łańcucha k w D w posortowanej sekwencji Umieść wpis (k,o) w kuble B[r(k)] d-krotka jest sekwencją d kluczy (k, k,, k d ), gdzie klucz k i będzie i-tym wymiarem krotki Przykład: Współrzędne Kartezjańskie punktu w przestrzeni są -krotką Uporządkowanie leksykograficzne dwóch d-krotek jest zdefiniowane rekurencyjnie w następujący sposób: (x, x,, xd) < (y, y,, yd) x < y x = y (x,, xd) < (y,, yd) Tzn., krotki są porównywane z przez pierwszy wymiar, potem przez drugi, itd. SORTOWANIE LEKSYKOGRAFICZNE SORTOWANIE POZYCYJNE Niech C i będzie komparatorem, który porównuje dwie krotki Niech stablesort(s, C) będzie stałym algorytmem sortowania wykorzystującym komparator C Sortowanie leksykograficzne sortuje sekwencję d-krotek w sposób leksykograficzny poprzez wywołanie d razy algorytmu stablesort. Raz dla każdego wymiaru. Sortowanie leksykograficzne działa w czasie O(dT(n)), gdzie T(n) jest czasem działania stablesort Algorytm lexicographicsort(s) Wejście sekwencja S z d-krotkami Wyjście sekwencja S posortowana leksykograficznie for i d downto stablesort(s, C i ) Przykład: (,,) (,,) (,,) (,, ) (,, ) (,, ) (,, ) (,,) (,,) (,,) (,, ) (,,) (,, ) (,,) (,,) (,, ) (,,) (,, ) (,,) (,,) Sortowanie pozycyjne jest specyficzną odmianą sortowania leksykograficznego, które wykorzystuje sortowanie kubełkowe jako algorytm sortowania stałego. Sortowanie pozycyjne ma zastosowanie do krotek, których klucze w każdym wymiarze są integerami w przedziale [, N ] Sortowanie pozycyjne działa w czasie O(d( n + N)) Algorytm radixsort(s, N) Wejście sekwencja S z d-krotkami takie, że (,, ) (x,, x d ) i (x,, x d ) (N,, N ) dla każdej krotki (x,, x d ) w S Wyjście sekwencja S posortowana leksykograficznie for i d downto bucketsort(s, N)

SORTOWANIE POZYCYJNE DLA LICZB BINARNYCH Posortuj podane wartości z zastosowaniem sortowania pozycyjnego: {,,,,, } Rozważ sekwencję n-bitowyh integerów x = x b x x Reprezentujemy każdy element jako b- krotkę integerów z przedziału [, ] i zastosujemy sortowanie pozycyjne z N = Ta modyfikacja algorytmu pozycyjnego działa w czasie O(bn) Dla przykładu, możemy posortować sekwencję -bitowych integerów w liniowym czasie Algorytm binaryradixsort(s) Wejście sekwencja S z b- bitowymi integerami Wyjście posortowana sekwencja S zamień każdy element x z S z elementem (, x) for i to b zamień klucz k każdego elementu (k, x) w S z bitem x i bucketsort(s, ) Sortowanie sekwencji -bitowych integerów