background image

Matematyka Dyskretna

Andrzej Szepietowski

25 czerwca 2002 roku

background image
background image

Rozdział 1

Rekurencja

1.1

Wie˙ze Hanoi

Rekurencja jest to zdolno´s´c podprogramu (procedury lub funkcji) do wywoływania sa-
mego siebie. Zacznijmy od przykładu wie˙z Hanoi. Przypu´s´cmy, ˙ze mamy trzy wie˙ze lub
trzy paliki:

,



i



. Na pierwszym paliku,

, znajduj¸a si¸e trzy kr¸a˙zki ró˙znej wielko´sci,

nanizane w porz¸adku od najwi¸ekszego na dole do najmniejszego na górze. Paliki



i



s¸a na pocz¸atku puste. Nale˙zy przenie´s´c wszystkie kr¸a˙zki z palika

na



, posługuj¸ac si¸e

w razie potrzeby palikiem



, według nast¸epuj¸acych reguł:



mo˙zna przenosi´c po jednym kr¸a˙zku z jednego palika na inny,



nie mo˙zna umieszcza´c wi¸ekszego kr¸a˙zka na mniejszym.

Rozwi¸azaniem tej łamigłówki dla trzech kr¸a˙zków jest nast¸epuj¸acy ci¸ag siedmiu przeło-

˙ze´n:







 







  



 









gdzie zapis



oznacza przeniesienie szczytowego kr¸a˙zka z palika

na palik



.

Chodzi nam teraz o algorytm, który dla dowolnej liczby



kr¸a˙zków wypisze ci¸ag

operacji potrzebnych do przeło˙zenia



kr¸a˙zków z palika

na palik



.

Algorytm przekładania kr¸a˙zków



je˙zeli



, to przekładamy ten jeden kr¸a˙zek





,



je˙zeli

 

, to:



przekładamy



kr¸a˙zków z

na pomocniczy palik



(posługuj¸ac si¸e w

razie potrzeby palikiem



),



przekładamy



-ty kr¸a˙zek z

na



,



przekładamy



kr¸a˙zków z



na

(za pomoc¸a palika



).

3

background image

4

Rozdział 1. Rekurencja

Nietrudno zauwa˙zy´c, ˙ze je˙zeli proces przekładania

 

kr¸a˙zków jest prawidłowy, to

cały proces te˙z jest prawidłowy, poniewa˙z obecno´s´c najwi¸ekszego kr¸a˙zka na dole palika
nie przeszkadza w przekładaniu





mniejszych kr¸a˙zków.

Powy˙zszy algorytm opiszmy teraz za pomoc¸a rekurencyjnej procedury przenie´s, któ-

ra odwołuje si¸e sama do siebie i wypisuje ci¸ag instrukcji przeniesienia



kr¸a˙zków z palika

na palik



.

procedura przenie´s(



kr¸a˙zków z

na



, za pomoc¸a



):



je˙zeli





, to wypisz

 

,



je˙zeli



, to



przenie´s(



kr¸a˙zków z

na



, za pomoc¸a



),



wypisz

 

,



przenie´s(



kr¸a˙zków z



na



, za pomoc¸a

).

Rysunek 1.1: Schemat działania procedury przenie´s dla wie˙z Hanoi z trzema kr¸a˙zkami

































 





































Na rysunku 8.1 zilustrowano działanie procedury przenie´s dla





. Skrót



 



oznacza wywołanie procedury przenie´s(



kr¸a˙zków z

na



, za pomoc¸a



). Strzałki

w dół oznaczaj¸a wywołanie procedury, strzałki w gór¸e powroty po wykonaniu procedu-
ry, a strzałki poziome odpowiadaj¸a nast¸epstwu instrukcji w ramach jednego wykonania
procedury.

background image

1.2. Algorytm Euklidesa, wersja rekurencyjna

5

1.2

Algorytm Euklidesa, wersja rekurencyjna

Innym przykładem algorytmu rekurencyjnego mo˙ze by ´c rekurencyjna wersja algorytmu
Euklidesa, który oblicza najwi¸ekszy wspólny dzielnik dwóch dodatnich liczb naturalnych

i



:

fun¯kcja NWD(a,b):



je˙zeli





, to





 



,



je˙zeli





, to





 



 







 

,



je˙zeli



, to





 



 









.

W j¸ezyku Pascal powy˙zsz¸a procedur¸e mo˙zemy zapisa´c w nast¸epuj¸acy sposób:

function NWD(a,b:integer):integer;

begin

if a=b then NWD:=a

else if





then NWD:=NWD(a-b,b)

else NWD:=NWD(a,b-a)

end;

Rysunek 1.2: Schemat działania rekurencyjnej wersji algorytmu Euklidesa

NWD(5,3):=1

NWD(2,3):=1

NWD(2,1):=1

NWD(1,1):=1

Na rysunku 8.2 przedstawiono proces obliczania funkcji NWD(7,3).

1.3

Funkcje rekurencyjne

Czasami wygodnie jest zdefiniowa´c funkcje za pomoc¸a wzoru rekurencyjnego. Na przy-
kład funkcj¸e silnia definiuje si¸e zwykle za pomoc¸a nast¸epuj¸acych dwóch równa ´n:























 













 

"!

background image

6

Rozdział 1. Rekurencja

Podobnie mo˙zna definiowa´c inne funkcje ze zbioru liczb naturalnych w zbiór liczb natu-
ralnych. Definicja taka zawiera przepis, jak policzy´c warto´s´c funkcji dla warto´sci pocz¸atkowych,
oraz drugi przepis, jak wyliczy´c warto´s´c dla argumentu



za pomoc¸a warto´sci funkcji dla

mniejszych argumentów.

1.4

Funkcja (ci¸ag) Fibonacciego

Nast¸epnym przykładem rekurencyjnego definiowania funkcji jest funkcja Fibonacciego,
okre´slona równaniami:



















































  

!

Kolejne warto´sci funkcji Fibonacciego to:



























!!!

Udowodnimy teraz przez indukcj¸e, ˙ze









 









(1.1)

gdzie





















"



oraz





















"



Równo´s´c (1.1) zachodzi dla







i







. Załó˙zmy teraz, ˙ze zachodzi dla wszystkich

argumentów mniejszych od



. Zauwa˙zmy, ˙ze



oraz

s¸a rozwi¸azaniami równania















, mamy wi¸ec











oraz





 

a tak˙ze





 







 

oraz

















. Łatwo teraz mo˙zna pokaza´c, ˙ze































 









.

Poniewa˙z







, mamy











, wi¸ec warto´s´c







jest równa

!



po zaokr¸agleniu do najbli˙zszej liczby naturalnej i funkcja Fibonacciego ro´snie

wykładniczo.

1.5

Funkcja Ackermanna

Funkcja Ackermanna okre´slona jest, dla liczb naturalnych



#"

 



, nast¸epuj¸acymi rów-

naniami:





$"





&%



"

 

































 









#"

















$"













$"

 

"!

Funkcja Ackermanna jest przykładem funkcji maj¸acej do´s´c prost¸a definicj¸e, ale jest prak-
tycznie nieobliczalna z tego powodu, ˙ze jej warto´sci szybko rosn¸a. Na przykład:













('











)



+*

,



background image

1.6. Algorytm sortowania przez scalanie

7











)

)









'





)

)

)



i ogólnie



















)

 

!

1.6

Algorytm sortowania przez scalanie

Zajmijmy si¸e teraz pewnym prostym rekurencyjnym algorytem sortowania ci¸agu. Dla
prostoty załó˙zmy, ˙ze długo´s´c ci¸agu jest pot¸eg¸a dwójki.

Algorytm sortowania



je˙zeli ci¸ag ma długo´s´c jeden, to jest ju˙z posortowany,



je˙zeli ci¸ag jest dłu˙zszy, to:



dzielimy go na połowy,



sortujemy te połowy,



ł¸aczymy posortowane połowy w jeden posortowany ci¸ag.

Istota pomysłu polega na tym, ˙ze mo˙zna szybko poł¸aczy ´c dwa posortowane ci¸agi w jeden
posortowany ci¸ag. Algorytm ł¸aczenia wyja´snijmy na przykładzie. Przypu´s´cmy, ˙ze mamy
dwa ci¸agi:



























'









i ˙ze chcemy je poł¸aczy´c w posortowany ci¸ag



. Na pocz¸atku ci¸ag



jest pusty. Usta-

wiamy dwa wska´zniki po jednym na pocz¸atku ka˙zdego ci¸agu (wskazane elementy b¸ed¸a
oznaczone daszkiem):



 



















 



'

















!

Porównujemy wskazane elementy. Mniejszy z porównanych elementów przepisujemy na
ci¸ag



i przesuwamy wska´znik w tym ci¸agu, z którego był wzi¸ety element do ci¸agu



.

W wyniku otrzymamy:























 



'



















!

Powtarzamy ten proces tak długo, a˙z w jednym z ci¸agów ostatni element zostanie zabrany
do ci¸agu



.





























'



 

















































'



 

















































'







 





















'

































'







 





















'































'







 





















'







!

background image

8

Rozdział 1. Rekurencja

W takiej sytuacje pozostałe elementy tego drugiego ci¸agu przenosimy do ci¸agu



:

























'



 





















'











!

Liczba porówna ´n potrzebna do scalenia ci¸agów nie jest wi¸eksza od sumy długo´sci tych
ci¸agów.

Algorytm merge-sort (inaczej — sortowanie przez scalanie), który sortuje ci¸ag

,

mo˙zna rekurencyjnie opisa´c tak (rysunek 8.3):

merge-sort(S):



je˙zeli

ma tylko jeden element, to koniec,



je˙zeli

ma wi¸ecej elementów, to:



dzielimy ci¸ag

na połowy



i



,



merge-sort(



),



merge-sort(



),



ł¸aczymy



i



.

Rysunek 1.3: Schemat działania algorytmu merge-sort dla ci¸agu 3, 7, 5, 2, 6, 1, 8, 4

3752|6186

37|52

61|84

3|7

5|2

6|1

8|4

3

7

5

2

6

1

8

4

37

25

16

48

2357

1468

12345678

Algorytm merge-sort jest przykładem algorytmu typu „dziel i zwyci¸e˙zaj”, którego

ogólny schemat wygl¸ada tak:



je˙zeli problem jest małego rozmiaru, to rozwi¸azujemy go bezpo´srednio,

background image

1.7. Rozwi¸azywanie równa ´n i nierówno´sci rekurencyjnych

9



je˙zeli problem jest du˙zy, to:



dzielimy problem na podproblemy,



rozwi¸azujemy podproblemy,



ł¸aczymy rozwi¸azania podproblemów w rozwi¸azanie całego problemu.

1.7

Rozwi¸azywanie równa ´

n i nierówno´

sci rekurencyjnych

Oszacujmy teraz czas działania algorytmu sortowania przez scalanie. Niech







oznacza

liczb¸e operacji porównania potrzebn¸a do posortowania ci¸agu długo´sci



. Mamy nast¸epuj¸ace

oszacowania:













(1.2)















!

(1.3)

Druga zale˙zno´s´c wynika st¸ad, ˙ze aby posortowa´c ci¸ag długo´sci



, sortujemy dwa ci¸agi

długo´sci



, a nast¸epnie potrzebujemy



porówna ´n, aby scali´c te dwie połówki. Dla pro-

stoty rozwa˙za ´n zakładamy tutaj, ˙ze



jest pot¸eg¸a dwójki,







dka jakiego´s naturalnego



.

Istnieje wiele sposobów wyliczania lub szacowania funkcji okre´slonej rekurencyjnie.

Przedstawimy teraz dwa najprostsze z nich: metod¸e podstawiania i metod¸e iteracji.

1.8

Metoda podstawiania

W metodzie podstawiania odgadujemy rozwi¸azanie albo jego oszacowanie, a nst¸epnie
pokazujemy, ˙ze jest ono poprawne. Poka˙zemy działanie tej metody szacuj¸ac zło˙zono´s´c
czasow¸a merge-sortu okre´slon¸a rekurencj¸a (1.2)-(1.3). Zgadujemy, ˙ze









 



dla jakiej´s stałej







i udowodnimy przez indukcj¸e, ˙ze powy˙zsza nierówno´s´c zacho-

dzi dla ka˙zdego pot¸egi dwójki



 



. Zachodzi ona dla







. Zakładamy teraz, ˙ze





 

 

  







i podstawiamy do nierówno´sci (1.3)















  















  



















  



Ostatnia nierówno´s´c jest spełniona, je˙zeli



 



.

Metoda podstawiania została zastosowana w podrozdziale o funkcji Fibonacciego do

pokazania, ˙ze









 









(1.4)

background image

10

Rozdział 1. Rekurencja

ale tam odgadni¸eto dokładne rozwi¸azanie. Teraz poka˙zemy jak doj´s´c do rozwi¸aznia zaczynaj¸ac
od ogólniejszej postaci. Zacznijmy od równania



























!

(1.5)

Sprawd´zmy, jakie funkcje postaci









,

spełniaj¸a to równanie. Po podstawieniu do

równania (1.5) mamy























Po podzieleniu stromnami przez





, otrzymamy











"!

Jest to równanie kwadratowe z dwoma rozwi¸azaniami















oraz











, czyli dwie funkcje











 

oraz













spełniaj¸a równanie (1.5).

Zauwa˙zmy, ˙ze tak˙ze ka˙zda funkcja postaci

































gdzie





i





to stałe, spełnia równanie (1.5). Sprawd´zmy teraz, dla jakich stałych





i





funkcja

spełnia zale˙zno´sci









i











. Otrzymujemu układ równo´sci































Powy˙zszy układ jest spełniony dla









































Tak wi¸ec otrzymujemy wzór na funkcj¸e Fibonacciego









 









(1.6)

1.9

Metoda iteracyjna

Moteda iteracyjna polega na rozwijaniu rekursji. Jako pierwszy przykład rozwa˙zmy za-
le˙zno´s´c.

























'





Dla uproszczenia zakładamy, ˙ze



jest pot¸eg¸a





'



, dla jakiego´s



naturalnego. Funkcj¸e

rozwijamy w nast¸epuj¸acy sposób:



















'



background image

1.10. Metoda rekurencji uniwersalnej

11













'









,

















'









,











'

















'







,











'



!!!











'







,



!!!







'



Iteracj¸e powtarzamy, a˙z ostatni składnik b¸edzie zawierał







, czyli gdy





  

*



.

Otrzymamy wtedy

















'







,



!!!

























'







 





'





















Skorzystali´smy tu z równo´sci





 









  

oraz z faktu, ˙ze

  

*





i





 









.

Jako drugi przykład rozwa˙zmy rekursj¸e























 



Jak b¸edziemy j¸a rozwija´c, to otrzymamy



































'





















'







































!!!















!!!









Dla





 





. Otrzymamy wtedy













 

)

















)







  













  





(1.7)

1.10

Metoda rekurencji uniwersalnej

Przypu´s´cmy, ˙ze mamy równanie rekurencyjne





















(1.8)

background image

12

Rozdział 1. Rekurencja

gdzie

 



i







. Równanie takie otrzymamy szacuj¸ac czas działania algorytmu

rekurencyjnego, który metod¸a "dziel i rz¸ad´z" dzieli problem na

podproblemów rozmiaru





. Funkcja









opisuje czas potrzebny na podzielenie problemu na podproblemy i na

poł¸aczenie rozwi¸aza ´n podproblemów w rozwi¸azanie całego problemu.

Na koniec podamy bez dowodu twierdzenie mówi¸ace jak mo˙zna szacowa ´c funkcj¸e







okre´slon¸a równaniem (1.8).

Twierdzenie 1.1 (o rekurencji uniwersalnej) Niech







b¸edzie okre´slone dla nieujem-

nych liczb całkowitych równaniem rekurencyjnym













" 











gdzie

 



,





i



"

oznacza





"

lub







. Wtedy



Je˙zeli



















 







dla pewnej stałej





, to





















.



Je˙zeli

















 







, to















 





  





.



Je˙zeli

















 







dla pewnej stałej





oraz







 













dla

pewnej stałej





, to





















.

1.11

Zadania

1. Napisz program, który rekurencyjnie oblicza: a) funkcj¸e silnia, b) funkcj¸e Fibonac-

ciego, c) funkcj¸e wykładnicz¸a



.

2. Napisz program, który oblicza symbol Newtona:

a) według wzoru rekurencyjnego

































b) według wzoru

































 

!

Porównaj te programy.

3. Napisz program, który rekurencyjnie oblicza funkcj¸e:













































 



!

4. Oblicz









'



według rekurencyjnego algorytmu Euklidesa.

5. Według algorytmu ł¸aczenia poł¸acz ci¸agi



























i















'













.

background image

1.11. Zadania

13

6. Stosuj¸ac algorytm merge-sort posortuj ci¸ag słów: słowik, wróbel, kos, jaskółka,

kogut, dzi¸ecioł, gil, kukułka, szczygieł, sowa, kruk, czubatka.

[Fragment wiersza Ptasie radio Juliana Tuwima]

7. Dana jest funkcja











:







































"!

Oblicz









. Co oblicza funkcja



?

8. Dana jest funkcja



 







:













































!

Oblicz





'







. Co oblicza funkcja



?

9. Wypisz ci¸ag przeło˙ze ´n potrzebnych do przeniesienia czterech kr¸a˙zków na wie˙zach

Hanoi.

10. Udowodnij, ˙ze algorytm opisany w podrozdziale 8.1 wymaga







przeło˙ze´n do

przeniesienia



kr¸a˙zków.