17、栈案例5:迷宫问题(非递归实现)

题源及算法思路来源于“网易云课堂:数据结构实战完全手册(夏曹俊·丁宋涛)”

迷宫问题(非递归实现)的需求

  迷宫问题,在一个由“0(表示通路)”“1(表示障碍)”的迷宫数组中,利用回溯法,从起点出发到达最终的出口。

迷宫问题(非递归实现)的链栈实现

利用链栈的特性和回溯算法的思想,通过不断的尝试搜索寻找迷宫的出口

/* 只要严格按照East->South->West->North的优先级顺序遍历寻找
   路径,就一定能够穷举到所有的路线,且要标记已经走过的坐标点,
   否则就会出现走回头路
   通常将已经走过的坐标点标记为“2”
   East(i,j+1)、South(i+1,j)、West(i,j-1)、 North(i-1,j)
*/

#define TRUE 1
#define FALSE 0

typedef int BOOL;

typedef struct
{
    int x;// 路径坐标点的横坐标值
    int y;// 路径坐标点的纵坐标值
    int direction;// 路径坐标点的方向
}ElemType;

typedef struct Node
{
    ElemType data;// 链栈的数据域
    struct Node* pNext;// 链栈的指针域
}LinkStack;

int main()
{
    // 迷宫,终点处在maze[6][10]
	int maze[][11] = 
    {
		{1,1,1,1,1,1,1,1,1,1,1 },
		{1,0,1,0,0,1,1,1,0,0,1 },
		{1,0,0,0,0,0,1,0,0,1,1 },
		{1,0,1,1,1,0,0,0,1,1,1 },
		{1,0,0,0,1,0,1,1,0,1,1 },
		{1,1,0,0,1,0,1,0,0,0,1 },
		{1,1,1,0,0,0,0,0,1,0,0 },
		{1,1,1,1,1,1,1,1,1,1,1 },
	};

    // 分别代表East、South、West、North四个方向
    int direction [4][2] = 
    {
        {0, 1}, 
        {1, 0}, 
        {0, -1}, 
        {-1, 0}
    };

    ElemType element;// 操作获取迷宫各位置信息的数据

    LinkStack* pStack = NULL;// 保存移动路径的栈
    pStack = InitialStack();

    // 设置起始位置
    element.x = 1;
    element.y = 1;
    element.direction = -1;// 保证下一个结点推进时,起点方向是0

    pStack = PushStack(pStack, element);// 迷宫入口入栈

    // 控制循环遍历的当前结点横、纵坐标和方向
    int currX, currY, currDire;
    // 控制循环遍历的潜在结点横、纵坐标
    int potenX, potenY;

    while(IsLinkStackEmpty(pStack) != TRUE)
    {
        // 获得当前的结点坐标
        currX = pStack->data.x;
        currY = pStack->data.y;
        currDire = pStack->data.direction + 1;

        while(currDire <= 3)
        {
            potenX = currX + direction[currDire][0];
            potenY = currY + direction[currDire][1];

            // 若已到达终点
            if(potenX == 6 && potenY == 10 && maze[potenX][potenY] == 0)
            {
                printf("Find the exit point!\n");
                printf("The current coordinate is: (%d, %d)\n", currX, currY);
                // 输出所有路过的坐标结点
                while(IsLinkStackEmpty(pStack->pNext) != TRUE)
                {
                    pStack = PopStack(pStack, &element);
                    printf("The previous coordinate is: (%d, %d)\n", pStack->data.x, pStack->data.y);
                }

                system("pause");

                return 0;
            }

            // 判断是否可以前进到下一个坐标结点
            if(maze[potenX][potenY] == 0)
            {
                maze[potenX][potenY] = 2;// 标记已经走过的坐标结点,避免走回头路

                // 将结点路径保留,所以进行入栈
                element.x = potenX;
                element.y = potenY;
                element.direction = -1;
                pStack = PushStack(pStack, element);

                break;
            }

            currDire = currDire + 1;// 确定下次选择的移动方向
        }

        /* 回溯:currDire > 3,说明所有的当前结点的四个方向都是死路,
           所以要退栈,返回上一个结点
        */
        if(currDire > 3)
        {
            pStack = PopStack(pStack, &element);// 使用element保存通往死路的结点
        }
    }

    printf("There is no path in zhe maze.\n");

    system("pause");

    return 0;
}

你可能感兴趣的:(数据结构,学习笔记)