【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;
}

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我们可以用C语言实现迷宫小游戏。 首先,我们需要定义迷宫的地图。可以用二维数组来表示迷宫的地图,其中0表示可以通行的路,1表示障碍物。 ```c #define ROW 10 #define COL 10 int map[ROW][COL] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 0, 1, 1, 0, 0}, {0, 1, 1, 0, 0, 0, 1, 1, 0, 0}, {0, 1, 1, 0, 1, 1, 1, 1, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; ``` 接下来,我们定义结构体和相关的操作。 ```c #define MAX_STACK_SIZE 100 typedef struct { int row; int col; } Position; typedef struct { Position data[MAX_STACK_SIZE]; int top; } Stack; void initStack(Stack *s) { s->top = -1; } int isStackEmpty(Stack *s) { return s->top == -1; } int isStackFull(Stack *s) { return s->top == MAX_STACK_SIZE - 1; } void push(Stack *s, Position pos) { if (isStackFull(s)) { printf("Stack is full.\n"); return; } s->top++; s->data[s->top] = pos; } Position pop(Stack *s) { if (isStackEmpty(s)) { printf("Stack is empty.\n"); Position p = {-1, -1}; return p; } Position p = s->data[s->top]; s->top--; return p; } Position peek(Stack *s) { if (isStackEmpty(s)) { printf("Stack is empty.\n"); Position p = {-1, -1}; return p; } return s->data[s->top]; } ``` 然后,我们定义一个函数来判断一个位置是否可以通行。 ```c int isPositionValid(Position pos) { if (pos.row < 0 || pos.row >= ROW || pos.col < 0 || pos.col >= COL) { return 0; } if (map[pos.row][pos.col] == 1) { return 0; } return 1; } ``` 接下来,我们定义一个函数来打印迷宫的地图。 ```c void printMap() { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { printf("%d ", map[i][j]); } printf("\n"); } } ``` 最后,我们定义一个函数来实现迷宫的小游戏。该函数首先将起点入,并不断出,判断出的位置是否为终点,如果是则游戏结束,否则将该位置的上、下、左、右四个相邻位置入,并将该位置标记为已访问。 ```c void mazeGame(Position start, Position end) { Stack s; initStack(&s); push(&s, start); while (!isStackEmpty(&s)) { Position current = pop(&s); if (current.row == end.row && current.col == end.col) { printf("Congratulations! You have reached the end of the maze.\n"); return; } if (map[current.row][current.col] != 2) { map[current.row][current.col] = 2; if (isPositionValid((Position){current.row - 1, current.col})) { push(&s, (Position){current.row - 1, current.col}); } if (isPositionValid((Position){current.row + 1, current.col})) { push(&s, (Position){current.row + 1, current.col}); } if (isPositionValid((Position){current.row, current.col - 1})) { push(&s, (Position){current.row, current.col - 1}); } if (isPositionValid((Position){current.row, current.col + 1})) { push(&s, (Position){current.row, current.col + 1}); } } } printf("Sorry, you have failed to reach the end of the maze.\n"); } ``` 现在我们可以在main函数中调用mazeGame函数来开始迷宫小游戏。 ```c int main() { Position start = {1, 1}; Position end = {8, 8}; printMap(); mazeGame(start, end); return 0; } ``` 这样,我们就用C语言实现了迷宫小游戏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值