Podyplomowe Studium Informatyki Wstęp do informatyki 30 godz. wykładu dr inż. Paweł Syty, 413GB, sylas@mif.pg.gda.pl, http://sylas.info Literatura D. Harel, Rzecz o istocie informatyki. Algorytmika, WNT 2001 J. Bentley, Perełki oprogramowania, wyd. II, WNT 2001 T.H. Cormen i inni, Wprowadzenie do algorytmów, WNT 2005 Materiały dydaktyczne http://students.sylas.info
Informatyka jako nauka Informatyka (w terminologii anglosaskiej Computer Science) w najbardziej ogólnym rozumieniu zajmuje się obliczeniami oraz badaniem procesów informacyjnych w aspekcie zarówno programowym jak i sprzętowym W węższym znaczeniu, które czasem jest traktowane jako skrótowe określenie, informatykę niemal utożsamia się z algorytmiką Tak czy inaczej, informatyki nie należy mylić z nauką o komputerach (a więc programowaniem komputerów, inżynierią komputerową, etc.). Informatyka istniałaby i bez komputerów, choć wyglądałaby zapewne inaczej. Znane są powiedzenia: Informatyka jest nauką o komputerach nie bardziej, niż astronomia jest nauką o teleskopach. Informatyka nie jest nauką o komputerach, podobnie jak chirurgia nie jest nauką o skalpelu.
Algorytm definicja, cechy, poprawność Obliczenie znalezienie rozwiązania danego zagadnienia w oparciu o dostępne dane i z użyciem algorytmu. Algorytm poddający się interpretacji skończony zbiór instrukcji wykonania zadania mającego określony stan końcowy dla każdego zestawu danych wejściowych. Formalnie algorytmem nazywa się każdy zestaw poleceń, który może wykonać uniwersalna, deterministyczna maszyna Turinga. Maszyną Turinga nazywa się abstrakcyjny model komputera (Alan Turing, 1936) mający dać ścisłą definicję algorytmu jako mechanicznej procedury.
Deterministyczna Maszyna Turinga ogólnie Maszyna Turinga składa się z nieskończenie długiej taśmy podzielonej na pola. Każde pole może znajdować się w jednym z N stanów. Maszyna zawsze jest ustawiona nad jednym z pól i znajduje się w jednym z M stanów. Zależnie od kombinacji stanu maszyny i pola, maszyna zapisuje nową wartość w polu, zmienia stan, a następnie może przesunąć się o jedno pole w prawo lub w lewo. Taka operacja nazywana jest rozkazem. Maszyna Turinga jest sterowana listą zawierającą dowolną ilość takich rozkazów. Liczby N i M mogą być dowolne, ale skończone. Lista rozkazów dla maszyny Turinga może być traktowana jako jej program. Maszyna posiadająca zdolność wykonywania dowolnego programu jest nazywana uniwersalną maszyną Turinga. Praktyczną realizacją uniwersalnej Maszyny Turinga jest komputer. Rzeczywiste komputery, w odróżnieniu od maszyny Turinga mają jednak ograniczoną wielkość pamięci.
Deterministyczna maszyna Turinga budowa i działanie 1. moduł sterujący, mogący znajdować się w jednym ze skończonej liczby stanów w danej chwili, 2. głowica czytająco-pisząca, 3. taśma, będąca układem pamięciowym podzielonym na jednostki i prawostronnie nieskończonym, może być traktowana jako model każdego obliczenia sekwencyjnego. Każde obliczenie można przedstawić poprzez siedem elementarnych operacji, tworzących tzw. język Turinga Posta mogący realizować dowolne możliwe obliczenia.
Język Turinga Posta (pierwszy język programowania): DRUKUJ-0 (oraz DRUKUJ-1) IDŹ-W-PRAWO IDŹ-W-LEWO IDŹ-DO-KROKU-i-JEŚLI-1 IDŹ-DO-KROKU-i-JEŚLI-0 STOP Instrukcjom przyporządkowane są kody, np. DRUKUJ-0 ma kod 000, DRUKUJ-1 ma kod 001, IDŹ-W-LEWO ma kod 010, STOP ma kod 100 itp.
Przykład programu: 1. DRUKUJ-0 2. IDŹ-W-LEWO 3. IDŹ-DO-KROKU-2-JEŚLI-1 4. DRUKUJ-1 5. IDŹ-W-PRAWO 6. IDŹ-DO-KROKU-2-JEŚLI-1 7. DRUKUJ-1 8. IDŹ-W-PRAWO 9. IDŹ-DO-KROKU-1-JEŚLI-1 10. STOP
Wszystkie możliwe algorytmy (a między nimi i dowody twierdzeń) można ustawić w ciąg i ponumerować (bo instrukcje są ponumerowane) tworzą one zbiór przeliczalny. Swój numer ma również sama maszyna Turinga czyli algorytm odczytujący i wykonujący dowolny zadany algorytm. Twierdzenie Gödla Swój numer ma również dowód, że niektórych algorytmów nie ma na liście (czyli nie istnieją) Przez analogię: nie istnieją dowody niektórych twierdzeń! Można je wypowiedzieć, ale nie sposób udowodnić. Ta teza jest treścią twierdzenia Gödla (1931): W ramach każdego formalizmu można wypowiedzieć twierdzenia, których nie można udowodnić w ramach tego formalizmu. 8
Na marginesie automaty komórkowe narzędzie do symulacji procesów fizycznych, chemicznych, biologicznych, biofizycznych itp., w których bierze udział wiele układów oddziałujących ze sobą obiekty matematyczne, interesujące z punktu widzenia teorii procesów dynamicznych zabawka reguły mogą być opisane językiem Turinga-Posta Najpopularniejszy automat komórkowy: gra w życie (Life) Conwaya 9
Własności algorytmu może korzystać z danych wejściowych prowadzi do jednej lub większej liczby danych wyjściowych wskazana własność ogólności rozwiązanie zawsze osiągnięte i to w skończonej liczbie kroków każdy możliwy przypadek przewidziany każdy krok jednoznacznie i precyzyjnie zdefiniowany korzysta z operacji podstawowych (plus iteracje i struktury warunkowe) Poprawność algorytmów Algorytm nazywamy poprawnym, jeżeli dla dowolnych poprawnych danych wejściowych, osiąga on punkt końcowy i otrzymujemy poprawne wyniki. 10
Cechy algorytmu poprawnego: Częściowa poprawność. Algorytm nazywamy częściowo poprawnym, gdy prawdziwa jest następująca implikacja: jeżeli algorytm osiągnie koniec dla dowolnych poprawnych danych wejściowych, to dane wyjściowe będą spełniać warunek końcowy. Własność określoności obliczeń. Algorytm posiada tę własność, jeżeli dla dowolnych poprawnych danych wejściowych, działanie algorytmu nie zostanie przerwane. Własność stopu. Algorytm posiada tę własność, jeżeli dla dowolnych poprawnych danych wejściowych, algorytm nie będzie działał w nieskończoność. 11
Dowodzenie poprawności algorytmów Metoda niezmienników Floyda wyróżnić newralgiczne punkty w algorytmie określić warunki (niezmienniki), jakie mają być spełnione w każdym wyróżnionym punkcie udowodnić poprawność kolejnych warunków, zakładając poprawność warunków poprzedzających własność stopu udowodnić np. metodą liczników iteracji lub metodą malejących wielkości 12
Struktury danych w dużym skrócie Struktura danych (ang. data structure) sposób uporządkowania informacji w komputerze. Na strukturach danych operują algorytmy. Przykładowe struktury danych: rekord tablica lista stos kolejka drzewo i jego liczne odmiany (np. drzewo binarne) graf 13
Złożoność obliczeniowa Służy do określania ilości zasobów potrzebnych do rozwiązania problemów obliczeniowych, takich jak czas, pamięć lub liczba procesorów. Wyniki pozytywne podają, co i jak da się obliczyć (zwykle mają postać algorytmu rozwiązującego dany problem wraz z dowodem poprawności oraz opisem potrzebnych zasobów) Wyniki negatywne dowodzą, czego nie da się obliczyć wykorzystując określoną ilość zasobów. Złożoność obliczeniowa algorytmu jest zwykle funkcją rozmiaru danych wejściowych. Złożoność ta zwykle nie zależy jednak tylko i wyłącznie od rozmiaru danych, ale może się znacznie różnić dla różnych zestawów danych o identycznym rozmiarze. Dwa często spotykane sposoby radzenia sobie z tym problemem to: branie pod uwagę przypadków najgorszych (złożoność pesymistyczna) i pewien sposób uśrednienia wszystkich możliwych przypadków (złożoność oczekiwana). 14
Złożoność czasowa Przyjętą miarą złożoności czasowej jest liczba wykonywanych operacji podstawowych w zależności od rozmiaru wejścia. Operacjami podstawowymi mogą być na przykład: podstawienie, porównanie lub prosta operacja arytmetyczna. Złożoność pamięciowa Podobnie jak złożoność czasowa jest miarą czasu działania algorytmu, tak złożoność pamięciowa jest miarą ilości wykorzystanej pamięci. Jako tę ilość najczęściej przyjmuje się użytą pamięć maszyny wyrażoną w bitach lub bajtach). 15
Oszacowania asymptotyczne Notacja Θ (Theta) Przykład: ½ n 2-3n = Θ(n 2 ). Uzasadnienie: Szukamy stałych c 1 i c 2 oraz n 0 takich, że c 1 n 2 <= ½ n 2-3n <= c 2 n 2 dla każdego n > n 0. Dzieląc przez n 2 otrzymujemy: c 1 <= ½ - 3/n <= c 2. Nierówność ta jest spełniona dla wszystkich n>6, np. gdy c 1 =1/14 i c 2 = ½. Zatem : ½ n 2-3n = Θ(n 2 ). 16
Przykład: 6n 3 Θ(n 2 ). Uzasadnienie: Załóżmy, że istnieją stałe c 2 oraz n 0 takie, że 6n 3 <= c 2 n 2 dla każdego n > n 0. Ale wtedy 6n <= c 2 /6 co nie może być prawdą dla dowolnie dużych n, ponieważ c 2 jest stałą. Notacja Θ asymptotycznie ogranicza funkcję od góry i od dołu. Oszacowania Θ używamy dla określenia pesymistycznej złożoności obliczeniowej algorytmów. Na przykład pesymistyczny czas wykonania sortowania przez wstawianie (czyli pesymistyczna złożoność obliczeniowa tego algorytmu) jest rzędu Θ(n 2 ). 17
Intuicyjnie, składniki niższego rzędu mogą być pominięte, gdyż są mało istotne dla dużych n. Składniki wyższego rzędu są wtedy dominujące. Przykład: dowolna funkcja kwadratowa jest rzędu Θ(n 2 ), tzn. an 2 + bn + c = Θ(n 2 ). d i Ogólnie, dowolny wielomian p(n) = a in = Θ(n d ), o ile a i są stałymi oraz a d > 0. Funkcję stałą określamy jako Θ(n 0 ) lub Θ(1). i = 0 18
Notacja O (dużego O) Przykład: ½ n 2-3n = O(n 2 ), ale również np. 5n +6 = O(n 2 ). Notacja O określa asymptotyczną granicę górną. Korzystamy z niej, żeby oszacować funkcję z góry, z dokładnością do stałego współczynnika. Można powiedzieć, że czas działania algorytmu sortowania przez wstawianie jest rzędu O(n 2 ) czyli algorytm ten nie zostanie nigdy wykonany wolniej niż w czasie kwadratowym (ale może być wykonany szybciej np. w czasie liniowym). 19
Notacja Ω (Omega) Notacja Ω określa asymptotyczną granicę dolną. Można powiedzieć, że czas działania algorytmu sortowania przez wstawianie jest rzędu Ω(n) czyli algorytm ten nie zostanie nigdy wykonany szybciej niż w czasie liniowym. 20
Własności oszacowań Twierdzenie. Dla każdych dwóch funkcji f(n) i g(n) zachodzi zależność f(n) = Θ(g(n)) wtedy i tylko wtedy, gdy f(n) = O(g(n)) i f(n) = Ω(g(n)). Przykład: Z tego, że ½ n 2-3n = Θ(n 2 ) wynika, że ½ n 2-3n = O(n 2 ) oraz ½ n 2-3n = Ω (n 2 ). Przechodniość: f(n) = Θ(g(n)) i g(n) = Θ(h(n)) implikuje f(n) = Θ(h(n)) f(n) = O(g(n)) i g(n) = O(h(n)) implikuje f(n) = O(h(n)) f(n) = Ω(g(n)) i g(n) = Ω(h(n)) implikuje f(n) = Ωh(n)) Zwrotność: f(n) = Θ(f(n)) f(n) = O(f(n)) f(n) = Ω(f(n)) Symetria: f(n) = Θ(g(n)) wtedy i tylko wtedy, gdy g(n) = Θ(f(n)) 21
Symetria transpozycyjna: f(n) = O(g(n)) wtedy i tylko wtedy, gdy g(n) = Ω(f(n)) f(n) = Ω(g(n)) wtedy i tylko wtedy, gdy g(n) = O(f(n)) Notacja asymptotyczna w równaniach Gdy notacja asymptotyczna pojawia się po prawej stronie równania, tak jak do tej pory (np. n = O(n 2 ) ), oznacza to przynależność: n O(n 2 ). Z kolei, np. równanie: 2n 2 + 3n +1 = 2 n 2 + Θ(n) oznacza, że Θ(n) jest pewną anonimową funkcją (o pomijalnej nazwie), tzn, 2n 2 + 3n +1 = 2 n 2 + f(n), gdzie f(n) jest funkcją należącą do zbioru Θ(n). W tym przypadku f(n) = 3n+1 = Θ(n). Użycie notacji asymptotycznej pozwala więc na uproszczenie równań poprzez wyeliminowanie nieistotnych jego składników. 22
Standardowe oszacowania f(n) = O(1) funkcja f(n) jest ograniczona przez funkcję stałą f(n) = O(log n) funkcja f(n) jest ograniczona przez funkcję logarytmiczną f(n) = O(n) funkcja f(n) jest ograniczona przez funkcję liniową f(n) = O(n log n) f(n) = O(n k ) funkcja f(n) jest ograniczona przez funkcję potęgową lub wielomian f(n) = O(a n ) funkcja f(n) jest ograniczona przez funkcję wykładniczą f(n) = O(n!) funkcja f(n) jest ograniczona przez silnię 23
Przykłady Jeżeli f(n) = 1000n 50 + 2n 2 oraz g(n) = 0,0000001n 50 + 665n, to f(n) = O(n 50 ) oraz g(n) = O(n 50 ), ale również f(n) = O(g(n)). S(n) = 1 + 2 +... + n. Ze wzorów sumacyjnych: S(n) = n(n+1)/2 < 3n 2, a zatem mamy złożoność O(n 2 ). 24
Rekurencja Dla rozwiązania danego problemu, algorytm wywołuje sam siebie przy rozwiązywaniu podobnych podproblemów. Przykład: silnia: n! = n(n-1)! Pseudokod: silnia(n): jeżeli n == 0 silnia = 1 w przeciwnym wypadku silnia = n * silnia(n-1) 25
Przykłady sformułowania problemów i propozycje algorytmów Sortowanie Wejście: tablica T zawierająca n elementów (a 1, a 2,..., a n ) typu porządkowego. Wyjście: tablica o tych samych elementach, ale uporządkowana niemalejąco. metoda przez wstawianie Algorytm polega na usuwaniu pewnego elementu z danych wejściowych i wstawianiu go na odpowiednie miejsce w wynikach. Wybór następnego elementu z danych jest dowolny. Szybkość tego algorytmu zależy od struktury danych wyjściowych i implementacji operacji wstawiania. 26
Schemat działania algorytmu: 1.Utwórz zbiór elementów posortowanych i przenieś do niego dowolny element ze zbioru nieposortowanego. 2.Weź dowolny element ze zbioru nieposortowanego. 3.Wyciągnięty element porównuj z kolejnymi elementami zbioru posortowanego póki nie napotkasz elementu równego lub elementu mniejszego, lub nie znajdziesz się na początku zbioru uporządkowanego. 4.Wyciągnięty element wstaw w miejsce gdzie skończyłeś porównywać. 5.Jeśli zbiór elementów nieuporządkowanych jest niepusty wróć do punktu 2. 27
Cechy: efektywny dla danych wstępnie posortowanych efektywny dla zbiorów o niewielkiej liczebności stabilny prosty do implementacji Złożoność obliczeniowa: O(n 2 ) sortowanie stogowe (przez kopcowanie) Wykorzystuje specjalną strukturę danych stóg (kopiec) Złożoność obliczeniowa: O(n log n) 28
sortowanie szybkie Wykorzystuje metodę dziel i zwyciężaj (rekurencja) Złożoność obliczeniowa: O(n log n) Wyszukiwanie Wejście: posortowana, n-elementowa tablica liczbowa T oraz liczba p. Wyjście: liczba naturalna, określająca pozycję elementu p w tablicy T, bądź zero, jeżeli element w tablicy nie występuje. wyszukiwanie liniowe złożoność obliczeniowa O(n) 29
wyszukiwanie binarne Wyszukiwanie binarne polega na tropieniu fragmentu tablicy, o którym wiemy, że musi zawierać element p, o ile element ten znajduje się w tablicy T. Początkowo tym fragmentem jest cała tablica. Przedział kurczy się po porównaniu środkowego elementu ze zmienną p i odrzuceniu odpowiedniej połowy tego przedziału. Proces trwa do chwili odnalezienia p w tablicy lub do momentu, gdy wiadomo, że przedział w którym musiałby się on znajdować, jest pusty. złożoność obliczeniowa O(log n) Generowanie podciągu Wejście: dwie liczby całkowite m i n, gdzie m <= n. Wyjście: posortowana lista m losowych liczb całkowitych z przedziału 1...n, wśród których żadna nie powtarza się dwukrotnie. 30
test losowy Należy wykorzystać algorytm, który analizuje kolejno liczby całkowite 1, 2,..., n i na podstawie odpowiedniego testu losowego decyduje, czy wybrać, czy też odrzucić każdą z nich. Zasada losowania zostanie szczegółowo omówiona na jedym z kolejnych wykładów. Ogólnie, aby wylosować W liczb spośród P pozostałych, należy następną liczbę wybierać z prawdopodobieństwem W/P. wybieranie Cel realizujemy wybierając m elementów wejściowej tablicy n-elementowej. Po każdym losowaniu sprawdzamy, czy liczba się nie powtórzyła a następnie sortujemy wybrane elementy. 31
przemieszanie Cel realizujemy mieszając (czyli zamieniając) pierwszych m elementów wejściowej tablicy n-elementowej (czyli liczby z przedziału 1...m) z elementami 1...n tej samej tablicy (oczywiście, w szczególnym przypadku taka zamiana może nie nastąpić, gdy chcąc przemieszać i-tą liczbę wylosujemy właśnie liczbę i). Wynikiem (po posortowaniu) jest tablica złożona z pierwszych m przemieszanych elementów. Problem komiwojażera Wejście: n miast, odległości pomiędzy miastami (d ij i, j = 1, 2,..., n); Wyjście: trasa komiwojażera przez wszystkie miasta (ale tylko jedna wizyta w każdym mieście permutacja miast) o najmniejszej sumie odległości. metoda siłowa obliczenie wszystkich możliwych dróg, złożoność O(n!) 32
Wieże Hanoi Zadanie polega na przeniesieniu wieży z krążków na inny pręt, z zachowaniem następujących reguł: jednorazowo można przenosić tylko jeden krążek dopuszczalne jest umieszczanie tylko mniejszego krążka na większym algorytm rekurencyjny złożoność O(2 n ) 33
Oznaczmy podstawki przez A, B, C, niech n oznacza liczbę krążków, ponumerujmy krążki od najmniejszego u góry do największego u dołu. W celu przeniesienia n krążków z A do B należy: przenieść n-1 krążków z A do C wówczas n-ty dysk samotnie pozostaje w A przenieść n-ty (największy krążek) z A do B przenieść n-1 krążków z C do B 34