Algorytmy rekurencyjne - przykład

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

Funkcje w PHP ABK.
Algorytmy sortowania i przeszukiwania
Instrukcje - wprowadzenie
Język C/C++ Funkcje.
Dzisiejszy wykład Wyjątki.
Programowanie obiektowe
Programowanie obiektowe PO PO - LAB 3 Wojciech Pieprzyca.
Operatory.
Wskaźniki repetytorium Wskaźniki int Y = 1, X = 2; X = 5; int *p = &X; Y X p 4 4 p = &Y; *p = 4; 5.
Język ANSI C Funkcje Wykład: Programowanie komputerów
Prowadzący: mgr inż. Elżbieta Majka
Algorytmy – różne przykłady
Static, const, volatile.
Filip Andrzejewski Remigiusz Chiluta
OOPC++ - wstêp w zakresie C1 C++ Bjarne Stroustrup AT&T Bell-Laboratories Historia – dodanie do C klas itp., jako punkt wyjścia przyjęto język Simula.
Sortowanie Zajęcia 13.
Modularyzacja i struktury danych w C Copyright, 2005 © Jerzy R. Nawrocki Wprowadzenie.
Modularyzacja i struktury danych w C Copyright, 2005 © Jerzy R. Nawrocki Wprowadzenie.
Programowanie imperatywne i język C Copyright, 2004 © Jerzy R. Nawrocki Wprowadzenie.
Język C – Część II Copyright, 2004 © Jerzy R. Nawrocki Wprowadzenie do informatyki.
Podstawy informatyki Wirtotechnologia – Wskaźniki i referencje
Podstawy informatyki Informatyka stosowana Prowadzący: Grzegorz Smyk
Tablice.
Laboratoria z „wstęp do programowania”
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Podstawy programowania PP – LAB6 Wojciech Pieprzyca.
Podstawy programowania
Podstawy programowania PP - LAB1 Wojciech Pieprzyca.
Pracę wykonali: Rafał Chmielorz Michał Sporek Jan Nowik
POJĘCIE ALGORYTMU Pojęcie algorytmu Etapy rozwiązywania zadań
Instrukcje sterujące część 1
Podstawy programowania
Podstawy informatyki 2013/2014
Rekurencja.
Podstawy informatyki 2012/2013
PORZĄDEK WŚRÓD INFORMACJI KLUCZEM DO SZYBKIEGO WYSZUKIWANIA
Podstawy programowania w języku C i C++
Algorytmy i Struktury Danych Typy algorytmów
IV OTWARTE MISTRZOSTWA OPOLA W PROGRAMOWANIU ZESPOŁOWYM
TABLICE C++.
Semantyczna poprawność algorytmów – dowodzenie za pomocą niezmienników
Łódź, 3 października 2013 r. Katedra Analizy Nieliniowej, WMiI UŁ Podstawy Programowania Złożona składnia języka C++
Procedury i funkcje.
Definicja pliku tekstowego Operacje wykonywane na plikach tekstowych
Podstawy programowania
Podstawy programowania w języku C i C++
Jerzy F. Kotowski1 Informatyka I Wykład 15 PIERWSZE KROKI.
C# Platforma .NET CZ.3 Kuba Ostrowski.
Programowanie obiektowe 2013/2014 Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Składnia instrukcji warunkowej if…
Temat 7: Instrukcje warunkowe
Algorytmy i Struktury Danych
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Rozwiązywanie układów równań liniowych różnymi metodami
Programowanie strukturalne i obiektowe C++ Przeładowanie operatorów Robert Nowak.
K URS JĘZYKA C++ – WYKŁAD 1 ( ) Łagodne wprowadzenie do języka C++
Rekurencja.
Tablice Zajęcia 8. Definicja Tablica (z ang. array) jest zmienną złożoną, która składa się z ciągu elementów tego samego typu. W pamięci komputera tablica.
Funkcje - rekurencja Zajęcia 8. Funkcje - definicja Ogólna postać funkcji w C++: typZwracany nazwaFunkcji(listaParametrówWejściowychFunkcji) { ciało funkcji.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Podstawy informatyki Tablice Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Wstęp do programowania wykład 3 Typy wyliczeniowe, tablice.
Wstęp do programowania Wykład 2 Dane, instrukcje, program.
ALGORYTMY I STRUKTURY DANYCH
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Język C++ Tablice Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Zapis prezentacji:

Algorytmy rekurencyjne - przykład Problem: tablica n liczb całkowitych tab[n]=tab[0], tab[1], …, tab[n-1]; czy w tablicy tab występuje liczba x (podana jako parametr)? Rozumowanie: wziąć pierwszy niezbadany element tablicy n-elementowej; jeśli aktualnie analizowany element tablicy jest równy x, to: wypisz „Sukces” i zakończ; w przeciwnym wypadku: zbadaj pozostałą część tablicy n-1 elementowej. Gdy przebadaliśmy całą tablicę i element nie został znaleziony, można np. wyświetlić komunikat o niepowodzeniu.

Algorytmy rekurencyjne - przykład Przykładowa realizacja: int const n=10; int tab[n]={1,2,3,2,-7,44,5,1,0,-3}; void szukaj(int tab[n], int left, int right, int x) //left, right - lewa i prawa granica obszaru poszukiwań //tab - tablica //x - wartość do odnalezienia { if (left>right) cout << "Element " << x << " nie został odnaleziony\n"; else if (tab[left]==x) cout <<"Znalazłem szukany element "<< x <<endl; szukaj(tab, left+1,right,x); }

Algorytmy rekurencyjne - cechy Program ilustruje podstawowe cechy typowego programu rekurencyjnego: Zakończenie programu jest jasno określone element znaleziony przekroczenie zakresu tablicy Duży problem zostaje rozbity na problemy elementarne, które umiemy rozwiązać i na analogiczny problem, tylko o mniejszym stopniu skomplikowaniu z tablicy o rozmiarze n schodzimy do tablicy o rozmiarze n-1

Algorytmy rekurencyjne - podstawowe błędy złe określenie warunku zakończenia programu niewłaściwa (nieefektywna) dekompozycja problemu

Algorytmy rekurencyjne - jak się wykonują? Przykład: Obliczanie silni unsigned long int silnia (int x) { if (x==0) return 1; else return x*silnia(x-1); } Proces przekazywania wyniku cząstkowego z poziomu niższego na wyższy Jak się liczy 3! Zagłębianie się programu z poziomu n na n-1 w celu dotarcia do przypadku elementarnego 0! Obliczanie wyników cząstkowych

Algorytmy rekurencyjne - niebezpieczeństwa Przykład: Ciąg Fibonacciego. (Elementy tego ciągu stanowią liczby naturalne takie, że kolejny wyraz (z wyjątkiem dwóch pierwszych) jest sumą dwóch poprzednich, tj. 1, 1, 2, 3, 5, 8, 13,…) unsigned long int Fibonaci(int n) { if(n<2) return n else return Fibonaci(n-1)+Fibonaci(n-2); } Obliczanie czwartego elementu ciągu Znaczna część obliczeń jest wykonywana więcej niż jeden raz!! Każde zacieniowane wyrażenie stanowi problem elementarny

Algorytmy rekurencyjne - niebezpieczeństwa Programy rekurencyjne są zazwyczaj dość pamięciożerne. Program obliczający 3! wywoła sam siebie tylko 3 razy, ale Fibonacci już nie jest taki łatwy do analizy. Przykład unsigned long int funkcja(int x) { if(x>100) return (x-10); else return funkcja(funkcja(x+11)); } Ile wywołań? Co się dzieje na większym przedziale liczbowym niż na rysunku? –ćw.

Algorytmy rekurencyjne - niebezpieczeństwa Stack overflow, czyli funkcja Ackermanna #include <iostream.h> int A(int n,int p) { if (n==0) return 1; if ((p==0)&&(n>=1)) if (n==1)return 2; else return n+2; if ((p>=1)&&(n>=1)) return A(A(n-1,p),p-1); } int main() cout << "A(3,4)="<<A(3,4) <<endl; Jaki jest powód komunikatu: „Stack overflow!” (przepełnienie stosu) podczas próby jego wykonania? Nastąpiła znaczna ilość wywołań funkcji Ackermanna.

Algorytmy rekurencyjne - niebezpieczeństwa Stack overflow, czyli funkcja Ackermanna Analiza wywołań Pobieżna analiza funkcji A prowadzi do spostrzeżenia: Analogicznie dla 2 otrzymamy: Z samej definicji funkcji Ackermanna możemy wywnioskować, że Na bazie tych równań możliwe jest rekurencyjne udowodnienie, że

Algorytmy rekurencyjne - niebezpieczeństwa Stack overflow, czyli funkcja Ackermanna Analiza wywołań Nieco gorsza jest sytuacja dla A(n,4), bo trudno jest podać wzór ogólny. Ale można zobaczyć przykłady liczbowe:

Algorytmy rekurencyjne - niebezpieczeństwa Błąd programisty! Sprowokowanie nieskończonej ilości wywołań rekurencyjnych! Przykład: int niesk(int n) { if(n==1) return 1; else if ((n%2)==0) //czy n jest parzyste? return niesk(n-2)*n; return niesk(n-1)*n; } Dla n>=2 wszystkie wywołania rekurencyjne kończą się parzystą liczbą n. Zatem dojdziemy do n=2, potem n=0, n=-2,…… Nigdzie po drodze nie ma przypadku elementarnego!

Algorytmy rekurencyjne - niebezpieczeństwa Błąd programisty! Jak go uniknąć? Sprawdzić matematycznie poprawność definicji rekurencyjnej, tzn. określić dziedziny wartości funkcji, udowodnić, że się ona zakończy, podać złożoność obliczeniową To nie wystarczy! Nie wiadomo, jak rzeczywisty kompilator wykona tę funkcję. int N(int n, int p) { if(n==0) return 1; else return N(n-1,N(n-p,p)); } Można udowodnić matematycznie, że powyższa definicja jest poprawna w tym sensie, że dla dowolnych n>=0, p>=0 jej wynik jest określony i wynosi 1. Zakłada się, że wartość argumentu wywołania funkcji jest obliczana tylko wtedy, gdy jest to konieczne. Jak wykona to typowy kompilator C++? Wszystkie parametry funkcji rekurencyjnej są obliczane jako pierwsze, a potem wywołana jest funkcja – wywołanie przez wartość.

Algorytmy rekurencyjne - niebezpieczeństwa Zapętlenie jest spowodowane próbą obliczenia parametru p, tymczasem to drugie wywołanie nie jest potrzebne do zakończenia funkcji! Kompilator tego nie wie! int N(int n, int p) { if(n==0) return 1; else return N(n-1,N(n-p,p)); } Wszystkie parametry funkcji rekurencyjnej są obliczane jako pierwsze, a potem wywołana jest funkcja – wywołanie przez wartość.

Algorytmy rekurencyjne - zalety Łatwe do zrozumienia Zajmują mało miejsca (liczba wierszy kodu) – ewentualnie łatwo znaleźć błędy Jak w takim razie usunąć wady? Inaczej zbudować rekurencję. Rekurencja „z parametrem dodatkowym” Rekurencja „naturalna” –poprzednie przykłady Na czym polega?

Algorytmy rekurencyjne - zalety Parametry domyślne funkcji fun(int a, int k=1) unsigned long int silnia (int x) { if (x==0) return 1; else return x*silnia(x-1); } Funkcja może być wywołana na dwa sposoby: Poprzez określenie wartości drugiego parametru, np. fun(2,5), wtedy k przyjmuje wartość 5; Bez określania wartości drugiego parametru, np. fun(12), wtedy k przyjmuje wartość domyślną równą tej podanej w nagłówku, czyli 1. unsigned long int silnia2 (int x, int tmp=1) { if (x==0) return tmp; else return silnia2(x-1,x*tmp); } Parametr dodatkowy przekazuje elementy wyniku końcowego – program nie ma potrzeby przekazywania wyniku obliczeń do góry, piętro po piętrze – ostatni aktywny poziom dostarczy wynik!

Algorytmy rekurencyjne - strategia „dziel izwyciężaj”

Algorytmy rekurencyjne - strategia „dziel izwyciężaj”

Algorytmy rekurencyjne - strategia „dziel izwyciężaj” Twierdzenie o rekurencji uniwersalnej podaje metodę rozwiązania tego typu rekurencji.

Algorytmy rekurencyjne - strategia „dziel izwyciężaj”

Sortowanie przez scalanie

Sortowanie przez scalanie Zapis tego algorytmu w pseudokodzie:

Sortowanie przez scalanie Wywołania rekurencyjne Ćwiczenie: Zapisać w C++

Sortowanie przez scalanie Twierdzenie:

Sortowanie przez scalanie

Sortowanie przez scalanie

Sortowanie przez scalanie Komentarz:

Sortowanie przez scalanie Twierdzenie:

Sortowanie przez scalanie

Sortowanie przez scalanie Gdy n jest dowolną liczbą naturalną rozwiązanie rekurencji jest trudniejsze. Należy wykorzystać następujący wzór sumacyjny: Twierdzenie:

Sortowanie przez scalanie Dowód:

Sortowanie przez scalanie Dowód:

Sortowanie przez scalanie

Sortowanie przez scalanie Korzystając z podanego wcześniej wzoru sumacyjnego, możemy policzyć wartość sumy: co daje ostatecznie: