Podstawy Informatyki Metalurgia, I rok Wykład 5 Rekurencja
Rekurencja z łacińskiego oznacza to przybiec z powrotem - osiągniesz rzecz wielką, jeśli zawrócisz po to, by osiągnąć rzeczy małe Przykład: Małe dziecko otrzymuje polecenie posprzątania rozrzuconych klocków do pudełka. zebrać wszystkie klocki naraz???? - skomplikowane zadanie wziąć jeden klocek, przełożyć go do pudełka, a następnie zrobić to samo z pozostałymi klockami??? - prosta czynność
Duży problem został rozłożony na problem elementarny, który umiemy rozwiązać. Problem elementarny jest mniej skomplikowany niż problem początkowy. Zakończenie algorytmu jest jasno określone ( w momencie gdy na podłodze nie ma rozrzuconych klocków )
Mamy obliczyć: a n Matematycznie: Wiemy że: a n =a x a n-1 (a n-1 jest łatwiej obliczyć niż a n ) Jeśli jest nadal trudno, to zawsze można wstawić: a n-1 =a x a n-2, gdzie: a n-2 =a x a n-3 itd. wystarczy wiedzieć tylko, że: a 0 =1 aby obliczyć dowolną potęgę a
Def: Program rekurencyjny jest to program, który wywołuje sam siebie Problem: Dysponujemy tablicą n liczb całkowitych A(n) o elementach: a(1),a(2), a(3),..., a(n) Zadanie: sprawdzić, czy w tablicy A występuje liczba x Rozwiązanie: wziąć pierwszy niezbadany element tablicy n elementowej, jeśli aktualnie analizowany element tablicy jest równy x to: wypisz sukces i zakończ działanie w przeciwnym wypadku: zbadaj pozostałą część tablicy n-1 elementów
W programach rekurencyjnych: zakończenie programu jest jasno określone (znaleziony element, przekroczony zakres tablicy), duży problem zostaje rozłożony na problemy elementarne, które umiemy rozwiązać Podstawowe błędy: złe określenie warunku zakończenia programu, niewłaściwa (nieefektywna) dekompozycja problemu.
Algorytmy sortowania danych Najprostsze sortowanie: zamiana dwóch elementów Sortowanie przez selekcję Opis: trzeba wyznaczyć najmniejszy element w ciągu; zamienić go miejscami z pierwszym elementem ciągu, wyznaczyć najmniejszy element w a[2..n] i zamienić go z drugim elementem w ciągu, itd.
Sortowanie przez selekcję - algorytm dla i := 1 do n-1 wykonuj początek min := i; dla j := i+1 do n wykonuj jeśli a[ j ] < a[ min ] to min := j; a[ min ] <-> a[ j ] {zamiana miejscami a[ min ] z a[ j ]} koniec
Sortowanie przez wstawianie (układanie kart do brydża) Opis: metoda polega na wstawianiu następnej karty we właściwe miejsce uporządkowanych uprzednio kart 9 8 3 5 7 9 8 3 5 7 8 9 3 5 7 3 8 9 5 7 3 5 8 9 7 3 5 7 8 9
Sortowanie przez wstawianie - algorytm dla i=2,...,liczba elementów tablicy wykonuj { j :=i podczas gdy j > 1 i x[ j-1 ] > x[ j ] wykonuj { pom := x[ j ] x[ j ] := x[ j-1] x[ j-1] := pom j := j-1 } }
Sortowanie bąbelkowe 0 1 40 2 2 2 2 40 40 39 4 4 4 4 6 4 39 39 39 39 18 4 6 6 6 6 6 4 4 18 18 18 18 18 18 20 20 20 20 20 20 20 20 20 Tablica jest przeszukiwana od dołu. Element zacieniony jest tym, który w pojedynczym przebiegu uleciał do góry jako najlżejszy. Analizowane są zawsze 2 sąsiadujące ze sobą elementy. Jeśli nie są uporządkowane (u góry jest element cięższy ) to następuje ich zamiana.
Wynik sortowania bąbelkowego 0 1 2 3 4 5 6 40 2 2 2 2 2 2 2 40 4 4 4 4 4 39 4 40 6 6 6 6 6 39 6 40 18 18 18 18 6 39 18 40 20 20 4 18 18 39 20 40 39 20 20 20 20 30 39 40
Algorytm sortowania bąbelkowego TAB : Tablica [1..n] elementów typu rzeczywistego i,j : całkowite pom: rzeczywiste Początek {programu} Dla i:=1 do n-1 wykonuj dla j:=n do i+1 z krokiem -1wykonuj Jeśli TAB[j]<TAB[j-1] to początek pom:=tab[j-1]; TAB[j-1]:=TAB[j]; TAB[j]:=pom koniec Koniec {programu}.
Dość często zdarzają się puste przebiegi (nie jest dokonywana żadna wymiana, bowiem elementy są już posortowane. Algorytm jest bardzo wrażliwy na konfigurację początkową danych. Wersja 1: 4 2 6 18 20 39 40 Wersja 2: 4 6 18 20 39 40 2 (wersja 1 wymaga jednej zamiany, a wersja 2 wymaga aż sześciu przebiegów)
Wieża Hanoi A B C Chcemy przenieść krążki z A na B, wykorzystując kołek C. Przenosimy po 1 krążku. Większy krążek nigdy nie może być umieszczony na mniejszym krążku..
A B C A -> B; A -> C; B -> C; A -> B; C -> A; C -> B; A -> B;
A B C 1. A -> B; 8. A -> C; 2. A -> C; 9. B -> C; 3. B -> C; 10. B -> A; 4. A -> B; 11. C -> A; 5. C -> A; 12. B -> C; 6. C -> B; 13. A -> B; 7. A -> B; 14. A -> C; 15. B -> C;
A B C Legenda Tybetu: po przeniesieniu 64 krążków nastąpi koniec świata. Liczba pojedynczych przeniesień: minimum 2 N - 1 (2 3-1 = 8-1 = 7 dla 3 krążków). Dla 64 to jest 2 64-1 tj 18446744073709551615 Jeżeli przeniesienie 1 krążka wymaga 2 sekund, to na przeniesienie 64 krążków potrzeba 1 biliona lat (4,5 miliarda lat temu powstała ziemia). Przy szybkości przenoszenia 1 miliona krążków na sekundę, całkowity czas przeniesienia 64 krążków wynosi minimum pół miliona lat..
Wieża Hanoi - algorytm Podprogram przenieś N z X na Y używając Z; jeżeli N=1, to wypisz X -> Y ; w przeciwnym razie (tj. jeżeli N>1) wykonaj, co następuje: wywołaj przenieś N-1 z X na Z używając Y; wypisz X->Y ; wywołaj przenieś N-1 z Z na Y używając X; wróć. Na stronie: http://wipos.p.lodz.pl/zylla/games/hanoi7p.html jest aplikacja do gry w wieże Hanoi
Jak wykonują się programy rekurencyjne? Zadanie: Obliczyć n! 0! = 1 N! = N*(n-1)! Dla n>=1 Jak to wygląda w praktyce dla n = 3 (3! =?) n = 0? nie 3*2! n = 0? nie 2*1! n = 0? nie 1*0! n = 0? tak 1 -pionowe strzałki oznaczają zagłębianie się programu z poziomu n na n-1, itd., aż do przypadku elementarnego 0!, - pozioma strzałka oznacza obliczanie wyników cząstkowych, - ukośna strzałka prezentuje przekazywanie wyniku cząstkowego z poziomu niższego na wyższy)
Nie rekurencyjne, ale ciekawe algorytmy
Algorytm sprawdzania czy trójkąt jest prostokątny We: a,b,c boki trójkąta d = a*a + b*b WY: trójkąt nie jest prostokątny N? d=c*c T WY: trójkąt jest prostokątny
Algorytm sprawdzania czy trójkąt jest prostokątny Program trojkat prostokatny; { Deklaracja zmiennych } a,b,c,d: całkowita; Początek pisz( podaj boki a,b,c); d:=a*a+b*b; jeżeli (d=c*c) to pisz ( trójkąt prostokątny ) Gdzie tkwi błąd? Jak poprawić ten program? koniec.. w przeciwnym razie pisz ( trójkąt nie jest prostokątny )
Algorytm sprawdzania parzystości liczby We: sprawdzana liczba x y = (x/2)*2 WY: x nieparzyste N? x=y T WY: x parzyste
Algorytm sprawdzania parzystości liczby Program parzystosc; { Deklaracja zmiennych } x,y: całkowita; Początek pisz( podaj liczbe x ); czytaj(x); y := x/2; y := y*2; jeżeli (x=y) to pisz ( liczba x jest parzysta ) w przeciwnym razie pisz ( liczba x jest nieparzysta ) koniec. Uwaga: Program ma sens tylko dzięki własności dzielenia liczb całkowitych.
Sito Erastotenesa Sito Erastotenesa Wyszukiwanie liczb pierwszych 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2
Sito Erastotenesa 2 3 5 7 9 11 13 15 17 19 21 23 25 2 3 5 7 11 13 17 19 23 25 Kiedy koniec? Dla n
program sito a: tablica [1...1000] elementów całkowitych i,j,n,m,x,y:całkowite pisz 'podaj górną granicę przedziału, max 1000' czytaj n m=int(sqrt(n)) {maksymalny mnoznik pierwiastek z n) dla i=1 do n wykonuj a[i]=i {podstawienie kolejnych liczb do tablicy} dla j=2 do m wykonuj początek jeśli a[j] <>0 to początek dla i=j+1 do n wykonuj początek x=a[i] y=(x/j)*j {sprawdzanie podzielności} jeśli x=y to a[i]=0 koniec koniec koniec
pisz 'w podanym zakresie liczby pierwsze to:' dla i=2 do n jeśli a[i] <>0 to drukuj a[i] koniec
Optymalizacja algorytmów Zawsze poszukujemy najlepszego algorytmu ze względu na czas i złożoność obliczeń. Wydajność czasowa algorytmu: - funkcja O(n), określająca ile czasu potrzebuje dany algorytm na rozwiązanie problemu o rozmiarze n (parametr n zależy od analizowanego zagadnienia, np. dla sortowania tablicy, n jest liczbą danych do sortowania, itp.) Przykład: Program zliczający sumę elementów tablicy A[n]: Suma :=0 dla i:=0 do i:=n suma := suma + A[i] Jedna instrukcja wymaga jednej jednostki czasu. Złożoność obliczeniowa O(n) = n+2. Ponieważ najbardziej znaczącym składnikiem jest n, więc, O(n) = n.
Złożoność obliczeniowa, c.d. Przykład: Program obliczający sumę elementów tablicy dwuwymiarowej A[n,n]: Suma :=0 // 1 dla i:=0 do i:=n //1 dla j:=0 do j:=n //n suma := suma + A[i,j] //n^2 Jedna instrukcja wymaga jednej jednostki czasu. Złożoność obliczeniowa O(n) = n^2 + n + 2 Przyjmujemy, że złożoność obliczeniowa O(n) = n^2 + n.
Czas pracy algorytmów różnych klas c(n) c(n) 10 20 30 40 N 10 20 30 40 N 2 100 400 900 1600 2 n 1024 1048576 1073741824 1099511627776 N! 3628800 2*10 18 6*10 32 3*10 57 Czas działania algorytmu zależy nie tylko od rozmiaru danych wejściowych, ale również od ich wartości lub układu (rozmieszczenia)..
Skrócenie czasu obliczeń Wielokrotne mnożenie zamiast potęgowania Przykład: y=x 5 y=x*x*x*x*x jest szybsze i dokładniejsze niż: y=x^5 gdyż funkcja potęgowania jest rozwijana jako: y=e 5*ln(x) a dodatkowo, funkcje ln i e x są obliczane jako sumy określonych ciągów. Ze zrozumiałych przyczyn zaniedbuje się dalsze wyrazy ciągu, co zmniejsza dokładność. Tak więc często otrzymujemy wyniki: 3^3=26.9999999999999 itp
Obliczenia numeryczne Obliczanie pierwiastka kwadratowego: Przykład: Jak obliczyć pierwiastek z x? Metoda Newtona: y= y+ 2 yx x- liczba pierwiastkowana y - wynik pierwiastkowania.
Obliczanie pierwiastka kwadratowego - algorytm: Program pierwiastek kwadratowy; { Deklaracja zmiennych } x,y: i : Początek. koniec. rzeczywista; całkowita; pisz( podaj x); y := 1; dla i:=0 do i:= 20 y:=(y+x/y)/2; pisz ( pierwiastek z, x, =, y)