数据结构课程设计-用图搜索方法解决迷宫问题

本文探讨了路径设计问题,特别是通过迷宫问题来阐述。利用邻接表这一图的链式存储结构,文章详细解释了如何构建和遍历这种数据结构。同时,介绍了深度优先搜索算法在解决迷宫路径问题中的应用,通过递归方式遍历图以找到从起点到终点的路径。最后,提供了具体的C语言代码实现,展示了如何创建邻接表,执行深度优先搜索以及销毁邻接表的过程。
摘要由CSDN通过智能技术生成

摘  要

在现实生活中,有许多路径的设计问题,比如铺设路面、铺设线路、铺设水管等等,面对这些问题,我们需要找到许多不同的路径,需要考虑到具体生活中的某些问题,比如地形地貌、适不适合从某个地点通过,只有合理的设计线路,才能更好的构建幸福家园,所以构建路径就显得尤为重要。

章  绪  论

1.1 课设主要研究问题    

迷宫问题是取自心理学的一个古典实验。在该实验中,把一只老鼠从一个无顶大盒子的门放入,在盒子中设置了许多墙,对行进方向形成了多处阻挡。盒子仅有一个出口,在出口处放置块奶酪,吸引老鼠在迷宫中寻找道路以到达出口。对同一只老鼠重复进行上述实验,一直到老鼠从入口走到出口,而不走错-一步。老鼠经过多次试验最终学会走通迷宫的路线。设计一个计算机程序对任意设定的矩形迷宫如下图A所示,求出一条从入口到出口的通路,或得出没有通路的结论。

1.2 课设应用的理论知识

1.2.1 邻接表

邻接表(Adjacency List)是图的一种链式存储结构。在邻接表中,对图中每个顶点Vi建立一个单链表,把与Vi相邻接的顶点放在这个链表中。邻接表中每个单链表的第一个节点存放有关顶点的信息,把这一节点看成链表的表头,其余节点存放有关边的信息,这样邻接表便由两部分组成:表头节点表和边表。

(1)表头节点表:由所有表头节点以顺序结构的形式存储,以便可以随机访问任一顶点的边链表。表头节点包括数据域(data)和链域(frstarc)两部分,如图(a)所示。其中,数据域用于存储顶点Vi的名称或其他有关信息:链域用于指向链表中第一个节点(与顶点口邻接的第一个邻接点)。

   边表:由表示图中顶点间关系的2n个边链表组成。边链表中边节点包括邻接点域(adivex)、数据域(info)和链域(nextare)了个部分,如图(b)所示。其中,邻接点域指示与顶点,邻接的点在图中的位置;数据域存储和边相关的信息,如权值等;链域指示与顶点Vi邻接的下一条边的节点。

图的遍历:和树的遍历类似,图的遍历也是从图中某一项点出发,拔照某种方法对图中所有项点进行访问且仅访问一次。图的遍历算法是求解因的连通性问题、拓扑排序和关键路径等算法的基础。然而,图的過历要比树的適历复杂得多。因为图的任一项点都可能和其余的顾点相邻拉,所以在访问了某个顶点之后,可能沿着某条路径搜索之后,又回到该顶点上。为了避免同一项点被访问至次,在遍历图的过程中,必领记下每个已访问过的顶点。为此,

设一个铺助数组visited[n],其初始值置为“false”或者0,一旦访问了顶点Vi,便置visited[i]为“true”或者1。

深度优先搜索:

深度优先搜索遍历的过程

,深度优先搜素(Depth First Search,DFS),遍历类似于树的先序通历,是树的先序遍历的推广对于一个连通图,深度优先搜索遍历的过程如下

(1)从图中某个顶点以发,访问”。

(2)找出刚访问过的顶点的第一个未被访问的邻接点,访问该顶点。以该顶点为新顶点,面复此步骤,直至刚访问过的顶点没有未被访同的邻接点为止。

(3)返回前一个访问过的且仍有末被访间的邻接点的顶点,找出该顶点的下一个未被访问的邻接点,访问该顶点。

(4)重复步骤(2)和生骤(3),直至图中所有顶点都被访问过,搜索结束。

第二章  课设实现过程

2.1 深度优先

深度优先算法:

算法实现:深度优先搜索遍历连通图是一个递归的过程。为了在遍历过程中便于区分项点是否己被访问,需附设访问标志数组visited[n],其初值为

“false”或“0”一旦某个顶点被访问,则其相应的分量置为“true”或“1”

2.2 算法实现

采用邻接表表示图的深度优先搜索遍历

【算法描述】

void DFS AL (AIGraph G, int V)

{//图G为邻接表类型,从第,个顶点出发深度优先搜素遍历图G

cout<<v; visited[v]=true;//访问第了个项点,并置访问标志数组相应分量的值为true

p=G.vertices[v].firstarc//0指向口的边链表的第一个边节点

while (p!=NULL)        //边节点非空

{

w=p->adjvex;     // 表示w是v的邻接点

if (!visited[w]) DFS_AL(G,W);//如果w未访问,则递归调用DES_AL()

p=p->nextarc;                 //p指向下一个边节点

}                             //while

}                              

程序代码

#include <stdio.h>
#include <malloc.h>

#define MAX_SIZE 100
#define M 4                                 // 行数
#define N 4                                 // 列数

/*----------------------------以下定义邻接表类型---------------------------*/
typedef struct ANode                        // 边的结点结构类型
{
    int i, j;                               // 该边的终点位置(i,j)
    struct ANode *nextarc;                  // 指向下一条边的指针
}ArcNode;

typedef struct Vnode                        // 邻接表头结点的类型
{
    ArcNode *firstarc;                      // 指向第一个相邻点
}VNode;

typedef struct
{
    VNode adjlist[M + 2][N + 2];            // 邻接表头结点数组
}ALGraph;                                   // 图的邻接表类型

typedef struct
{
    int i;                                  // 当前方块的行号
    int j;                                  // 当前方块的列号
}Box;

typedef struct
{
    Box data[MAX_SIZE];
    int length;                             // 路径长度
}PathType;                                  // 定义路径类型

int cnt = 0;
int visited[M + 2][N + 2] = {0};

/*-------------------由迷宫数组mg建立对应的邻接表G--------------------*/
static void CreateAdj(ALGraph *&G, int mg[][N + 2])
{
    int i, j;
    int di;
    int i1, j1;
    ArcNode *p;

    G = (ALGraph *)malloc(sizeof(ALGraph));
    for(i = 0; i < M + 2; i++)              // 给邻接表中所有头结点的指针域设置初值
    {
        for(j = 0; j < N + 2; j++)
        {
            G->adjlist[i][j].firstarc = NULL;
        }
    }

    for(i = 1; i <= M; i++)                 // 检查mg中每个元素
    {
        for(j = 1; j <= N; j++)
        {
            if(mg[i][j] == 0)
            {
                di = 0;
                while(di < 4)
                {
                    switch(di)
                    {
                    case 0:                                     // 向上走
                        i1 = i - 1;
                        j1 = j;
                        break;
                    case 1:                                     // 向右走
                        i1 = i;
                        j1 = j + 1;
                        break;
                    case 2:                                     // 向下走
                        i1 = i + 1;
                        j1 = j;
                        break;
                    case 3:                                     // 向左走
                        i1 = i;
                        j1 = j - 1;
                        break;
                    }
                    if(mg[i1][j1] == 0)                         // (i1,j1)为可走方块
                    {
                        p = (ArcNode *)malloc(sizeof(ArcNode)); // 创建一个结点p
                        p->i = i1;
                        p->j = j1;
                        p->nextarc = G->adjlist[i][j].firstarc; // 将p结点链到链表后
                        G->adjlist[i][j].firstarc = p;
                    }
                    di++;
                }
            }
        }
    }
}

/*-----------------------输出邻接表G--------------------------*/
static void DispAdj(ALGraph *G)
{
    int i, j;
    ArcNode *p;

    for(i = 0; i < M + 2; i++)
    {
        for(j = 0; j < N + 2; j++)
        {
            printf(" [%d,%d]: ", i, j);
            p = G->adjlist[i][j].firstarc;
            while(p != NULL)
            {
                printf("(%d,%d)", p->i, p->j);
                p = p->nextarc;
            }
            printf("\n");
        }
    }
}

/*---------------------销毁邻接表--------------------------*/
static void DestroyAdj(ALGraph *&G)
{
    int i, j;
    ArcNode *pre, *p;

    for(i = 0; i < M + 2; i++)
    {
        for(j = 0; j < N + 2; j++)
        {
            pre = G->adjlist[i][j].firstarc;
            if(pre != NULL)
            {
                p = pre->nextarc;
                while(p != NULL)
                {
                    free(pre);
                    pre = p;
                    p = p->nextarc;
                }
                free(pre);
            }
        }
    }
    free(G);
}

/*--------------在图G中采用DFS算法求(xi,yi)到(xe,ye)的所有路径-------------*/
// path数组记录访问过的顶点序列,当找到出口时输出path中的访问序列
static void FindPath(ALGraph *G, int xi, int yi, int xe, int ye, PathType path)
{
    ArcNode *p;

    visited[xi][yi] = 1;                                        // 置已访问标记
    path.data[path.length].i = xi;                              // 设置起始方块的行号
    path.data[path.length].j = yi;                              // 设置起始方块的列号
    path.length++;

    if((xi == xe) && (yi == ye))                                // 走到迷宫的出口(M,N)时,输出迷宫路径
    {
        printf(" 迷宫路径%d: ", ++cnt);
        for(int k = 0; k < path.length; k++)
        {
            printf("(%d,%d)", path.data[k].i, path.data[k].j);  // 输出迷宫的行号和列号
        }
        printf("\n");
    }
    p = G->adjlist[xi][yi].firstarc;                            //p指向顶点v的第一条边顶点
    while(p != NULL)
    {
        if(visited[p->i][p->j] == 0)                            // 若(p->i,p->j)方块未访问,则递归访问它
            FindPath(G, p->i, p->j, xe, ye, path);
        p = p->nextarc;                                         //p指向顶点v的下一条边顶点
    }
    visited[xi][yi] = 0;                                        // 取消访问标记
}

int main(void)
{
    ALGraph *G;
    int mg[M + 2][N + 2] = {                                    // 一个迷宫:其四周加上均为1的外框
        {1, 1, 1, 1, 1, 1}, 
		{1, 0, 0, 0, 1, 1},
        {1, 0, 1, 0, 0, 1}, 
		{1, 0, 0, 0, 1, 1},
        {1, 1, 0, 0, 0, 1}, 
		{1, 1, 1, 1, 1, 1}
    };

    CreateAdj(G, mg);
    printf("迷宫对应的邻接表:\n");
    DispAdj(G);                                                 // 输出邻接表
    PathType path;
    path.length = 0;
    printf("所有的迷宫路径:\n");
    FindPath(G, 1, 1, M, N, path);
    DestroyAdj(G);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X-MTing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值