我們小時候都玩過迷宮,走迷宮可以說是非常有意思了。而在我們大腦裡是如何對這個遊戲進行思考的呢?其實我們在玩這個遊戲的是,大多是一條路走到黑,如果到達出口那麼就走出來了,如果是死胡同,那麼回到剛才的分叉口,再找一條路再一條路走到黑,以此類推。而我們在實現迷宮求解的時候也是利用這種方法,這種方法又稱作回溯法。
我們要實現迷宮求解問題,首先應當是建立乙個迷宮。這裡我們用乙個二維陣列當做乙個平面,然後用01序列當做牆與路,最終通過走1的路,看是否能夠到達出口。
如上圖,此時1就是可以走的路,而0就是牆,無法行走。
我們可以建立乙個結構體,在結構體內放置地圖map。
#define row 6
#define col 6
typedef struct maze maze;
在定義完地圖以後,我們考慮的是,如何在地圖中走?以及定義規則。
首先我們應該確定入口點的位置。設為entry,而在我們的二維陣列中,區別元素的唯一法則就是下標與內容,這裡不考慮內容,下標應該是最理想的,所以我們應該再定義乙個結構體來存放下標。
typedef
struct pointpoint;
這樣我們在定義入口點,以及接下來每乙個走的點都可以用這個point來處理操作。
接下來就是如何走的問題了。
我們這裡採用的是從出口點開始,以順時針為方向,依次判斷入口點上、右、下、左是否能夠落腳,而落腳的判斷就是這四個點內的元素值是否為1,如果為1,那麼證明可以落腳,然後對落腳點進行標記併入棧,落腳以後利用遞迴對落腳點四周繼續判斷,以此類推,直至走到出口,或者是無路可走,出棧並返回。然後再判斷入口點右、下、左。
所以此時一旦落腳了(1,1)這個點,那麼就應該對其進行標記及入棧,接下來應該判斷這個點是否為出口,顯然不是,那麼接著以這個點為主,判斷它的四周,以此類推。接下來我們實現。
void mazeinit(maze* maze)//初始化地圖
intmap[row][col] = ,,,
,,};size_t i = 0;
size_t j = 0;
for(; i < row; ++i)
} return;
} printf("\n");
size_t i = 0;
size_t j = 0;
for(; i < row; ++i)
printf("\n");
}}int canstay(maze* maze, point cur)//是否能夠落腳
if(cur.col < 0 || cur.col >= col || \
cur.row < 0 || cur.row >= row)
if(maze->map[cur.row][cur.col] == 1)
return0;}
void markstay(maze* maze, point cur)//標記落腳點
maze->map[cur.row][cur.col] = 2;
}int i***it(maze* maze, point cur, point entry)//判斷是否是出口點
if((cur.row == 0 || cur.row == row - 1 || \
cur.col == 0 || cur.col == col - 1) && \
(cur.col != entry.col || cur.row != entry.row))
return0;}
int _getpathmaze(maze* maze, point cur, point entry)
//判斷是否能落腳
if(!canstay(maze, cur))
//標記落腳點
markstay(maze, cur);
//判斷是否是出口點
if(i***it(maze, cur, entry))
//如果不是出口點那麼就判斷它的四周
//預定順序為上、右、下、左
point up = cur;
up.row -= 1;
_getpathmaze(maze, up, entry);
point right = cur;
right.col += 1;
_getpathmaze(maze, right, entry);
point down = cur;
down.row += 1;
_getpathmaze(maze, down, entry);
point left = cur;
left.col -= 1;
_getpathmaze(maze, left, entry);
return1;}
void getpathmaze(maze* maze,point entry)//查詢路徑
entry.row = 0;
entry.col = 1;
_getpathmaze(maze, entry, entry);
}
我們發現,上面的**並沒有入棧用任何的入棧出棧操作,但是我們的思路裡面卻說入棧出棧,這是為什麼呢?其實這裡我們是利用了系統給予我們的棧,函式呼叫時每次呼叫函式都會形成自己的棧,函式返回後,棧銷毀,資料釋放。所以我們不必維護棧,就可以實現這個目的。
接下來,我們利用自己的棧來實現一下這一系列操作。
int _getpathmazebymystack(maze* maze, point entry)
seqstack stack;
seqstackinit(&stack);
//首先判斷是否能夠落腳
if(!(canstay(maze, entry)))
//如果能夠落腳,那麼這個時候就標記落腳點,並且入棧
markstay(maze, entry);
seqstackpush(&stack, entry);
//判斷是否是出口,如果是出口就進行列印並標記
//如果不是出口點,此時應該判斷其四周的點,是否能夠落腳
//如果可以落腳就標記併入棧依次迴圈
point cur;
while(seqstackgetfront(&stack, &cur))
point up = cur;
up.row -= 1;
if(canstay(maze, up))
point right = cur;
right.col += 1;
if(canstay(maze, right))
point down = cur;
down.row += 1;
if(canstay(maze, down))
point left = cur;
left.col -= 1;
if(canstay(maze, left))
seqstackpop(&stack);
} return1;}
void getpathmazebymystack(maze* maze, point entry)
entry.row = 0;
entry.col = 1;
_getpathmazebymystack(maze, entry);
return;
}
這裡我們利用自己的棧,之前寫過的棧操作這裡直接使用,不再多說。
我們每次判斷能夠落腳以後首先先進行入棧操作,而接著判斷是否是出口點,如果不是那麼進入迴圈,取棧頂元素判斷它的四周是否可以落腳以及是否是出口點,可以落腳就再次入棧並直接continue進行下次迴圈,再去棧頂元素,比較,以此類推。直至迴圈結束。
資料結構 迷宮求解
定義迷宮 include seqstack.h define max row 6 最大行數 define max col 6 最大列數 typedef struct mazemaze void mazeinit maze maze size t i 0 for imap i j map i j vo...
資料結構 迷宮求解
include include int mg 10 10 地圖 int m 8 行數 int n 8 列數 typedef struct box 定義方塊型別 typedef struct sttype 定義順序棧型別 bool mgpath int xi,int yi,int xe,int ye ...
迷宮求解(資料結構)
include stdio.h include malloc.h define max 10 define l 10 define c 10 int sum l c typedef struct postype typedef struct selemtype typedef struct stac...