迷宫问题--链栈

问题描述

给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题。

问题分析

我们可以使用二维数组来模拟迷宫,用‘0’来表示通路,用‘1’来表示障碍。于是我们可以这样定义这样一个迷宫(左上角为入口,右下角为出口):

// 迷宫的定义,0表示通路,1表示障碍
int maze[ROW][COL] = {
    {0, 1, 0, 0, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 0, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 1, 0}
};

我们可以想想如何才能找到这条出口:

当我们站在(0,0)点的时候,我们只有一个选择那就是往下走,因为右边是障碍物,当我们走到(1,0)点的时候,显然我们也只能继续往下走,因为右边是障碍物,上面是刚刚走过的路。但当我们走到(2,0)点的时候,此时我们可以选择两条路,要么继续下,要么往右走。聪明的你肯定能看出来往右走才是正确的,但计算机并没有你聪明,它并不知道要往哪块走,如果它继续往下走的话,当它走到(4,2)点的时候就会发现无路可走了,那怎么办呢?聪明的你又会知道应该让计算机回到(2,0)点继续往右走

那计算机怎么实现回到(2,0)点呢?那肯定是让计算机按他原来走过的路一步一步回退。那它怎么会知道它走过哪些路呢?那就在地图上把它走过的路记为2。这样在它回到(2,0)点的时候就可以继续判断:上面走过,下面走过,只能走左边了。

那当它走到终点时,只是知道了他这条迷宫有出路,那出路到底是什么呢?我们就可以把它每走过的路存起来。

那说了这么多,我们到底要如何实现呢?本章我介绍一种链栈的思路。每次判断该路可不可行,如果可行,就将该节点存入栈中,如果遇到死路,就往回走,也就是出栈。这样在走到终点的时候,栈中存放的节点就正好是迷宫的一条出路。

代码实现

我们可以这样定义栈的结点x,y为结点坐标:

typedef struct node {
    int x;
    int y;
    struct node* next;
} LNode, *Node;

使用两个数组来实现上下左右的移动:

int dirRow[] = {0, 1, 0, -1};
int dirCol[] = {1, 0, -1, 0};

//newx和newy为移动后的结点坐标
for (int i = 0; i < 4; i++) {
    int newx = (*p)->x + dirRow[i];
    int newy = (*p)->y + dirCol[i];
}

我们来看关键部分代码:

//判断是否为可走的路
int IsPass(int x, int y) {
    return x >= 0 && x < MAXSIZE && y >= 0 && y < MAXSIZE && Map[x][y] == 0;
}

//寻找通路
int FindPath(Node* p) {
	int t=0;
    while (1){
    	if((*p)->x==MAXSIZE-1&&(*p)->y == MAXSIZE-1){
    		return 1;
		}
		t=0;
        for (int i = 0; i < 4; i++) {
            int newx = (*p)->x + dirRow[i];
            int newy = (*p)->y + dirCol[i];

            if (IsPass(newx, newy)) {
                Push(p,newx,newy);//入栈
                Map[newx][newy] = 2;
                t=1;
                break;
            }
        }
        if(t==0){
        	Pop(p);//出栈
		}
    }
    return 0;
}

其中  int IsPass(int x, int y)  函数用来判断进行移动后的那一个点是否可行:是否超出数组范围,是否有障碍。

在  while  循环中,先判断此结点是否为出口,如果是直接退出函数。随后的  for  循环就是将四个方向尝试走一遍,如果哪条路可走,就将该路入栈,标记已走,然后直接退出for循环。

通过变量  t  判断在for循环中是否入过栈,即是否有路。如果t值为0,那就代表for循环中四个方向都不能走,即死路,那么就往前退一格,即出栈

完整代码

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define ROW 5
#define COL 5

// 迷宫的定义,0表示通路,1表示障碍
int maze[ROW][COL] = {
    {0, 1, 0, 0, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 0, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 1, 0}
};

// 存储路径的坐标
typedef struct {
    int row;
    int col;
} Coordinate;

// 定义方向:东、南、西、北
int dirRow[] = {0, 1, 0, -1};
int dirCol[] = {1, 0, -1, 0};

// 函数声明
bool findPath();

int main() {
    if (findPath()) {
        // 打印路径
        printf("找到通路,路径如下:\n");
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                if (maze[i][j] == 2) {
                    printf("-> ");
                } else {
                    printf("%d ", maze[i][j]);
                }
            }
            printf("\n");
        }
    } else {
        printf("没有找到通路。\n");
    }

    return 0;
}

// 栈的结点定义
typedef struct StackNode {
    Coordinate data;
    struct StackNode* next;
} StackNode;

// 栈的定义
typedef struct {
    StackNode* top;
} Stack;

// 初始化栈
void initStack(Stack* stack) {
    stack->top = NULL;
}

// 判断栈是否为空
bool isEmpty(Stack* stack) {
    return stack->top == NULL;
}

// 入栈
void push(Stack* stack, Coordinate data) {
    StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
    newNode->data = data;
    newNode->next = stack->top;
    stack->top = newNode;
}

// 出栈
bool pop(Stack* stack) {
    if (isEmpty(stack)) {
        return false;
    }
    StackNode* temp = stack->top;
    stack->top = stack->top->next;
    free(temp);
    return true;
}

// 获取栈顶元素
Coordinate top(Stack* stack) {
    Coordinate data = {0, 0};
    if (!isEmpty(stack)) {
        data = stack->top->data;
    }
    return data;
}

// 判断当前位置是否有效
bool isValidMove(int row, int col) {
    return (row >= 0 && row < ROW && col >= 0 && col < COL && maze[row][col] == 0);
}

// 在迷宫中查找通路
bool findPath() {
    Stack stack;
    initStack(&stack);

    Coordinate start = {0, 0};
    push(&stack, start);
    maze[start.row][start.col] = 2; // 标记入口

    while (!isEmpty(&stack)) {
        Coordinate current = top(&stack);

        if (current.row == ROW - 1 && current.col == COL - 1) {
            // 已经到达出口
            return true;
        }

        bool found = false;
        for (int i = 0; i < 4; i++) {
            int newRow = current.row + dirRow[i];
            int newCol = current.col + dirCol[i];

            if (isValidMove(newRow, newCol)) {
                Coordinate next = {newRow, newCol};
                push(&stack, next);
                maze[newRow][newCol] = 2; // 标记已访问
                found = true;
                break;
            }
        }

        if (!found) {
            // 无法继续前进,回溯
            pop(&stack);
        }
    }

    return false; // 没有找到通路
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值