Algorytmy i struktury danych IS/IO, WIMiIP Danuta Szeliga AGH Kraków
Spis treści I 1 Algorytmy i struktury danych 2 Spis treści 3 Organizacja zajęć 4 Literatura 5 Pojęcia podstawowe Rozwiązywanie problemu Algorytm Zapis algorytmu - schemat blokowy Cechy algorytmu Poprawność algorytmu 6 Metody algorytmiczne Metody konstrukcji algorytmu Klasy metod algorytmicznych Rekurencja Metoda dziel i zwyciężaj Metoda zachłanna
Spis treści II Programowanie dynamiczne Redukcja
Organizacja zajęć Wykłady - 28h Ćwiczenia audytoryjne - 28h Ćwiczenia laboratoryjne - 28/14h
Organizacja zajęć Wykłady - 28h Ćwiczenia audytoryjne - 28h Ćwiczenia laboratoryjne - 28/14h Zaliczenia i egzaminy: http://home.agh.edu.pl/ szeliga/ menu Dydaktyka Zakres materiału, literatura: syllabus AGH
Literatura N. Wirth, Algorytmy + struktury danych = programy D. Knuth, Sztuka programowania T.H. Cormen, C.E. Leiserson, R.L. Rivest, Wprowadzenie do Algorytmów A.V. Aho, J.E. Hopcroft, J.D. Ullman, Algorytmy i struktury danych A. Drozdek, C++ Algorytmy i struktury danych L. Banachowski, K. Diks, W. Rytter, Algorytmy i struktury danych
Rozwiązywanie problemu (zagadnienia) Modelowanie rzeczywistości zdefiniowanie zadania wprowadzenie założeń i ograniczeń selekcja informacji Algorytm rozwiązania Zapis: język naturalny pseudokod schemat blokowy Wybór narzędzia programowania Implementacja struktur danych algorytmu rozwiązania
Rozwiązywanie problemu (zagadnienia) Modelowanie rzeczywistości zdefiniowanie zadania wprowadzenie założeń i ograniczeń selekcja informacji Algorytm rozwiązania Zapis: język naturalny pseudokod schemat blokowy Wybór narzędzia programowania Implementacja struktur danych algorytmu rozwiązania Dobry algorytm warunek konieczny, ale niewystarczający napisania poprawnego i wydajnego programu
Co to jest algorytm? Jeżeli mamy do wykonania pewne zadanie, tworzymy sposób (przepis, proces, metodę, technikę, procedurę) realizacji tego zadania. Taki przepis to algorytm. Przykłady: przepis kucharski instrukcja składania mebla, urządzenia zapis nutowy wykonywanie pisemne dodawania/mnożenia/dzielenia...
Co to jest algorytm? Jeżeli mamy do wykonania pewne zadanie, tworzymy sposób (przepis, proces, metodę, technikę, procedurę) realizacji tego zadania. Taki przepis to algorytm. Przykłady: przepis kucharski instrukcja składania mebla, urządzenia zapis nutowy wykonywanie pisemne dodawania/mnożenia/dzielenia... Słowo algorytm (z ang. algorism) pochodzi od nazwiska matematyka perskiego z IX wieku, Muhammada ibn Musa al-chuwarizmi ego i oznaczało pierwotnie wykonywanie działań przy pomocy liczb arabskich
Przykład algorytmu - opis słowny Problem najwiekszego wspólnego dzielnika dwóch liczb naturalnych n i m, czyli najwiekszej liczby naturalnej, która dzieli obie liczby bez reszty Algorytm Euklidesa Algorytm Euklidesa (ok. 300 p.n.e) wyznaczania najwiekszego wspólnego dzielnika: K1 podziel n przez m. Niech r będzie resztą z tego dzielenia K2 jeżeli r = 0, wówczas m jest wynikiem, zakończ K3 podstaw n m, m r i wróć do kroku K1
Przykład algorytmu - opis słowny Problem najwiekszego wspólnego dzielnika dwóch liczb naturalnych n i m, czyli najwiekszej liczby naturalnej, która dzieli obie liczby bez reszty Algorytm Euklidesa Algorytm Euklidesa (ok. 300 p.n.e) wyznaczania najwiekszego wspólnego dzielnika: K1 podziel n przez m. Niech r będzie resztą z tego dzielenia K2 jeżeli r = 0, wówczas m jest wynikiem, zakończ K3 podstaw n m, m r i wróć do kroku K1 Np. Najwiekszy wspólny dzielnik n=6 i m=4: K1: r 6 modulo 4 K2: r = 2, zatem przechodzimy do K3 K3: n 4, m 2 K1: r 4 modulo 2 K2: r = 0, wynikiem jest m = 2, zakończ
Zapis algorytmu - schemat blokowy Schemat blokowy (block diagram, flowchart) to diagram, na którym algorytm jest reprezentowany przez opisane figury geometryczne, połączone liniami zgodnie z kolejnością wykonywania czynności wynikających z przyjętego algorytmu rozwiązania zadania pozwala dostrzec istotne etapy algorytmu i logiczne zależności między nimi Elementy schematu blokowego strzałka wskazuje kierunek przebiegu sterowania algorytmem, łączy inne bloki operand (prostokąt) wszystkie operacje z wyjątkiem instrukcji wyboru predykat (romb, sześciokąt) instrukcja wyboru etykieta (owal) początek lub koniec sekwencji schematu wejście/wyjście (równoległobok) Rysunek: Przykład - algorytm Euklidesa
Schematy blokowe instrukcji sterujących instrukcja bezpośredniego następstwa: {instrukcja1; instrukcja2;} instrukcja wyboru: {if (wyrażenie) instrukcja1;} {if (wyrażenie) instrukcja1; else instrukcja2;}
Schematy blokowe instrukcji sterujących instrukcje iteracyjne: while (wyrażenie) instrukcja; do {... } while(wyrażenie) for(wyr1; wyr2; wyr3) instrukcja;
Algorytm I Algorytm to ściśle określony ciąg kroków obliczeniowych, prowadzący do przekształcenia danych wejściowych w wyjściowe Cechy algorytmu Poprawnie zdefiniowany. Definicja zadania = co algorytm ma zrobić, jakie zadanie wykonać. Definicja problemu określa dane wejściowe (pochodzące z dokładnie określonego zbioru wartości dozwolonych) i dane wyjściowe - tzw. specyfikacja we/wy Precyzyjnie zdefiniowany. Każdy krok jest jednoznacznie określony, obejmuje operacje elementarne. Opis ciągu czynności, które po kolei mają być wykonane. Czynności te muszą być na tyle proste (i możliwe do wykonania), aby wykonawca algorytmu mógł je bez dodatkowego tłumaczenia zrealizować operacje elementarne (odpowiednio dobrany poziom szczegółowości) Skończony. Wyprodukuje wynik w skończonej liczbie kroków.
Algorytm II Jednoznaczny (powtarzalny). Algorytm dostaje pewne informacje (dane we) i zwraca (oczekiwane) wyniki dane wy. Wielokrotne wykonywanie dla identycznych danych we daje zawsze taki sam wynik. Kompletny. Uwzględnia wszystkie możliwe przypadki, jakie mogą wystąpić podczas jego wykonywania. Uniwersalny. Umożliwia rozwiązanie całej klasy zadań, a nie tylko pojedynczego, ustalonego zadania. Może istnieć kilka przepisów, które dają te same wyniki
Poprawność algorytmu Jeżeli: algorytm zatrzymuje się po skończonej liczbie kroków (posiada własność stopu) dla danych spełniajacych warunek poczatkowy (WP), algorytm generuje dane spełniajęce warunek końcowy (WK) algorytm jest poprawny
Poprawność algorytmu Jeżeli: algorytm zatrzymuje się po skończonej liczbie kroków (posiada własność stopu) dla danych spełniajacych warunek poczatkowy (WP), algorytm generuje dane spełniajęce warunek końcowy (WK) algorytm jest poprawny Poprawność algorytmu Algorytm jest częściowo poprawny względem danego warunku WP i danego warunku WK, gdy dla dowolnych danych wejściowych spełniających WP, jeżeli algorytm się zatrzymuje, to dane wyjściowe algorytmu spełniają warunek WK Algorytm jest całkowicie poprawny względem danego warunku WP i danego warunku WK, gdy dla dowolnych danych wejściowych spełniających warunek WP algorytm zatrzymuje się i dane wyjściowe tego algorytmu spełniaja warunek WK
Tworzenie algorytmu Definicja problemu (najlepiej w postaci modelu matematycznego) Koncepcja rozwiązania i wybór struktur danych Zapis algorytmu (stopniowe precyzowanie od koncepcji do pseudo-kodu lub kodu) Dowód poprawności i analiza złożoności obliczeniowej (Implementacja w wybranym języku programowania)
Klasy metod algorytmicznych Metoda TOP-DOWN (zstępująca, analityczna) problem jest dzielony na podproblemy podproblemy są rozwiązywane, a wyniki zapamiętywane, jeżeli będą użyte później używana jest rekursja i spamiętywanie Metoda BOTTOM-UP (wstępująca, syntetyczna) najpierw są rozwiązywane wszystkie (elementarne) podproblemy, które mogą być potrzebne następnie ich wyniki są używane do rozwiązywania większych podproblemów
Podstawowe metody rozwiązywania zadań algorytmicznych Metoda dziel i zwyciężaj Algorytmy zachłanne Planowanie dynamiczne
Rekurencja I Rekurencja / rekursja odwoływanie się funkcji lub definicji do samej siebie Silnia { 1 n = 0 n! = n (n 1)! n > 0 integer silnia(integer n){ if (n=0) then return 1; else return n*silnia(n-1); } Ciąg Fibbonacciego 0 n = 0 F n = 1 n = 1 F n 1 + F n 2 n > 1 integer Fib(integer n){ if (n=0) then return 0; else if (n=1) then return 1; else return Fib(n-1)+Fib(n-2); }
Rekurencja II Każda definicja rekurencyjna potrzebuje przynajmniej jednego przypadku bazowego (nie rekurencyjnego) w przeciwnym wypadku nigdy się nie zakończy Należy zachować ostrożność przy stosowaniu rekurencji!
Metoda dziel i zwyciężaj Problem dzieli się na mniejsze zadania tego samego typu i rozwiązuję się zdefiniowane podzadania Następnie łączy się częściowe rozwiązania w rozwiązanie całościowe problemu wyjściowego Jeżeli zdefiniowane podzadania są dokładnie takie same jak zadanie wyjściowe, lecz postawione dla mniejszych lub prostszych danych, to algorytm rozwiązania może być rekurencyjny Metoda jest przykładem zastosowania podejścia top-down konstrukcji algorytmu
Metoda dziel i zwyciężaj. Przykład: problem wież Hanoi Algorytm rozwiązuje zadanie dla N krążków, dzieląc problem na dwa problemy dla N-1 krążków i rozwiązując je Dane są trzy wieże (kołki): A, B, C. Na kołku A znajdują się trzy krążki ułożone malejąco, pozostałe kołki są puste Zadanie: przenieś krążki z kołka A na B, można korzystać z kołka C. Zachowane muszą być następujące zasady jednocześnie można przenieść tylko jeden kołek kołek większy nigdy nie może znaleźć się na kołku mniejszym Rozwiązanie dla trzech krążków: A B, A C, B C, A B, C A, C B, A B
Metoda dziel i zwyciężaj. Przykład: problem wież Hanoi - cd Algorytm rozwiązania problemu Wież Hanoi dla N N + krążków i trzech kołków A, B, C. WieżeHanoi(N,X,Y,Z){ //przenieś N krążków z X na Y używając Z if(n==1) przenieś(x," -> ", Y); else{ WieżeHanoi(N-1,X,Z,Y); //przenieś N-1 krążków z X na Z używając Y przenieś(x," -> ", Y); WieżeHanoi(N-1,Z,Y,X); //przenieś N-1 krążków z Z na Y używając X } }
Metoda dziel i zwyciężaj. Przykład: wyszukiwanie binarne Dane: posortowany ciąg liczb przechowywany w tablicy Zadanie: wyszukać w ciągu element o zadanej wartości Zastosowanie metody dziel i zwyciężaj dla tablicy o rozmiarze N i elementu x: dziel: weź element środkowy y (pozycja N/2); porównaj x z elementem środkowym zwyciężaj: jeżeli x = y zwróć pozycję; jeżeli x < y szukaj w lewej podtablicy, w przeciwnym przypadku szukaj w prawej podtablicy. integer WyszukajBin(ELEM T[N], ELEM x){ l = 1; p = N; integer m; do{ m = (l + p) / 2; if( T[m]=x) return m; else if( T[m]<x ) l = m + 1; else p = m - 1; } while( l<=p ); return -1; }
Metoda Dziel i zwyciężaj. Cechy Umożliwia często rozwiązywanie skomplikowanych problemów Daje efektywne algorytmy jeżeli: danych jest p podproblemów o rozmiarze n/p, podział i scalenie O(n) rozwiązanie trywialne O(1) wtedy metoda daje algorytm o złożoności O(nlogn) Algorytmy można łatwo zrównoleglić Wykorzystanie rekurencji do konstrukcji algorytmu metodą dziel i zwyciężaj może być nieefektywne Jeżeli podproblemy na siebie zachodzą, wtedy powtarzające się rozwiązania należy zapamiętywać (np. jak w przypadku ciągu Fibonacciego).
Metoda zachłanna Zastosowanie znajdowanie dla danego problemu rozwiązania pod pewnymi względami najlepszego z wszystkich możliwych rozwiązań Własność zachłannego wyboru Za pomocą lokalnie optymalnych (zachłannych) wyborów można uzyskać optymalne rozwiązanie całego zadania Optymalny wybór dokonany przez algorytm zachłanny może zależeć od poprzednich wyborów, ale nie zależy od wyborów kolejnych
Metoda zachłanna Zastosowanie znajdowanie dla danego problemu rozwiązania pod pewnymi względami najlepszego z wszystkich możliwych rozwiązań Własność zachłannego wyboru Za pomocą lokalnie optymalnych (zachłannych) wyborów można uzyskać optymalne rozwiązanie całego zadania Optymalny wybór dokonany przez algorytm zachłanny może zależeć od poprzednich wyborów, ale nie zależy od wyborów kolejnych Algorytm zachłanny konstruuje iteracyjnie rozwiązanie w sposób zachłanny, tzn. najbardziej obiecujący w danej chwili wybór rozwiązania częściowego Algorytm zachłanny nie przewiduje, czy w kolejnych krokach wykonywane działania będą miały sens, ale dokonuje decyzji lokalnie optymalnej, czyli w danej chwili najlepszej, kontynuując rozwiązywanie podproblemu wynikające z podjętej decyzji
Algorytmy zachłanne. Cechy Problem nie jest rozpatrywany globalnie Typowe zadanie rozwiązywane metodą zachłanną ma charakter optymalizacyjny Musi być znane kryterium pozwalające oceniać jakość rozwiązania Istnieje wiele problemów, dla których udowodnić można, że rozwiązanie zachłanne jest zawsze optymalne (np. algorytm Prima, Kruskala). W przypadku innych problemów zachłanność się nie opłaca lub może być problematyczna (np. problem wydawania reszty) Nie istnieje ogólna metoda dowodzenia, czy dla danego problemu rozwiązanie zachłanne (zawsze) odnajduje poprawny (i optymalny) wynik.
Algorytmy zachłanne. Budowa rozwiązania Niech Z będzie zbiorem skończonym, takim, że wszystkie możliwe rozwiązania R problemu P są podzbiorami Z Budowa rozwiązania zachłannego Na początku R = Aż do znalezenia rozwiązania, w każdej iteracji wybierane jest rozwiązanie częściowe z Z, które jest dołączane do rozwiązania problemu, takie, że: R = R {z} : R jest optymalne przy czym wybrane rozwiązanie z jest usuwane ze zbioru (Z = Z\ {z})
Algorytmy zachłanne. Przykład Dane: zbiór miast Zadanie: połącz miasta w sieć w ten sposób, aby z dowolnego miasta można było dotrzeć do każdego innego w najtańszy (np. najkrótszy) sposób Założenia: znane są tylko odległości dla par miast, dla których jest możliwe bezpośrednie połączenie
Algorytmy zachłanne. Przykład Dane: zbiór miast Zadanie: połącz miasta w sieć w ten sposób, aby z dowolnego miasta można było dotrzeć do każdego innego w najtańszy (np. najkrótszy) sposób Założenia: znane są tylko odległości dla par miast, dla których jest możliwe bezpośrednie połączenie Sieć połączeń między miastami nazywana jest grafem etykietowanym Rozwiązanie zadania sprowadza się do znalezienia minimalnego drzewa rozpinającego grafu Minimalne drzewo rozpinające grafu (MDR) To drzewo, które dociera do każdego węzła grafu dokładnie raz suma etykiet krawędzi grafu jest najmniejsza z możliwych
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd Algorytm Prima: zbuduj drzewo zdegenerowane, składające się z dowolnego wierzchołka grafu utwórz kolejkę priorytetową zawierającą wierzchołki osiągalne z MDR (w pierwszym kroku MDR zawiera tylko jeden wierzchołek na początku w kolejce będą sąsiedzi tylko tego wierzchołka) - priorytetem jest najmniejszy kosztu dotarcia do danego wierzchołka z MDR w każdym kolejnym kroku aż do przetworzenia wszystkich wierzchołków: wśród nieprzetworzonych wierzchołków (spoza dotychczasowego MDR) wybierz ten, dla którego koszt dojścia z dotychczasowego MDR jest najmniejszy dodaj do obecnego MDR wybrany wierzchołek i krawędź (uwaga! dodanie nowej krawędzi nie może prowadzić do powstania cyklu, w takim przypadku przejdź do nastepnej krawędzi w kolejce) aktualizuj kolejkę priorytetową uwzględniając nowe krawędzie wychodzące z dodanego wierzchołka
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Algorytmy zachłanne. Przykład - cd
Programowanie (planowanie) dynamiczne Własność optymalnej podstruktury Optymalne rozwiązanie całego problemu jest możliwe tylko przy optymalnym rozwiązaniu jego podproblemów. (Optymalne rozwiązanie całego problemu zawiera optymalne rozwiązania podproblemów).
Programowanie (planowanie) dynamiczne Własność optymalnej podstruktury Optymalne rozwiązanie całego problemu jest możliwe tylko przy optymalnym rozwiązaniu jego podproblemów. (Optymalne rozwiązanie całego problemu zawiera optymalne rozwiązania podproblemów). Spamiętywanie [Donald Michie, 1968] Technika optymalizacyjna przyspieszająca działanie algorytmów, polegająca na zapamiętywaniu wyników zwracanych przez funkcje do późniejszego ich wykorzystania, zamiast ponownego wywołania tych funkcji.
Programowanie (planowanie) dynamiczne Programowanie dynamiczne [Richard Bellman, 1940] W każdym kroku rozważamy wszystkie kombinacje powstałe z: dokonania konkretnego wyboru znalezienia optymalnych rozwiązań dla pozostałych dla pozostałych wyborów Optymalny wybór dokonany przez metodę programowania dynamicznego może zależeć od poprzednich wyborów oraz od wyborów kolejnych wtedy rozwiązanie optymalne jest modyfikowane
Programowanie dynamiczne Podproblemy cechują się następującymi własnościami: 1 nie są na ogół rozłączne - te same podproblemy są używane do rozwiązywania wielu większych podproblemów Rysunek: Kolejne wyrazy ciągu Fibbonaciego 2 z tego powodu należy zapamiętać rozwiązanie danego podproblemu, aby go ponownie użyć (spamiętywanie) 3 posiadają własność optymalnej podstruktury
Algorytmy i struktury danych Spis treści Organizacja zajęć Literatura Pojęcia podstawowe Metody algorytmiczne Programowanie dynamiczne. Przykład Poszukiwanie najtańszej drogi od początkowego węzła do węzła przeznaczenia w etykietowanym grafie skierowanym
Algorytmy i struktury danych Spis treści Organizacja zajęć Literatura Pojęcia podstawowe Metody algorytmiczne Programowanie dynamiczne. Przykład Poszukiwanie najtańszej drogi od początkowego węzła do węzła przeznaczenia w etykietowanym grafie skierowanym W algorytmie planowania dynamicznego długość najkrótszej ścieżki wiodącej z A do B powstaje przez znalezienie: K1 Najmniejszej z trzech odległości z A do C, D, G K2 Dodanie do tych odległości długości najkrótszej ścieżki prowadzącej z C, D i G do B K3 Wybór najkrótszej z nich
Programowanie dynamiczne. Przykład - cd Niech L(X ) oznacza najkrótszą ścieżkę prowadzącą z X do B. Wtedy: L(A) = min(5 + L(C), 14 + L(G), 3 + L(D)) Najpierw znajdowane są trzy mniejsze ścieżki optymalne: L(C), L(G), L(D), a później wykonując dodawania i porównania otrzymywana jest całkowita ścieżka optymalna: L(C) = min(2 + L(F ); 3 + L(E)) L(G) = min(7 + L(E); 6 + L(B)) L(D) = min(6 + L(G); 11 + L(C)) L(B) = 0
Programowanie dynamiczne. Przykład - cd Algorytm znajdowania najkrótszej ścieżki w grafie Jeśli węzłami są C i,..., C n i ścieżka ma się rozpocząć w C 1 i skończyć w C N, to algorytm wymaga obliczenia optymalnej ścieżki częściowej L(C i ), przedstawiającej najkrótszą ścieżkę z C i do C n, dla każdego i = 1... n: L(C i ) = min(odległość(c i, C k ) + L(C k )) przy czym C k to wszystkie węzły, do których prowadzą bezpośrednio krawędzie z C i Z założenia graf jest acykliczny, możliwe jest więc obliczenie wszystkich L(C i ), posuwając się z B4 do tyłu: 1 L(F ) = 7, L(E) = 5, L(G) = 6 2 L(C) = min(2 + L(F ), 3 + L(E)) = 3 + L(E) = 8 3 L(D) = min(11 + L(C), 6 + L(G)) = 6 + L(G) = 12 4 L(A) = min(5 + L(C), 3 + L(D), 14 + L(G)) = 5 + L(C) = 13 Optymalna ścieżka z A do B to: A C E B
Programowanie dynamiczne. Przykłady Algorytmy operujących na ciągach znaków, np. longest common subsequence, longest increasing subsequence Algorytm Floyda-Warshalla - poszukiwanie najkrótszych ścieżek pomiędzy wszystkimi parami wierzchołków w grafie etykietowanym Alorytm Cocke-Younger-Kasami (CYK) - sprawdzanie, czy słowo należy do języka bezkontekstowego Problem optymalnego nawiasowania macierzy Wybór instrukcji niskiego poziomu w kompilatorach
Redukcja Redukcja Technika rozwiązywania trudnego problemu poprzez jego transformację do innego problemu, dla którego znamy asymptotycznie optymalne algorytmy Kluczowe jest znalezienie takiego algorytmu redukującego, którego złożoność jest mniejsza niż złożoność algorytmu dla problemu zredukowanego
Redukcja Redukcja Technika rozwiązywania trudnego problemu poprzez jego transformację do innego problemu, dla którego znamy asymptotycznie optymalne algorytmy Kluczowe jest znalezienie takiego algorytmu redukującego, którego złożoność jest mniejsza niż złożoność algorytmu dla problemu zredukowanego Przykład: problem znalezienia mediany 1 Posortowanie elementów (kosztowna część algorytmu) 2 Wybór środkowego elementu (tania część algorytmu)