【C語言】迷宮
阿新 • • 發佈:2018-11-05
一,涉及知識點
結構體,棧,遞迴
二,實現邏輯
1.定義一個結構體儲存當前位置座標
2.用陣列初始化一個迷宮,1表示可以走,0表示牆,迷宮最後一列都是出口
3.列印迷宮
4.走迷宮方法一:使用棧,通過壓棧出棧回溯;方法二:在棧的基礎上,用遞迴做回溯
5.記錄最短路徑,把路徑壓入棧中,列印最短路徑
三,原始碼
#pragma once #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdio.h> #define ROWS (6) //行數 #define COLS (6) //列數 #define MAX_SIZE (100) //結構體存放座標 typedef struct Position { int x; int y; }Position; typedef Position StackDataType; //棧 typedef struct Stack { StackDataType array[MAX_SIZE]; int top; //表示當前個數 }Stack; void StackInit(Stack *pStack) { pStack->top = 0; } void StackDestroy(Stack *pStack) { pStack->top = 0; } void StackPush(Stack *pStack, StackDataType data) { assert(pStack->top < MAX_SIZE); //pStack->top 永遠指向的棧頂後的一個空間 pStack->array[pStack->top++] = data; } void StackPop(Stack *pStack) { assert(pStack->top>0); pStack->top--; } Position StackTop(Stack *pStack) { assert(pStack->top > 0); return pStack->array[pStack->top-1]; } int StackSize(const Stack *pStack) { return pStack->top; } int StackFull(const Stack *pStack) { return pStack->top >= MAX_SIZE; } int StackEmpty(const Stack *pStack) { return pStack->top <= 0; } void StackCopy(Stack *pDest,Stack *pSrc) { memcpy(pDest->array, pSrc->array, sizeof(StackDataType)*pSrc->top); pDest->top = pSrc->top; } Stack path; //當前路徑 Stack min; //之前的最小路徑 //簡單迷宮 int gMaze[ROWS][COLS] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0 }, { 0, 0, 1, 1, 1, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 0, 0, 0 } }; //入口 Position gEntry = { 5, 2 }; //判斷是否走到出口,最後一列都是出口 int IsExit(Position pos) { if (pos.y == COLS - 1){ return 1; } else { return 0; } } //判斷是否可以走,沒有越界&&值是1 int CanPass(Position pos) { if (pos.x >= ROWS){ return 0; } if (pos.y >= COLS){ return 0; } return gMaze[pos.x][pos.y] == 1; } //列印路徑 void PrintPath(Stack *pStack) { Position at; for (int i = 0; i < pStack->top; i++){ at = pStack->array[i]; printf("x=%d y=%d\n", at.x, at.y); } } //列印迷宮 void PrintMaze() { for (int i = 0; i < ROWS;i++){ for (int j = 0; j < COLS;j++){ if (gMaze[i][j] == 0) { printf("■", gMaze[i][j]); } else if (gMaze[i][j] == 1) { printf(" ", gMaze[i][j]); } else if (gMaze[i][j] == 2){ printf("☆", gMaze[i][j]); } } printf("\n"); } printf("\n\n"); } //方法二 //呼叫棧做回溯,遞迴 void RunMazeRec(Position at) { Position next; StackPush(&path,at); //一進來標記我走過了 gMaze[at.x][at.y] = 2; PrintMaze(); if (IsExit(at)){ //如果當前路徑(path)小於之前的最小路徑(min),最小路徑是path if (StackEmpty(&min) || StackSize(&path) < StackSize(&min)){ StackCopy(&min, &path); //打印出最短路徑 PrintPath(&path); } } //根據左->上->右->下來嘗試 //左 next.x = at.x; next.y = at.y - 1; if (CanPass(next)){ RunMazeRec(next);//遞迴 //PrintMaze(); } //上 next.x = at.x - 1; next.y = at.y; if (CanPass(next)){ RunMazeRec(next); //PrintMaze(); } //右 next.x = at.x; next.y = at.y + 1; if (CanPass(next)){ RunMazeRec(next); //PrintMaze(); } //下 next.x = at.x + 1; next.y = at.y; if (CanPass(next)){ RunMazeRec(next); //PrintMaze(); } //如果at的四周都沒法兒走,at重新置為1 gMaze[at.x][at.y] = 1; StackPop(&path); return; //回溯 } //方法一 //需要一個棧回溯,壓棧出棧 void RunMaze() { Stack stack; StackInit(&stack); Position next; Position at; at.x = gEntry.x; at.y = gEntry.y; while (1){ //一進來標記我走過了 gMaze[at.x][at.y] = 2; PrintMaze(); //把當前位置壓入棧中,方便做回溯 StackPush(&stack, at); if (IsExit(at)){ //如果到了出口,退出 PrintPath(&stack); return; } //根據左->上->右->下來嘗試 //左 next.x = at.x; next.y = at.y - 1; if (CanPass(next)){ at.x = next.x; at.y = next.y; continue; } //上 next.x = at.x - 1; next.y = at.y; if (CanPass(next)){ at.x = next.x; at.y = next.y; continue; } //右 next.x = at.x; next.y = at.y + 1; if (CanPass(next)){ at.x = next.x; at.y = next.y; continue; } //下 next.x = at.x + 1; next.y = at.y; if (CanPass(next)){ at.x = next.x; at.y = next.y; continue; } //如果四周都沒法兒走,出棧 StackPop(&stack); if (StackEmpty(&stack)){ printf("沒有出口\n"); return; } at = StackTop(&stack); //回溯 StackPop(&stack); } } void testRunMazeRec() { StackInit(&path); StackInit(&min); PrintMaze(); RunMazeRec(gEntry); } int main() { PrintMaze(); //RunMaze(); testRunMazeRec(); system("pause"); return 0; }