Temat: Powtórzenie wiadomości z PODSTAW INFORMATYKI I: Pojęcia: złożoność czasowa algorytmu, rząd funkcji kosztu. Algorytmy. Metody programistyczne. Struktury danych. Literatura. A. V. Aho, J.E. Hopcroft, J. D. Ullman - Projektowanie i analiza algorytmów komputerowych. L. Banachowski, K. Diks, W. Rytter Algorytmy i struktury danych 3. (!)T. H. Cormen, C. E. Leiserson, R. L. Rivest Wprowadzenie do algorytmów. (!)A. Drozdek, D. L. Simon Struktury danych w języku C 5. D. Harel Rzecz o istocie informatyki. Algorytmika 6. (!)R. Neapolitan, K. Naimipour, Podstawy algorytmów z przykładami w C++ 7. (!)V. V. Vazirani, Algorytmy aproksymacyjne ) Pojęcia: złożoność czasowa, rząd funkcji Aby wyznaczyć pesymistyczną złożoność czasową algorytmu należy: określić WP (warunek początkowy) i WK (warunek końcowy) problemu WP warunek początkowy formuła logiczna definiująca dane wejściowe problemu WK warunek końcowy formuła logiczna definiująca dane wyjściowe (wyniki rozwiązania problemu) uzyskane dla danych wejściowych spełniających WP ustalić rozmiar zadania Rozmiar zadania (problemu) to rozmiar tych danych wejściowych, których ilość wpływa na czas wykonania algorytmu, tzn. im większa jest ilość tych danych, tym dłużej realizuje się algorytm. Rozmiar zadania może zależeć od kilku parametrów wybrać operację elementarną
Operacja elementarna (inaczej operacja dominująca) to operacja charakterystyczna dla danego algorytmu. To taka operacja, której łączna liczba wykonań jest proporcjonalna do rozmiaru zadania, tzn. im większy jest rozmiar zadania, tym więcej razy realizuje się operacja elementarna. ustalić przypadek pesymistyczny Przypadek pesymistyczny to taki przypadek danych spełniających warunek WP, dla którego liczba wykonanych przez algorytm operacji elementarnych jest największa, przy ustalonym rozmiarze zadania wyznaczyć funkcję kosztu pesymistycznego T ( n) = max { t( d ): d } max D n D n zbiór zestawów możliwych danych wejściowych rozmiaru n t(d) liczba operacji elementarnych wykonanych dla danych wejściowych d Przy porównaniu efektywności czasowej dwóch algorytmów rozwiązujących ten sam problem uwzględnia się rzędy funkcji kosztu. Lemat o porównywaniu rzędów funkcji f(n), g(n) funkcje, których rzędy mamy porównać f ( n ) E = lim n g ( n ) Jeśli E=+, to funkcja g(n) ma niższy rząd niż funkcja f(n), co zapisujemy g(n)=o(f(n)) Jeśli E=c>0, to obie funkcje mają ten sam rząd, co zapisujemy g(n)= Θ (f(n)), Jeśli E=0, to funkcja f(n) ma niższy rząd niż funkcja g(n), co zapisujemy f(n)=o(g(n))
Przykład Problem wyszukiwania ustalonej liczby w ciągu nieuporządkowanym WP: A: a 0, a,..., a n- - ciąg liczb całkowitych (n > 0). Liczby w ciągu są różne. x szukana wartość. x jest liczbą całkowitą. WK: zmienna logiczna jest ustawia się wartości, gdy x występuje w ciągu albo przyjmuje wartość zero, gdy liczba x nie należy do ciągu. Algorytm i = 0; while (i<n && a i!=x) i++; jest=i<n; Rozmiar zadania: n - długość ciągu Operacja elementarna: porównania między elementami ciągu A a liczbą x. Przypadek pesymistyczny: ciąg, w którym x nie występuje albo występuje w indeksie n- Złożoność czasowa pesymistyczna: T ( n) = max { t( d ): d D } n max n = Złożoność czasowa algorytmu nie zależy od: języka programowania, szybkości procesora. ) Algorytmy Jakie problemy algorytmiczne były omówione w ramach wykładu z Podstaw Informatyki I? problem wyszukiwania w ciągu nieuporządkowanym - algorytm wyszukiwania liniowego o koszcie Θ(n), problem wyszukiwania w ciągu uporządkowanym - algorytm wyszukiwania binarnego o koszcie Θ (logn), problem sortowania 3
- dane w strukturze indeksowej (tablica) sortowanie szybkie, przez kopcowanie, przez połówkowe wstawianie koszt Θ(nlogn); - dane w strukturze liniowej bez dostępu indeksowego (lista) sortowanie bąbelkowe, sortowanie przez proste wstawienia, sortowanie przez proste wybieranie koszt Θ (n ) ), - dane z niewielkiego zakresu całkowitoliczbowego sortowanie przez zliczanie, sortowanie pozycyjne, sortowanie kubełkowe koszt Θ (n) 3) Metody programistyczne dziel i zwyciężaj Strategia typu dziel i zwyciężaj polega na dekompozycji problemu na pewną skończoną ilość podproblemów tego samego typu (faza dziel ), a następnie połączeniu w pewien sposób otrzymanych częściowych rozwiązań w celu odnalezienia rozwiązania globalnego (faza zwyciężaj ). Zastosowanie metody dziel i zwyciężaj często zmniejsza koszt czasowy algorytmu. Przykłady zastosowania strategii dziel i zwyciężaj : - wyszukiwanie binarne, - sprawdzanie, czy punkt należy do wielokąta wypukłego. technika zachłanna Algorytm zachłanny ( ang. greedy algorithm) wykonuje zawsze działanie, które wydaje się w danej chwili najkorzystniejsze. Wybiera zatem lokalnie optymalną możliwość w nadziei, że doprowadzi ona do globalnie optymalnego rozwiązania. Przykłady zastosowania strategii zachłannej: - problem kasjera, - problem wyboru zajęć, - ciągły problem plecakowy programowanie dynamiczne Użycie strategii programowania dynamicznego polega na zapamiętaniu w odpowiedniej strukturze (najczęściej tablicy) wyników rozwiązania podproblemów, na które został podzielony problem zasadniczy, unikając w ten sposób wielokrotnych obliczeń dla tego samego podproblemu. Programowanie dynamiczne prowadzi do całkowitej bądź częściowej eliminacji rekurencji.
Przykłady zastosowania programowania dynamicznego: - iteracyjna wersja funkcji wyznaczającej n-ty wyraz ciągu Fibbonaciego, - problem optymalnego nawiasowania w iloczynie macierzowym, - dyskretny problem plecakowy strategia powrotów Strategia powrotów ogranicza liczbę przypadków, które muszą być sprawdzone w trakcie poszukiwania optymalnego rozwiązania danego problemu trudno rozwiązalnego. Aby rozwiązać taki problem, musimy przeszukać przestrzeń stanów, przechodząc z jednego stanu w drugi, aż znajdziemy się w stanie określającym rozwiązanie problemu. Ponieważ dla każdego stanu może istnieć wiele dopuszczalnych ruchów, czyli wiele stanów, do których można dojść, możemy wybrać złe posunięcie. Jeżeli wykonamy zły ruch i znajdziemy się w sytuacji bez wyjścia (nie osiągając poprawnego rozwiązania i nie mając więcej dopuszczalnych posunięć do wykonania), musimy cofnąć ostatni ruch i spróbować zrobić inny. Jeżeli cofnięcie ostatniego ruchu w dalszym ciągu nie prowadzi do rozwiązania, to cofamy ruch przedostatni i próbujemy dalej. Ta metoda nosi nazwę metody powrotów. Metoda powrotów wymaga zapamiętania wszystkich wykonanych ruchów czy też wszystkich odwiedzonych stanów, aby możliwe było cofanie przesunięć. Naturalną techniką kodowania algorytmów opartych na strategii powrotów jest rekurencja. Przykłady zastosowania techniki powrotów: - problem znalezienia cyklu Hamiltona w grafie, - problem ustawienia hetmanów na szachownicy. ) Struktury danych a) Struktury indeksowe Struktury indeksowe to struktury, w których dane dostępne są za pośrednictwem indeksu, tzn. każdej danej przydzielony jest numer. Przykłady prostych struktur indeksowych: - tablica struktura indeksowa w pamięci wewnętrznej (operacyjnej), - plik binarny struktura indeksowa w pamięci zewnętrznej (dyskowej) 5
Struktury indeksowe to poindeksowane bloki pamięci o z góry określonej wielkości. Usunięcie danych ze struktury indeksowej nie powoduje zwolnienia (dealokacji) pamięci. b) Dynamiczne struktury liniowe Dynamiczne struktury liniowe to struktury, w których przydział pamięci dla danych odbywa się podczas realizacji operacji wstawiania danych do struktury. Usunięcie danych z tego typu struktury powoduje zwolnienie (dealokację) pamięci. Dodatkowo, w dynamicznych strukturach liniowych z danego elementu dostępny jest tylko jeden inny element struktury. Przykłady dynamicznych struktur liniowych: - stos operacje: push, pop, top, empty (LIFO last in, first out) - kolejka operacje: in, out, firt, empty (FIFO first in, first out), - lista operacje: insert, delete, search c) Struktury drzewiaste - drzewa BST, - drzewa AVL Przykład Załóżmy, że do początkowo pustej struktury zostały wstawione po kolei wstawione następujące liczby:,, 6,,, 0, 3, 30. Jak będą wyglądały poszczególne struktury: Tablica nieuporządkowana 6 0 3 30 0 3 5 6 7 Tablica uporządkowana 6 0 3 30 6
0 3 5 6 7 stos kolejka lista uporządkowana 30 wierzchołek stosu początek kolejki początek listy 3 0 6 6 6 0 0 3 3 30 30 NULL NULL NULL drzewo BST drzewo AVL 6 3 0 0 30 3 30 Zestawienie pesymistycznego kosztu czasowego operacji słownikowych w poznanych strukturach danych tablica tablica stos kolejka lista drzewo drzewo 7
nieuporząd- uprządko- BST AVL kowana wana search insert delete Zestawienie średniego kosztu czasowego operacji słownikowych w poznanych strukturach danych tablica nieuporządkowana search ( n) insert ( n) delete ( n) tablica uprządkowana stos kolejka lista drzewo BST drzewo AVL Θ Θ Θ d) Struktury do reprezentacji grafów - tablica sąsiedztwa, - tablica list incydencji, - tablica wag Przykład 3 Grafy bez wag Tablica sąsiedztwa dla grafu nieskierowanego 3 5 0 0 0 3 0 0 0 0 5 0 0 Tablica sąsiedztwa dla grafu skierowanego 3 5 0 0 0 0 0
3 0 0 0 0 5 0 0 0 Przykład dla grafu nieskierowanego, T tablica list incydencji T[]:, 3, 5 T[]:, 3, T[3]:,, T[]:, 3, 5 T[5]:, 5 3 Przykład grafu skierowanego T[]:, 3, 5 T[]: 3, T[3]: T[]: 3 T[5]: 5 3 Grafy z wagami Tablica wag 3 5 5 3 3-6.5 3 0 6 5.3 Poznane algorytmy grafowe dla grafów bez wag: - przeglądanie grafu metodą w głąb, - przeglądanie grafu metodą wszerz Poznane algorytmy grafowe dla grafów z wagami: - najkrótsze ścieżki w grafie z ustalonym źródłem: 9
- metoda Forda Bellmana dla grafów z nieujemnymi cyklami, - metoda Dijkstry dla grafów z nieujemnymi wagami, - najkrótsze ścieżki w grafie między każdą parą: - metoda Floyda dla grafów z nieujemnymi cyklami 0