資料結構學習(C++)——遞迴【3】(2) (轉)
遞迴法和回溯法
有人說,回溯實際上是遞迴的展開,但實際上。兩者的指導思想並不一致。
打個比方吧,遞迴法好比是一個軍隊要透過一個迷宮,到了第一個分岔口,有3條路,將軍命令3個小隊分別去探哪條路能到出口,3個小隊沿著3條路分別前進,各自到達了路上的下一個分岔口,於是小隊長再分派人手各自去探路——只要人手足夠(對照而言,就是的堆疊足夠),最後必將有人找到出口,從這人開始只要層層上報直屬領導,最後,將軍將得到一條通路。所不同的是,計算機的遞迴法是把這個並行過程化了。
而回溯法則是一個人走迷宮的思維模擬——他只能寄希望於自己的記憶力,如果他沒有辦法在分岔口留下標記(電視裡一演到什麼迷宮尋寶,總有惡人去改好人的標記)。
想到這裡突然有點明白為什麼都喜歡遞迴了,他能夠滿足人心最底層的虛榮——難道你不覺得使用遞迴就象那個分派士兵的將軍嗎?想想漢諾塔的解法,也有這個傾向,“你們把上面的N-1個拿走,我就能把下面的挪過去,然後你們在把那N-1個搬過來”。笑談,切勿當真。
這兩種方法的例程,我不給出了,網上很多。我只想對書上的遞迴解法發表點看法,因為書上的解法有偷樑換柱的嫌疑——迷宮的儲存不是用的二維陣列,居然直接用岔路口之間的連線表示的——簡直是人為的降低了問題的難度。實際上,如果把迷宮抽象成(岔路口)點的連線,迷宮就變成了一個“圖”,求解入口到出口的路線,完全可以用圖的遍歷演算法來解決,只要從入口DFS到出口就可以了;然而,從二維陣列表示的迷宮轉化為圖是個很複雜的過程。並且這種轉化,實際上就是沒走迷宮之前就知道了迷宮的結構,顯然是不合理的。對此,我只能說這是為了遞迴而遞迴,然後還自己給自己開綠燈。
但迷宮並不是只能用上面的方法來走,前提是,迷宮只要走出去就可以了,不需要找出一條可能上的最短路線——確實,迷宮只是前進中的障礙,一旦走通了,沒人走第二遍。下面的方法是一位遊戲玩家提出來的,既不需要遞迴,也不需要棧來回溯——玩遊戲還是有收穫的。
另一種解法
請注意我在迷宮中用粗線描出的路線,實際上,在迷宮中,只要從入口始終沿著一邊的牆走,就一定能走到出口,那位玩家稱之為“靠一邊走”——如果你不把迷宮的通路看成一條線,而是一個有面積的圖形,很快你就知道為什麼。實現起來也很簡單。
下面的在TC2中編譯,不能在VC6中編譯——為了動態的表現人的移動情況,使用了gotoxy(),VC6是沒有這個的,而且堆砌迷宮的219號字元是不能在使用中文頁碼的操作的32位的console程式顯示出來的。如果要在VC6中實現gotoxy()的功能還得用,為了一個簡單的程式沒有必要,所以,就用TC2寫了,突然換到C語言還有點不適應。
#include
typedef struct hero {int x,y,face;} HERO;
void set_hero(HERO* h,int x,int y,int face){h->x=x;h->y=y;h->face=face;}
void go(HERO* h){if(h->face%2) h->x+=2-h->face;else h->y+=h->face-1;}
void goleft(HERO* h){if(h->face%2) h->y+=h->face-2;else h->x+=h->face-1;}
void turnleft(HERO* h){h->face=(h->face+3)%4;}
void turnright(HERO* h){h->face=(h->face+1)%4;}
void print_hero(HERO* h, int b)
{
gotoxy(h->x + 1, h->y + 1);
if (b)
{
switch (h->face)
{
case 0: printf("%c", 24); break;
case 1: printf("%c", 16); break;
case 2: printf("%c", 25); break;
case 3: printf("%c", 27); break;
default: break;
}
}
else printf(" ");
}
int maze[10][10] =
{
0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
1, 0, 1, 1, 0, 1, 1, 1, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 1, 0, 1, 1, 1,
0, 0, 1, 0, 1, 1, 0, 0, 0, 1,
1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 1, 0, 1,
0, 1, 1, 0, 0, 0, 0, 1, 0, 1,
0, 0, 0, 0, 1, 0, 1, 1, 0, 1,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0
};
void print_maze()
{
int i, j;
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
if (maze[i][j]) printf("%c", 219);
else printf(" ");
}
printf(" ");
}
}
int gomaze(HERO* h)
{
HERO t = *h; int i;
for (i = 0; i < 2; t = *h)
{
print_hero(h, 1); sleep(1); go(&t);
if (t.x >= 0 && t.x < 10 && t.y >= 0 && t.y < 10 && !maze[t.y][t.x])
{
print_hero(h, 0); go(h);/*前方可走則向前走*/
if (h->x == 9 && h->y == 9) return 1; goleft(&t);
if (h->x == 0 && h->y == 0) i++;
if (t.x >= 0 && t.x < 10 && t.y >= 0 && t.y < 10 && !maze[t.y][t.x]) turnleft(h);/*左方無牆向左轉*/
}
else turnright(h);/*前方不可走向右轉*/
}
return 0;
}
:namespace prefix = o ns = "urn:schemas--com::office" />
main()
{
HERO Tom;/*有個英雄叫Tom*/
set_hero(&Tom, 0, 0, 0);/*放在(0,0)面朝北*/
clrscr();
print_maze();
gomaze(&Tom);/*Tom走迷宮*/
}
總結
書上講的基本上就這些了,要是細說起來,幾天幾夜也說不完。前面我並沒有講如何寫遞迴演算法,實際上給出的都是非遞迴的方法,我也覺得有點文不對題。我的目的是使大家明白,能寫出什麼演算法,主要看你解決問題的指導思想,換而言之,就是對問題的認識程度。所以初學者現在就去追求“漂亮”的遞迴演算法,是不現實的,結果往往就是削足適履,搞的一團糟——有位仁兄寫了個騎馬遊世界的“遞迴”程式,在我機器上10分鐘沒反映。其實優秀的遞迴演算法是在對問題有了清楚的認識後才會得出的。
最後說說用語言寫遞迴函式。我的彙編水平並不高,不過我想說的是用匯編寫遞迴函式,絕對不像《彙編與c解決遞迴問題之比較》/develop/article/17/17597.shtm">http://www.csdn.net/develop/article/17/17597.shtm那篇文章說的,實際上比高階語言並不複雜,甚至在masm32v7中,和高階語言一樣,因為那裡面有一句很象代參函式的INVOKE expression [,arguments]。那位作者顯然連教科書都沒看全,因為在我們的講8086組合語言的書上就有一個階乘的遞迴函式例程,如果他看過,就不會有那個結論了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-960589/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料結構學習(C++)——遞迴【2】(3) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(2) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【3】(1) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(1) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(4) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【1】 (轉)資料結構C++遞迴
- 資料結構學習(C++)——迴圈連結串列 (轉)資料結構C++
- 資料結構與演算法學習總結--遞迴資料結構演算法遞迴
- 資料結構-遞迴資料結構遞迴
- 資料結構學習筆記-遞迴求解森林高度資料結構筆記遞迴
- 資料結構學習(C++)續——排序【3】交換排序 (轉)資料結構C++排序
- 資料結構學習(C++)——二叉樹【3】 (轉)資料結構C++二叉樹
- 資料結構學習(C++)——序言 (轉)資料結構C++
- 資料結構學習(C++)——二叉樹【2】 (轉)資料結構C++二叉樹
- 資料結構學習(C++)——圖【2】(DFS和BFS) (轉)資料結構C++
- 資料結構學習(C++)——圖(總結) (轉)資料結構C++
- 資料結構學習(C++)——樹(總結) (轉)資料結構C++
- 資料結構學習(C++)——圖【3】(無向圖)(上) (轉)資料結構C++
- 資料結構學習(C++)——圖【3】(無向圖)(下) (轉)資料結構C++
- 資料結構學習(C++)續——排序【2】插入排序 (轉)資料結構C++排序
- 資料結構學習(C++)——線性鏈式結構總結(代後記)【2】 (轉)資料結構C++
- 資料結構5_遞迴資料結構遞迴
- 資料結構學習(C++)——雙向連結串列 (轉)資料結構C++
- 資料結構學習(C++)——稀疏矩陣(十字連結串列【2】) (轉)資料結構C++矩陣
- 資料結構學習(c++)——二叉樹 (轉)資料結構C++二叉樹
- PLSQL學習-【3迴圈結構】SQL
- 基礎資料結構之遞迴資料結構遞迴
- 前端學習 資料結構與演算法 快速入門 系列 —— 遞迴前端資料結構演算法遞迴
- 【資料結構】二叉樹遍歷(遞迴+非遞迴)資料結構二叉樹遞迴
- 資料結構學習(C++)——圖【4】(最短路徑) (轉)資料結構C++
- 資料結構學習(C++)——二叉樹【1】 (轉)資料結構C++二叉樹
- 資料結構和演算法:遞迴資料結構演算法遞迴
- 資料結構:歸併排序(非遞迴)資料結構排序遞迴
- 資料結構與演算法:遞迴資料結構演算法遞迴
- 關於樹型結構資料遞迴查詢,轉非遞迴查詢的實現遞迴
- 透過例子學習Lua(3)----Lua資料結構(轉)資料結構
- 【資料結構】遞迴實現連結串列逆序資料結構遞迴
- 資料結構與演算法讀書筆記 - 004 -C++遞迴資料結構演算法筆記C++遞迴