Wstęp do Programowania potok funkcyjny

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

Algorytmy zachłanne. dr inż. Urszula Gałązka

Wstęp do Programowania potok funkcyjny

Wstęp do Programowania potok funkcyjny

Wstęp do Programowania potok funkcyjny

Temat: Algorytm kompresji plików metodą Huffmana

Wstęp do programowania

Wstęp do Programowania potok funkcyjny

0-0000, , , itd

Kompresja bezstratna. Entropia. Kod Huffmana

Def. Kod jednoznacznie definiowalny Def. Kod przedrostkowy Def. Kod optymalny. Przykłady kodów. Kody optymalne

Niech x 1,..., x n będzie ciągiem zdarzeń. ---

Wstęp Statyczne kody Huffmana Dynamiczne kody Huffmana Praktyka. Kodowanie Huffmana. Dawid Duda. 4 marca 2004

KODY SYMBOLI. Kod Shannona-Fano. Algorytm S-F. Przykład S-F

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

Wstęp do Programowania potok funkcyjny

Temat: Algorytmy zachłanne

Porządek symetryczny: right(x)

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

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

Nierówność Krafta-McMillana, Kodowanie Huffmana

Sortowanie bąbelkowe

Kody Huffmana. Konrad Wypyski. 11 lutego 2006 roku

Programowanie dynamiczne i algorytmy zachłanne

Definicja. Jeśli. wtedy

Kodowanie Huffmana. Platforma programistyczna.net; materiały do laboratorium 2014/15 Marcin Wilczewski

Analiza algorytmów zadania podstawowe

Programowanie dynamiczne cz. 2

Minimalne drzewa rozpinające

Struktury danych: stos, kolejka, lista, drzewo

Algorytmy i Struktury Danych

Kompresja danych kodowanie Huffmana. Dariusz Sobczuk

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

Wstęp do programowania

Wstęp do Programowania potok funkcyjny

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

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

Struktury danych i złożoność obliczeniowa Wykład 2. Prof. dr hab. inż. Jan Magott

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:

Wstęp do Programowania potok funkcyjny

Łyżwy - omówienie zadania

Wstęp do Programowania potok funkcyjny

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

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

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

Kodowanie i kompresja Streszczenie Studia dzienne Wykład 9,

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

dr inż. Paweł Myszkowski Wykład nr 11 ( )

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Granica kompresji Kodowanie Shannona Kodowanie Huffmana Kodowanie ciągów Kodowanie arytmetyczne. Kody. Marek Śmieja. Teoria informacji 1 / 35

Kompresja danych Streszczenie Studia Dzienne Wykład 10,

KODY SYMBOLI. Materiały KODA, A.Przelaskowski. Koncepcja przedziałów nieskończonego alfabetu

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

Wstęp do Programowania potok funkcyjny

Programowanie dynamiczne

mgr inż. Grzegorz Kraszewski SYSTEMY MULTIMEDIALNE wykład 4, strona 1. GOLOMBA I RICE'A

Sztuczna Inteligencja i Systemy Doradcze

Kodowanie informacji

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

Drzewa poszukiwań binarnych

Algorytmy kodowania entropijnego

Modulacja i kodowanie. Labolatorium. Kodowanie źródłowe Kod Huffman a

Algorytmy i struktury danych. wykład 8

Listy, kolejki, stosy

Wstęp do Programowania potok funkcyjny

Algorytm obejścia drzewa poszukiwań i zadanie o hetmanach szachowych

Sortowanie danych. Jolanta Bachan. Podstawy programowania

Elementy teorii informacji i kodowania

Algorytmy kompresji. Kodowanie Huffmana, kodowanie arytmetyczne

Teoria informacji i kodowania Ćwiczenia

Wstęp do Informatyki

Heurystyki. Strategie poszukiwań

Luty 2001 Algorytmy (4) 2000/2001

Wygra Polska czy Brazylia, czyli o tym jak zwięźle zapisywać informacje

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

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 )

Wstęp do programowania. Reprezentacje liczb. Liczby naturalne, całkowite i rzeczywiste w układzie binarnym

Kodowanie i kompresja Tomasz Jurdziński Studia Wieczorowe Wykład Kody liniowe - kodowanie w oparciu o macierz parzystości

Algorytmy i str ruktury danych. Metody algorytmiczne. Bartman Jacek

Programowanie w VB Proste algorytmy sortowania

2 Arytmetyka. d r 2 r + d r 1 2 r 1...d d 0 2 0,

Algorytmy Równoległe i Rozproszone Część V - Model PRAM II

INŻYNIERIA BEZPIECZEŃSTWA LABORATORIUM NR 2 ALGORYTM XOR ŁAMANIE ALGORYTMU XOR

Zadanie 1. Zmiana systemów. Zadanie 2. Szyfr Cezara. Zadanie 3. Czy liczba jest doskonała. Zadanie 4. Rozkład liczby na czynniki pierwsze Zadanie 5.

Wstęp do Programowania potok funkcyjny

Algorytmy równoległe: prezentacja i ocena efektywności prostych algorytmów dla systemów równoległych

Wstęp do programowania

Algorytmy równoległe. Rafał Walkowiak Politechnika Poznańska Studia inżynierskie Informatyka 2010


Algorytmy sortujące i wyszukujące

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

Algorytmy i złożoność obliczeniowa. Wojciech Horzelski

Zapis liczb binarnych ze znakiem

Algorytmy i Struktury Danych, 9. ćwiczenia

Wykład 5. Sortowanie w czasie liniowologarytmicznym

Lista 4. Kamil Matuszewski 22 marca 2016

Drzewa podstawowe poj

Transkrypt:

Wstęp do Programowania potok funkcyjny Marcin Kubica 22/23

Outline Programowanie zachłanne Programowanie zachłanne

Rodzaje kodów Programowanie zachłanne Kody stałej długości (np. ASCII). Kody zmiennej długości (np. Morse a). Problem separatora kody (bez-)prefiksowe. Kod zmiennej długości może być efektywniejszy niż kod stałej długości.

Kody stałej długości i prefiksowe Wiadomość: BACADAEAFABBAAAGAH Kod stałej długości: A C E G B D F H (54 bity) A C E G B D F H (42 bity).

Reprezentacja kodu w postaci drzewa Problem optymalnego kodu prefiksowego (przy znanych częstościach występowania znaków) Reprezentacja optymalnego kodowania w postaci drzewa binarnego. Jeśli kod jest prefiksowy, to znaki odpowiadają liściom. Drzewo musi być regularne, inaczej kod nie jest optymalny.

Reprezentacja kodu w postaci drzewa Drzewo reprezentujące kod z poprzedniego przykładu. A B C D E F G H

Algorytm Huffmana Programowanie zachłanne Algorytm Huffmana: Drzewo kodowania budujemy od liści do korzenia. Zbiór liści = zbiór znaków. Wybieramy dwa elementy o najmniejszych częstościach występowania. Sklejamy je i zastępujemy jednym poddrzewem. Częstość występowania sumuje się. Ich kody będą się różnić ostatnim bitem. Powtarzamy, aż pozostanie tylko jedno drzewo.

Algorytm Huffmana Programowanie zachłanne Działanie algorytmu Huffmana: (C, )(D, )(E, )(F, )(G, )(H, )(B, 3)(A, 9) (E, )(F, )(G, )(H, ) 2 (B, 3)(A, 9) (C, ) (D, ) (G, )(H, ) 2 (C, ) (D, ) 2 (B, 3)(A, 9) (E, ) (F, )

Algorytm Huffmana Programowanie zachłanne 2 (C, ) (D, ) 2 (E, ) (F, ) 2 (B, 3)(A, 9) (G, ) (H, ) 2 (B, 3) 4 (A, 9) (C, ) (D, ) 2 2 (E, ) (F, ) (G, ) (H, )

Algorytm Huffmana Programowanie zachłanne 4 5 (A, 9) 2 2 (B, 3) 2 (E, ) (F, ) (G, ) (H, ) (C, ) (D, ) 9 (A, 9) 5 4 (B, 3) 2 2 2 (C, ) (D, ) (E, ) (F, ) (G, ) (H, )

Algorytm Huffmana Programowanie zachłanne 8 (A, 9) 9 5 4 (B, 3) 2 2 2 (C, ) (D, ) (E, ) (F, ) (G, ) (H, )

Optymalność wyboru Programowanie zachłanne Lemma f (c) częstość występowania. x i y para znaków o najmniejszej częstości wystąpień. Istnieje optymalny kod prefiksowy, w którym kody dla x i y mają tę samą długość i różnią się tylko ostatnim bitem. Dowód. Rozważmy optymalne kodowanie. b i c dwa sąsiednie liście o maksymalnej głębokości h b = h c, Bez straty ogólności zakładamy, że f (b) f (c) oraz f (x) f (y). f (x) f (b) f (y) f (c) h x, h y h b = h c. Zamieniamy b z x i c z y. Długość kodu zmienia się o: f (x)(h b h x ) + f (y)(h c h y ) + f (b)(h x h b ) + f (c)(h y h c ) = (f (x) f (b))(h b h x ) + (f (y) f (c))(h c h y ) Powstały kod musi być również optymalny.

Optymalność wyboru Programowanie zachłanne Lemma f (c) częstość występowania. x i y para znaków o najmniejszej częstości wystąpień. Niech z będzie nowym symbolem, f (z) = f (x) + f (y). Niech T będzie drzewem optymalnego kodowania (C \ {x, y}) {z}. Drzewo T powstałe przez dodanie do z synów x i y jest drzewem optymalnego kodowania dla C. Dowód. Gdyby T nie było optymalne, to istniałoby lepsze drzewo kodowania, w którym x i y byliby braćmi. Oznaczając ich ojca przez z i usuwając je uzyskalibyśmy drzewo kodowania lepsze od T, co nie jest możliwe.

Implementacja algorytmu Huffmana Dane: lista znaków posortowana wg rosnących częstości występowania. Wynik: drzewo optymalnego kodu. let huffman l = let rec process col = if huff_size col = then huff_first col else let t = huff_first col and col = huff_remove col in let t2 = huff_first col and col2 = huff_remove col in process (huff_put col2 (merge t t2)) in process (make_huff_col l);;

Implementacja drzew Huffmana type a huff_tree = Letter of ( a * float) Node of ( a huff_tree * a huff_tree * float);; let frequency (t : a huff_tree) = match t with Letter (_, f) -> f Node (_, _, f) -> f;; let merge t t2 = Node (t, t2, frequency t +. frequency t2);;

Implementacja kolekcji drzew Huffmana type a huff_col = a huff_tree fifo * a huff_tree fifo;; let make_huff_col l = (fold_left (fun q x -> put q (Letter x)) empty_queue l, empty_queue);; let huff_size ((q, q2): a huff_col) = size q + size q2;; let huff_put ((q, q2): a huff_col) t = ((q, put q2 t): a huff_col);;

Implementacja kolekcji drzew Huffmana let huff_first ((q, q2): a huff_col) = if q = empty_queue then first q2 else if q2 = empty_queue then first q else let f = first q and f2 = first q2 in if frequency f <= frequency f2 then f else f2;; let huff_remove ((q, q2): a huff_col) = if q = empty_queue then (q, remove q2) else if q2 = empty_queue then (remove q, q2) else let f = first q and f2 = first q2 in if frequency f <= frequency f2 then (remove q, q2) else ((q, remove q2): a huff_col);;

Schemat programowania zachłannego Szukamy optymalnego rozwiązania, złożonego z ciągu kolejno wybieranych elementów. Własność wyboru zachłannego ciąg wyborów optymalnych lokalnie prowadzi nas do rozwiązania optymalnego globalnie, Jeśli istnieje rozwiązanie optymalne zgodne z dotychczasowymi wyborami, to istnieje rozwiązanie optymalne zgodne również z kolejnym wyborem. (W szczególności istnieje rozwiązanie optymalne zgodne z pierwszym wyborem.) Zasada dziel i zwyciężaj własność optymalnej podstruktury: optymalne rozwiązanie jest funkcją optymalnych rozwiązań podproblemów i łączącego je zachłannego wyboru.

Programowanie zachłanne : Dane są wagi n osób, w postaci listy uporządkowanej niemalejąco. Jak usadzić te osoby w minimalnej liczbie kajaków? Kajaki są dwuosobowe i mają określoną wyporność. W kajaku może płynąć jedna lub dwie osoby. Zakładamy, że żadna z osób nie przekracza wyporności kajaka, ale dwie osoby mogą już przekroczyć wyporność kajaka. Problem ten można rozwiązać zachłannie i to na kilka sposobów. Będziemy korzystać z kolejek dwustronnych.

algorytm I Algorytm I: Najgrubszego kajakarza nazwiemy grubasem. Ci co mieszczą się z nim w kajaku to chudzielce. Pozostali to też grubasy. Idea: największy grubas płynie z najgrubszym chudzielcem. Im chudszy grubas, tym grubsi są chudzielce. Podział na grubasów i chudzielców będzie się zmieniał. Chudsze grubasy będą przechodzić do puli chudzielców. W razie braku grubasów, najgrubszy chudzielec zostanie grubasem. Początkowo zakładamy, że wszyscy to grubasy. Każdy tylko raz może się zmienić z grubasa w chudzielca i raz z chudzielca w grubasa.

algorytm I let kajaki l wyp = let rec dobierz g ch =... in let rec sadzaj gp chp acc =... in sadzaj (make_queue l) empty_queue [];; kajaki [; 2; 2; 3; 3; 3; 4; 6; 6; 8; 8; 8; 9; 9; ] ;; [[3; 3]; [6; 3]; [6; 4]; [8]; [8; 2]; [8; 2]; [9]; [9; ]; []]

algorytm I let rec sadzaj gp chp acc = let (g, ch) = dobierz gp chp in if is_empty_queue g then acc else if is_empty_queue ch then sadzaj (remove_last g) ch ([last g]::acc) else sadzaj (remove_last g) (remove_last ch) ([last g; last ch]::acc)

algorytm I let rec dobierz g ch = if (is_empty_queue g) && (is_empty_queue ch) then (g, ch) else if is_empty_queue g then (make_queue [last ch], remove_last ch) else if queue_size g = then (g, ch) else if first g + last g <= wyp then dobierz (remove_first g) (put_last ch (first g)) else (g, ch)

algorytm I Uzasadnienie poprawności: Istnieje optymalne rozwiązanie, w którym największy grubas g i najgrubszy chudzielec c płyną razem. Jeśli g płynie sam, to można do niego dosadzić c. Załóżmy, że g płynie z jakimś x, więc x c. c i x można zamienić miejscami. Własność optymalnej podstruktury oczywista. Po obsadzeniu pierwszego kajaka, pozostali kajakarze powinni płynąć minimalną liczbą kajaków.

algorytm II Algorytm II: Najchudszy kajakarz jest chudzielcem. Grubasy, to ci, którzy nie mieszczą się z nim w kajaku. Pozostali to chudzielce. Jeśli jest tylko jeden chudzielec, to przyjmujemy, że jest on grubasem. Idea: najchudszego chudzielca sadzamy z najgrubszym chudzielcem. Na koniec grubasy siadają samotnie. Im grubszy jest najchudszy chudzielec, tym mniej jest chudzielców. Początkowo wszyscy to chudzielce. Potem stopniowo przerzucamy chudzielców do puli grubasów.

algorytm II let kajaki l wyp = let rec dobierz ch g =... in let rec sadzaj chp gp acc =... in sadzaj (make_queue l) empty_queue [];; kajaki [; 2; 2; 3; 3; 3; 4; 6; 6; 8; 8; 8; 9; 9; ] ;; [[]; [9]; [8]; [3; 4]; [3; 6]; [3; 6]; [2; 8]; [2; 8]; [; 9]]

algorytm II let rec sadzaj chp gp acc = let (ch, g) = dobierz chp gp in if (is_empty_queue ch) && (is_empty_queue g) then acc else if is_empty_queue ch then sadzaj ch (remove_first g) ([first g]::acc) else sadzaj (remove_first (remove_last ch)) g ([first ch; last ch]::acc)

algorytm II let rec dobierz ch g = if is_empty_queue ch then (ch, g) else if queue_size ch = then (empty_queue, put_first g (last ch)) else if first ch + last ch > wyp then dobierz (remove_last ch) (put_first g (last ch)) else (ch, g)

algorytm II Uzasadnienie poprawności: Jeśli brak chudzielców, to każdy płynie osobno. Jeśli są chudzielcy, to jest ich przynajmniej dwóch. Wówczas istnieje optymalne rozwiązanie, w którym najgrubszy g i najchudszy chudzielec c płyną razem. Jeśli c płynie sam, to można do niego dosadzić g. Załóżmy, że c płynie z jakimś x, więc x g. g i x można zamienić miejscami. Własność optymalnej podstruktury oczywista. Po obsadzeniu pierwszego kajaka, pozostali kajakarze powinni płynąć minimalną liczbą kajaków.

algorytm III Algorytm III: Najgrubszego kajakarza sadzamy z najchudszym, o ile się zmieszczą. Jeśli nie, to najgrubszy kajakarz płynie sam.

algorytm III let kajaki l wyp = let rec sadzaj q acc = if is_empty_queue q then acc else if queue_size q = then [first q]::acc else if first q + last q <= wyp then sadzaj (remove_first (remove_last q)) ([first q; last q]::acc) else sadzaj (remove_last q) ([last q]::acc) in sadzaj (make_queue l) [];; kajaki [; 2; 2; 3; 3; 3; 4; 6; 6; 8; 8; 8; 9; 9; ] ;; [[3; 4]; [3; 6]; [3; 6]; [8]; [2; 8]; [2; 8]; [9]; [; 9]; []]

algorytm III Uzasadnienie poprawności: Jeśli najgrubszy kajakarz g nie może płynąć z najchudszym c, to musi płynąć sam. Jeśli g może płynąć z c, to istnieje optymalne rozwiązanie, w którym płyną razem. Jeśli g płynie sam, to można do niego dosadzić c. Załóżmy, że g płynie z jakimś x. Jeśli c płynie sam, to można zamienić miejscami c i x. Załóżmy, że c płynie z jakimś y. Wówczas y g i można zamienić g i y miejscami. Własność optymalnej podstruktury oczywista. Po obsadzeniu pierwszego kajaka, pozostali kajakarze powinni płynąć minimalną liczbą kajaków.

algorytm III To rozwiązanie generuje takie same wyniki (z dokładnością do kolejności) jak poprzednie. Dlaczego?

algorytm IV Algorytm IV: Wsadzamy razem dwóch kolejnych, jak najgrubszych, kajakarzy. Grubi są ci, którzy nie mieszczą się do jednego kajaka razem z kolejnym chudszym. Najchudszy jest z definicji chudy. Sadzamy razem dwóch najgrubszych chudych. Stopniowo grubi mogą przenosić się do puli chudych.

algorytm IV let kajaki l wyp = let rec dobierz ch g =... in let rec sadzaj chp gp acc =... in sadzaj [] l [];; kajaki [; 2; 2; 3; 3; 3; 4; 6; 6; 8; 8; 8; 9; 9; ] ;; [[]; [9]; [9]; [; 8]; [2; 8]; [2; 8]; [3; 3]; [3; 6]; [4; 6]]

algorytm IV let rec sadzaj chp gp acc = let (ch, g) = dobierz chp gp in match ch with [] -> acc [h] -> sadzaj [] g ([h]::acc) h::h2::t -> sadzaj t g ([h2; h]::acc)

algorytm IV let rec dobierz ch g = match (ch, g) with (_, []) -> (ch, []) ([], h::t) -> dobierz [h] t (chh::cht, gh::gt) -> if chh + gh <= wyp then dobierz (gh::ch) gt else (ch, g)

algorytm IV Uzasadnienie poprawności: Jeśli nawet dwaj najchudsi nie mogą płynąć razem, to każdy musi płynąć oddzielnie. Oznaczmy dwóch kolejnych najgrubszych, którzy mogą płynąć razem przez g i c, g c. Istnieje optymalne rozwiązanie, w którym g i c płyną razem. Jeśli g płynie sam, to można do niego dosadzić c. Jeśli c płynie sam, to można do niego dosadzić g. Załóżmy, że g płynie z jakimś x, a c z jakimś y. Mamy: x c g. y może płynąć razem z x, a g razem z c. Własność optymalnej podstruktury oczywista. Po obsadzeniu pierwszego kajaka, pozostali kajakarze powinni płynąć minimalną liczbą kajaków.