遞推與遞歸

1、遞推算法

遞推算法是一種用若干步可重複的簡運算(規律)來描述複雜問題的方法。函數

遞推是序列計算機中的一種經常使用算法。它是按照必定的規律來計算序列中的每一個項,一般是經過計算機前面的一些項來得出序列中的指定項的值。其思想是把一個複雜的龐大的計算過程轉化爲簡單過程的屢次重複,該算法利用了計算機速度快和不知疲倦的機器特色。spa

例1:植樹節那天,有五位同窗參加了植樹活動,他們完成植樹的棵樹都不相同。問第一位同窗植了多少棵時,他指着旁邊的第二位同窗說比他多植了兩棵;追問第二位同窗,他又說比第三位同窗多植了兩棵;... 如此,都說比另外一位同窗多植兩棵。最後問到第五位同窗時,他說本身植了10棵。到底第一位同窗植了多少棵樹?設計

分析:設第一位同窗植樹的棵樹爲a1,欲求a1,需從第五位同窗植樹的棵數a5入手,根據「多兩棵」這個規律,按照必定順序逐步進行推算:
(1) a5=10;
(2) a4=a5+2=12;
(3) a3=a4+2=14;
(4) a2=a3+2=16;
(5) a1=a2+2=18;blog

var
  i,a:byte;
begin
  a:=10;
  for i:=1 to 4 do a:=a+2;
  writeln('The Num is',a);
end.遞歸

本程序的遞推運算可用下圖示表示:
初始值a:=10-----i=1,a=a+2(12)-----i=2,a=a+2(14)------i=3,a=a+2(16)-----i=4,a=a+2(18)----輸出a值數學

例2:十本不一樣的書放在書架上,現從新擺放,使每本書都不在原來放的位置,有幾種擺法?it

分析:當n個元素放在n個編號位置,元素編號與位置編號各不對應的方法數用M(n)表示,那麼M(n-1)就表示n-1個編號元素放在n-1個編號位置且各不對應的方法數,其它類推。io

第一步,把第n個元素放在除n之外的某一個位置,好比位置k,一共有n-1種方法
第二步,放編號爲k的元素,這時有兩種狀況:
一、把它放到位置n,那麼對於剩下的n-2個元素,就有M(n-2)種方法
二、不把它放到位置n,這時對於這n-1個元素有M(n-1)種方法function

綜上獲得:
M(n)=(n-1)*[M(n-2)+M(n-1)] (n>=3)

var
  n,i:byte;
  a,b,c:longint;
begin
  readln(n);
  case n of
    1: writeln(0);
    2: writeln(1);
  else begin
    a:=0;b:=1;
    for i:=3 to n do begin
      c:=(i-1)*(a+b);
      a:=b;b:=c;
    end;
    writeln(c);
  end;
  end;
end.

遞推算法以初始(起點)值爲基礎,用相同的運算規律,逐次重複運算,直至運算結束。這種從「起點」重複相同的方法直至到達必定「邊界」,猶如單向運動,用循環能夠實現。遞推的本質是按規律逐次推出(計算)先一步的結果。

 

2、遞歸

若是函數體或過程體中出現調用其自身的語句,稱爲遞歸調用。這樣的函數或過程稱爲遞歸函數或遞歸過程。

 

例3:設計一個計算n!的遞歸程序

根據數學含義,n!可由下面的公式表示:

n!=1            當n=0時

n!=n*(n-1)!  當n>0時

根據以上公式推理,爲了求n!能夠先求出(n-1)!,爲了求(n-1)!又能夠先求出(n-2)!……,如此遞推,直到n=0。因爲n=0時已定義爲1,再由0!=1又一步步反向推回,求出1!、2!……最終獲得n!

 

var

  n:integer;

function fct(t:integer):integer;

begin

  if t=0 then fct:=1

         else fct:=t*fct(t-1);

end;

begin

  readln(n);

  writeln(n,'!=',fct(n));

end.

 

例4:漢諾(hanoi)塔問題。給定三根杆A、B、C和大小不一樣的幾個盤子,這些盤子按尺寸遞減順序套在A杆上,如圖。咱們的任務是把這些盤子從A杆移到C杆且保持原來堆放順序;在實現任務時,規定每次只能移動一個盤子,不容許大的盤子放在小的盤子上面,B杆能夠做爲輔助存放杆,求出每一步應該如何移動。

遞推與遞歸 - 徐老師 - Pascal程序設計

 

題目要求將n個盤子由A杆移到C杆可用一樣的方法:

一、先(遞歸地)將A杆上面的n-1個盤子移到B杆(藉助C杆)

二、而後把A杆上惟一的一個盤子移到C杆

三、再把B杆上的n-1個盤子(遞歸地)移到C杆(藉助A杆)

 

var

  n:integer;

procedure move(n:integer;a,b,c:char);

begin

  if n=1 then writeln(a,'--->',c)

         else begin

    move(n-1,a,c,b);

    writeln(a,'--->',c);

    move(n-1,b,a,c);

  end;

end;

begin

  readln(n);

  move(n,'A','B','C');

end.

 

遞歸結構的程序具備結構清晰,容易閱讀和理解的優勢,寫出的程序較簡短,但在處理遞歸問題中,須要保留每次遞歸調用時的參數和局部變量,這樣就佔用大量的存儲空間和花費較多的機器時間,效率較低。

 

用遞歸過程或函數解決問題時應注意:

一、求解的問題是否符合遞歸的描述,要解決的問題是否能夠化爲與原問題相同的子問題

二、過程體或函數體中必須有遞歸結束的條件,這個條件就是遞歸邊界

 

3、做業

一、zerojudge:a21六、a04二、b12七、a51九、d580、d2十二、d810

二、用遞歸方法求兩個正整數的最大公約數

三、讀入一個任意位數的正整數,按顛倒過來的順序將其輸出(利用遞歸過程)

四、從鍵盤輸入任意長度的一串字符,其中包括數字和字母,並以星號「*」結束。利用遞歸的方法將這串字符中的數字字符按相反的次序個輸出。例如:輸入Delphi6TP70Ada586*,輸出爲685076。

相關文章
相關標籤/搜索