博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图的遍历——邻接表实现
阅读量:3947 次
发布时间:2019-05-24

本文共 4272 字,大约阅读时间需要 14 分钟。

此篇博客主要就图的储存结构——邻接表展开。

邻接表

图的一种最便于理解的储存结构就是邻接矩阵了(可以简单的把它视为一个二维数组),但是邻接矩阵在处理边数较少,但顶点较多的情况时会浪费不少的储存空间。因此便有了邻接表这种储存结构。

  1. 图中顶点用一个一维数组存储, 当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
  2. 图中每个顶点 Vi 的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点 Vi 的边表,有向图则称为顶点 Vi 作为弧尾的出边表。

如下图:

在这里插入图片描述根据上图,再来看相关结点的定义就比较好理解了。

//边表结点typedef struct EdgeNode     {
int adjvex; //邻接点域,储存顶点对应的下标 //int weight; //权值 struct EdgeNode *next; }EdgeNode;//顶点表结点typedef struct VertexNode{
int data; //储存顶点信息 EdgeNode *firstedge; //边表头结点}VertexNode, AdjList[MAXVEX];typedef struct{
AdjList adjList; int vernum, edgenum; //当前顶点数,结点数}Graph;

下来再让我们一起来看一下如何建立邻接表(无向图)。

//建立邻接表void CreatALGraph(Graph *G){
int i, j, k, w; EdgeNode *e; printf("输入顶点数和边数:"); scanf("%d %d", &G->vernum, &G->edgenum); //建立顶点表 printf("输入顶点:"); for(i = 0; i < G->vernum; ++i) {
scanf("%d", &G->adjList[i].data); G->adjList[i].firstedge = NULL; } //建立边表 for(k = 0; k < G->edgenum; ++k) {
printf("输入边上的顶点序号:"); scanf("%d %d", &i, &j); //无向图,两次插入(头插法) e = (EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex = j; //e->weight = w; e->next = G->adjList[i].firstedge; //将e指向当前顶点指向的结点 G->adjList[i].firstedge = e; //将当前顶点指向e e = (EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex = i; //e->weight = w; e->next = G->adjList[j].firstedge; //将e指向当前顶点指向的结点 G->adjList[j].firstedge = e; //将当前顶点指向e }}

图的遍历

从图中某一顶点出发访问图中其余顶点,且使每一个顶点仅能被访问一次,这个过程就叫做图的遍历。

深度优先遍历

简单理解,就是一条路走到黑,不撞南墙不回头🦐 。

如下图,给定一个迷宫,要求从顶点 A 出发,访问其余所有顶点。
在这里插入图片描述加深的黑线便是我们所走过的路程(默认开始走右边的路径),当遇到重复顶点时便会回溯(撞到墙🌶)。
可以看出,转化为右图后,就相当于一个树的前序遍历。

结论:

从图中某个顶点 V 出发,访问此顶点,然后从 V 的未被访问的邻接点出发深度优先遍历图,直至图中所有和 V 相通的顶点都被访问到。若图中尚有顶点未被访问(非连通图),则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到。

//dfsvoid dfs(Graph G, int i){
book[i] = 1; printf("%d ", G.adjList[i].data); EdgeNode *e = G.adjList[i].firstedge; while(e) {
if(!book[e->adjvex]) dfs(G, e->adjvex); //对未访问的邻接顶点递归调用 e = e->next; }}void dfsTraverse(Graph G){
int i; for(i = 0; i < G.vernum; ++i) book[i] = 0; for(i = 0; i < G.vernum; ++i) {
if(!book[i]) //未被访问 dfs(G, i); } printf("\n");}

上面是dfs的递归版本,再让我们来看一看非递归的吧

//dfs——非递归void dfs_(Graph G){
memset(book, 0, MAXVEX); std::stack
S; S.push(0); while(!S.empty()) {
int n = S.top(); S.pop(); if(!book[n]) {
book[n] = 1; printf("%d ", G.adjList[n].data); } EdgeNode *e = G.adjList[n].firstedge; while(e) {
if(!book[e->adjvex]) S.push(e->adjvex); e = e->next; } } printf("\n");}

广度优先遍历

bfs 有一种广撒网的意思🌶

在这里插入图片描述dfs 类似于树的前序遍历,而bfs 就有点类似于层序遍历了。

结论:

从图中某个顶点 V 出发,访问此顶点,将与其有边且未被访问的顶点都依次入队,按出队顺序依次执行以上步骤。

//bfsvoid bfsTraverse(Graph G){
int i; EdgeNode *e; std::queue
Q; for(i = 0; i < G.vernum; ++i) book[i] = 0; for(i = 0; i < G.vernum; ++i) {
if(!book[i]) {
book[i] = 1; printf("%d ", G.adjList[i].data); Q.push(i); while(!Q.empty()) {
i = Q.front(); Q.pop(); e = G.adjList[i].firstedge; //当前顶点边表头指针 while(e) {
if(!book[e->adjvex]) {
book[e->adjvex] = 1; printf("%d ", G.adjList[e->adjvex].data); Q.push(e->adjvex); } e = e->next; //指向下一邻接点 } } } } printf("\n");}

补充——销毁边表节点

void DeleteEdge(Graph *G){
EdgeNode *e; for(int i = 0; i < G->vernum; ++i) {
while(G->adjList[i].firstedge != NULL) {
e = G->adjList[i].firstedge; G->adjList[i].firstedge = e->next; free(e); } }}

深度优先遍历与广度优先遍历在时间复杂度上是一致的,不同之处在与对顶点的访问顺序不同。

深度优先遍历更适合目标比较明确,以找到目标为目地的情况,而广度优先遍历更适合寻找相对最优解。

参考

《数据结构与算法》——王曙燕

《大话数据结构》

转载地址:http://ejqwi.baihongyu.com/

你可能感兴趣的文章
android如何使得电阻屏在第一次开机时自动叫起屏幕校准程序
查看>>
android如何实现:当开启图案解锁时,取消滑动解锁
查看>>
Providing Ancestral and Temporal Navigation 设计高效的应用导航
查看>>
Putting it All Together: Wireframing the Example App 把APP例子用线框图圈起来
查看>>
Implementing Lateral Navigation 实现横向导航
查看>>
Implementing Ancestral Navigation 实现原始导航
查看>>
Implementing Temporal Navigation 实现时间导航
查看>>
Responding to Touch Events 响应触摸事件
查看>>
Defining and Launching the Query 定义和启动查询
查看>>
Handling the Results 处理结果
查看>>
如何内置iperf到手机中
查看>>
如何adb shell进入ctia模式
查看>>
Contacts Provider 联系人存储
查看>>
android 图库播放幻灯片时灭屏再亮屏显示keyguard
查看>>
android 图库语言更新
查看>>
android camera拍照/录像后查看图片/视频并删除所有内容后自动回到camera预览界面
查看>>
android 图库中对非mp4格式的视频去掉"修剪"功能选项
查看>>
how to disable watchdog
查看>>
android SDIO error导致wifi无法打开或者连接热点异常的问题
查看>>
android USB如何修改Serial Number or SN?
查看>>