【C语言数据结构】——栈的学习,与用栈实现迷宫问题(附源码,注释,流程图解析)

导入:所谓迷宫问题,就是把迷宫看做一个二维数组(二维坐标系),在数组中寻找从一个点到另一个点的通路。利用“栈”的特点——只允许在顶端进行插入和删除——可以十分轻松的解决这一个问题。(结尾附完整代码)

一.创建“栈”,并实现有关“栈”的基本操作函数。

1.“栈”的数据结构定义:

typedef int DataType;    //定义int为当前栈内存储的数据类型(后续会更改)

typedef struct
{
    int MAXNUM;    //记录当前栈的最大数据
    int top;        //记录栈顶的位置
    DataType *element;    //数据数组,可自定义数组长度
} seqStack;

typedef seqStack* PseqStack;    //定义栈的指针形式

        上面的代码中把int定义为DataType为了方便后续更改代码

2.“栈”的创建函数:

PseqStack CreateStack(int maxnum)
{
    if (maxnum > 0)
    {
        PseqStack stack = (PseqStack)malloc(sizeof(PseqStack));    //为栈申请空间
        stack->MAXNUM = maxnum;
        stack->top = -1;        //其实把栈顶标记为-1,表示栈为空
        stack->element = (DataType *)malloc(sizeof(DataType) * maxnum);    //为栈储存的数据申请空间
        return stack;
    }
    else
    {
        printf( "maxnum不得小于0" ) ;
        return NULL;
    }
}

        创建栈的时候,只需像下面这样调用函数即可:

int main()
{
    PseqStack stack = PseqStack Stack = CreateStack(10);//参数为你想申请的最大数组容量
}

3.判断“栈”是否为空,是否为满,是否存在:

        判断是否为空

/*
 *   若栈不存在,则返回-1;若栈为空,则返回1;若栈不为空,则返回0。
 */
int IsEmptyStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        return -1;
    }
    else
    {
        if (stack->top == -1)       //若栈顶为-1则表明栈中已经空了
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

        判断是否已满

/*
 *   若栈不存在,则返回-1;若栈不满,则返回0;若栈满,则返回1。
 */
int IsFullStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        return -1;
    }
    else
    {
        if (stack->top == stack->MAXNUM - 1)    //栈顶的位置从0开始计数,计到MAXNUM-1时表示已满
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

4.实现“入栈”与“出栈”功能的函数:

        入栈:

/*
 *   将数据data插入栈中,若栈为空则返回-1;若栈已满则返回0;若插入成功则返回1。
 */
int PushStack(PseqStack Stack, DataType data)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        printf( "栈不存在\n" ) ;
        return -1;
    }

    {
        if (IsFullStack(stack) == 1)
        {
            printf( "栈已满,无法入栈\n" ) ;
            return 0;
        }
        else
        {
            stack->top++;
            stack->element[stack->top] = data;
            return 1;
        }
    }
}

        由于top是标记栈顶位置,所以每次入栈的操作都是先更新栈顶位置,再输入栈顶数据。

        出栈:

/*
 *弹出栈顶元素,若栈不存在则返回-1;若栈为空则返回0;若弹出成功则返回栈顶元素。
 */
DataType PopStack(PseqStack Stack)
{
    PseqStack stack = Stack;

    if (stack == NULL)
    {
        printf("栈不存在\n");
        return -1;
    }
    else
    {
        if (IsEmptyStack(stack) == 1)
        {
            printf("栈为空,无法出栈\n");
            return 0;
        }
        else
        {
            DataType data = stack->element[stack->top];
            stack->element[stack->top] = 0;
            stack->top--;
            return data;
        }
    }
}

5.返回“栈”顶数据:

/*
 *返回栈顶元素,若栈不存在则返回-1;若栈为空则返回0。
 */
DataType TopStack(PseqStack Stack)
{
    PseqStack stack = Stack;

    if (stack == NULL)
    {
        printf("栈不存在\n");
        return -1;
    }
    else
    {
        if (IsEmptyStack(stack) == 1)
        {
            printf("栈为空\n");
            return 0;
        }
        else
        {
            return stack->element[stack->top];
        }
    }
}

6.打印“栈”内数据:

        将“栈”内数据全部打印出来,方便观察结果。

/*
*打印栈内现有元素,若栈不存在则返回-1;若栈为空则返回0。
*/
int PrintStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        printf("栈不存在\n");
        return -1;
    }
    else
    {
        if (IsEmptyStack(stack) == 1)
        {
            printf("栈为空\n");
            return 0;
        }
        else
        {
            for (int i = 0; i <= stack->top; i++)
            {
                DataType data = stack->element[i];
                printf("element[%d]:%d\n", i, data);
            }
        }
    }
}

        至此,有关“栈”的基本操作就已经全部完成,让我们正式进入解决“迷宫问题”的环节。

二.迷宫问题的算法思路讲解与代码实现:

1.初步认识迷宫问题:

        1.认识地图:

        首先,我们来看一下现有的迷宫地图


 const int maze[12][12] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
        1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

        迷宫的起始点为(1,1),终点为(10,10)。被标记为“1”的点表示是不可通行的“墙”,而标记为“0”的点则表示是可以通行的“路”。这种网格地图的标记权值在RPG游戏中经常会用到,比如我们熟知的《口袋妖怪》便是这样:

(口袋妖怪的地图中,用“1”标记不可通行的道路,用“c”标记可通行道路,用“4”标记水路等等)

        2.流程图分析:

2.根据迷宫特性修改“栈”

        1.定义结构体point,里面含有两个int型数据x,y;用于记录二维坐标。

typedef struct
{
    int x;    //坐标点的x值
    int y;    //坐标点的y值
} point;

        2.在“栈”中储存point类型数据,用于记录走过的路径。

typedef point DataType;    //将point数据类型定义为DataType

typedef struct
{
    int MAXNUM;
    int top;
    DataType *element;
} seqStack;

typedef seqStack *PseqStack;

        3.定义结构体direct用于表示在迷宫中的移动方向。

typedef struct
{
    int incX;    //increase_x表示x方向的增量
    int incY;    //increase_y表示y方向的增量

} Direct;

3.使用“栈”解决迷宫问题

        上源码

int main()
{
    int maze[12][12] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
        1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
    PseqStack Stack = CreateStack(100);
    int towards;
    Direct direct;
    DataType pos;

    pos.x = 1;
    pos.y = 1;
    PushStack(Stack, pos);  //起始点(1,1)

    while (1)
    {
        for (towards = 0; towards < 4; towards++) //遍历上下左右四个方向,查询各点状态是否为出路
        {
            switch (towards)
            {
            case 0: 
                direct.incX = 1;    //向右,沿X轴正方向移动
                direct.incY = 0;
                break;
            case 1:
                direct.incX = 0;    //向下,沿Y轴正方向移动
                direct.incY = 1;
                break;
            case 2:
                direct.incX = -1;   //向右,沿X轴负方向移动
                direct.incY = 0;
                break;
            case 3:
                direct.incX = 0;    //向上,沿Y轴负方向移动
                direct.incY = -1;
                break;
            default:
                break;
            }

            if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0)    //若当前方向找到出路,则停止遍历
            {
                break;
            }
        }

        if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若可以找到出路,则入栈新位置,并将旧位置点标记为-1
        {
            pos.x = pos.x + direct.incX;
            pos.y = pos.y + direct.incY;
            PushStack(Stack, pos);
            maze[pos.x][pos.y] = -1;

        }
        else //若无法找到出路,则进行退栈操作(即返回上一步)
        {
            PopStack(Stack);
            pos = TopStack(Stack);
            continue;
        }

        if (IsEmptyStack(Stack) == 1) //若退栈回溯至起点,则表明该迷宫无解
        {
            printf("Cannot find the path!\n");
            PrintStack(Stack);
            break;
        }
        else    //若当前位置已经到达(10,10),则表明找到出口,结束
        {
            if (TopStack(Stack).x == 10 && TopStack(Stack).y == 10) 
            {
                break;
            }
        }
    }

    PrintStack(Stack);  //打印当前栈内数据

    return 0 ;
}

                运行结果:

Point[0]=[1,1]
Point[1]=[2,1]
Point[2]=[2,2]
Point[3]=[2,3]
Point[4]=[3,3]
Point[5]=[4,3]
Point[6]=[5,3]
Point[7]=[5,4]
Point[8]=[6,4]
Point[9]=[7,4]
Point[10]=[8,4]
Point[11]=[8,5]
Point[12]=[8,6]
Point[13]=[7,6]
Point[14]=[6,6]
Point[15]=[5,6]
Point[16]=[4,6]
Point[17]=[3,6]
Point[18]=[3,7]
Point[19]=[2,7]
Point[20]=[1,7]
Point[21]=[1,8]
Point[22]=[1,9]
Point[23]=[2,9]
Point[24]=[3,9]
Point[25]=[4,9]
Point[26]=[5,9]
Point[27]=[6,9]
Point[28]=[6,8]
Point[29]=[7,8]
Point[30]=[8,8]
Point[31]=[9,8]
Point[32]=[9,9]
Point[33]=[10,9]
Point[34]=[10,10]

         路线如下

三.总结

        额其实也没什么好总结的,迷宫问题是很经典的数据结构问题,解法也有很多,相信大家都可以通过学习找出更优质的解法,欢迎一起讨论,如有不足也欢迎指出。

#include <stdio.h>
#include <stdlib.h>
/*
    使用栈作为辅助结构,实现迷宫找路问题。
*/
typedef struct
{
    int x;
    int y;
} point;
typedef point DataType;
typedef struct
{
    int MAXNUM;
    int top;
    DataType *element;
} seqStack;

typedef seqStack *PseqStack;

typedef struct
{
    int incX;
    int incY;

} Direct;

PseqStack CreateStack(int maxnum)
{
    if (maxnum > 0)
    {
        PseqStack stack = (PseqStack)malloc(sizeof(PseqStack));
        stack->MAXNUM = maxnum;
        stack->top = -1;
        stack->element = (DataType *)malloc(sizeof(DataType) * maxnum);
        return stack;
    }
    else
    {
        return NULL;
    }
}

/*
 *   若栈不存在,则返回-1;若栈为空,则返回1;若栈不为空,则返回0。
 */
int IsEmptyStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        return -1;
    }
    else
    {
        if (stack->top == -1)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

/*
 *   若栈不存在,则返回-1;若栈不满,则返回0;若栈满,则返回1。
 */
int IsFullStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        return -1;
    }
    else
    {
        if (stack->top == stack->MAXNUM - 1)
        {
            return 1;
        }
        else
        {
            return 0;
        }
    }
}

/*
 *   将数据data插入栈中,若栈为空则返回-1;若栈已满则返回0;若插入成功则返回1。
 */
int PushStack(PseqStack Stack, DataType data)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        printf("栈不存在");
        return -1;
    }

    {
        if (IsFullStack(stack) == 1)
        {
            printf("栈已满,无法入栈");
            return 0;
        }
        else
        {
            stack->top++;
            stack->element[stack->top] = data;
            return 1;
        }
    }
}

/*
 *弹出栈顶元素,若栈不存在则返回-1;若栈为空则返回0;若弹出成功则返回栈顶元素。
 */
DataType PopStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    DataType rData;
    rData.x = -1;
    rData.y = -1;
    if (stack == NULL)
    {
        printf("栈不存在");
        return rData;
    }
    else
    {
        if (IsEmptyStack(stack) == 1)
        {
            printf("栈为空,无法出栈");
            return rData;
        }
        else
        {
            DataType data = stack->element[stack->top];
            rData.x = 0;
            rData.y = 0;
            stack->element[stack->top] = rData;
            stack->top--;
            return data;
        }
    }
}

/*
 *返回栈顶元素,若栈不存在则返回-1;若栈为空则返回0。
 */
DataType TopStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    DataType rData;
    rData.x = -1;
    rData.y = -1;
    if (stack == NULL)
    {
        return rData;
    }
    else
    {
        if (IsEmptyStack(stack))
        {
            return rData;
        }
        else
        {
            return stack->element[stack->top];
        }
    }
}

/*
*打印栈内现有元素,若栈不存在则返回-1;若栈为空则返回0。
*/
int PrintStack(PseqStack Stack)
{
    PseqStack stack = Stack;
    if (stack == NULL)
    {
        return -1;
    }
    else
    {
        if (IsEmptyStack(stack) == 1)
        {
            return 0;
        }
        else
        {
            for (int i = 0; i <= stack->top; i++)
            {
                DataType data = stack->element[i];
                printf("Point[%d]=[%d,%d]\n", i, data.x, data.y);
            }
        }
    }
}

/*
 *   使用栈作为辅助结构,实现迷宫找路问题。
 *      0   1   1   1   0   0   0   0   0   0
 *		0   0   0   1   0   0   0   1   0   0
 *		0   1   0   1   1   0   0   1   0   0
 *		0   1   0   0   1   0   1   1   0   0
 *		0   1   0   0   1   0   1   1   0   0
 *		1   1   1   0   1   0   1   0   0   0
 *		0   0   1   0   0   0   1   0   1   1
 *		0   0   1   0   0   0   1   0   1   1
 *		0   1   1   0   1   0   1   0   0   0
 *		0   0   0   0   1   0   1   1   0   0
 *   element元素十位数表示x,个位数表示y
 */
void TASK_3(void)
{
    int maze[12][12] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
        1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
        1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1,
        1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
    PseqStack Stack = CreateStack(100);
    int towards;
    Direct direct;
    DataType pos;

    pos.x = 1;
    pos.y = 1;
    PushStack(Stack, pos);  //起始点(1,1)

    while (1)
    {
        for (towards = 0; towards < 4; towards++) //遍历上下左右四个方向,查询各点状态是否为出路
        {
            switch (towards)
            {
            case 0: 
                direct.incX = 1;    //向右,沿X轴正方向移动
                direct.incY = 0;
                break;
            case 1:
                direct.incX = 0;    //向下,沿Y轴正方向移动
                direct.incY = 1;
                break;
            case 2:
                direct.incX = -1;   //向右,沿X轴负方向移动
                direct.incY = 0;
                break;
            case 3:
                direct.incX = 0;    //向上,沿Y轴负方向移动
                direct.incY = -1;
                break;
            default:
                break;
            }

            if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0)    //若当前方向找到出路,则停止遍历
            {
                break;
            }
        }

        if (maze[pos.x + direct.incX][pos.y + direct.incY] == 0) //若可以找到出路,则入栈新位置,并将旧位置点标记为-1
        {
            pos.x = pos.x + direct.incX;
            pos.y = pos.y + direct.incY;
            PushStack(Stack, pos);
            maze[pos.x][pos.y] = -1;

        }
        else //若无法找到出路,则进行退栈操作(即返回上一步)
        {
            PopStack(Stack);
            pos = TopStack(Stack);
            continue;
        }

        if (IsEmptyStack(Stack) == 1) //若退栈回溯至起点,则表明该迷宫无解
        {
            printf("Cannot find the path!\n");
            PrintStack(Stack);
            break;
        }
        else    //若当前位置已经到达(10,10),则表明找到出口,结束
        {
            if (TopStack(Stack).x == 10 && TopStack(Stack).y == 10) 
            {
                break;
            }
        }
    }

    PrintStack(Stack);  //打印当前栈内数据
}

int main()
{
    
    TASK_3();

    return 0;
}

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,是一种常见的数据结构,可以用来解决迷宫问题。下面是使用完成迷宫问题算法C语言实现): 1. 定义一个,用来存储迷宫的路径。 2. 定义一个二维数组来表示迷宫,其中0表示可以通过的路,1表示墙,2表示已经走过的路。 3. 从起点开始,将起点压入中。 4. 从中取出当前位置,如果当前位置为终点,则输出路径,并结束程序。 5. 如果当前位置不是终点,则将当前位置标记为已经走过的路(2)。 6. 依次判断当前位置的上、下、左、右四个方向是否可以走,如果可以走,则将下一个位置压入中。 7. 如果四个方向都不能走,则将当前位置从中弹出,回到上一个位置。 8. 重复步骤4到步骤7,直到找到终点或者为空。 下面是代码实现: ```c #include <stdio.h> #include <stdlib.h> #define ROW 10 #define COL 10 typedef struct { int x; int y; } Point; typedef struct { Point data[ROW * COL]; int top; } Stack; void init(Stack *s) { s->top = -1; } void push(Stack *s, Point p) { s->data[++(s->top)] = p; } Point pop(Stack *s) { return s->data[(s->top)--]; } Point getTop(Stack *s) { return s->data[s->top]; } int isEmpty(Stack *s) { return s->top == -1; } int isFull(Stack *s) { return s->top == ROW * COL - 1; } int maze[ROW][COL] = { {1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,1,0,0,0,0,1}, {1,0,1,0,1,0,1,1,0,1}, {1,0,1,0,1,0,0,0,0,1}, {1,0,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,1,1,1,1,1,1,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,1,1,1,0,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1}, }; int main() { Stack s; init(&s); Point start = {1, 1}; Point end = {8, 8}; push(&s, start); while (!isEmpty(&s)) { Point cur = getTop(&s); if (cur.x == end.x && cur.y == end.y) { printf("Path found:\n"); for (int i = 0; i <= s.top; i++) { printf("(%d,%d)\n", s.data[i].x, s.data[i].y); } return 0; } maze[cur.x][cur.y] = 2; if (cur.y + 1 < COL && maze[cur.x][cur.y + 1] == 0) { Point next = {cur.x, cur.y + 1}; push(&s, next); } else if (cur.x + 1 < ROW && maze[cur.x + 1][cur.y] == 0) { Point next = {cur.x + 1, cur.y}; push(&s, next); } else if (cur.y - 1 >= 0 && maze[cur.x][cur.y - 1] == 0) { Point next = {cur.x, cur.y - 1}; push(&s, next); } else if (cur.x - 1 >= 0 && maze[cur.x - 1][cur.y] == 0) { Point next = {cur.x - 1, cur.y}; push(&s, next); } else { pop(&s); } } printf("Path not found!\n"); return 0; } ``` 这段代码使用来存储路径,然后依次判断当前位置的四个方向是否可以走,如果可以走,则将下一个位置压入中,如果四个方向都不能走,则将当前位置从中弹出,回到上一个位置。如果找到终点,则输出路径,否则输出“Path not found!”。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值