图的深度优先遍历和广度优先遍历
来源:互联网 发布:重庆oppo公司知乎 编辑:程序博客网 时间:2024/06/03 13:35
图的深度优先遍历和广度优先遍历
一、邻接表法建立图
创建图的方法有邻接矩阵和邻接表法。
- 邻接矩阵把边的关系包含在一个矩阵中,虽然很方便,但是,当图中的定点数远大于边数时,浪费了很大的空间。
- 邻接表把边与顶点的关系存在一个叫弧(边)的数据结构中,有几条边就创建几条弧。节省了内存空间,但也怎加了对各种结构体之间关系的理解难度。
- 其实图的DFS和BFS就算法上来看,是非常简单的,但是要很流利的写出图的这两种遍历的算法,要对结构体之间关系有较好的理解。
下面先来看数据结构:
typedef enum{DG,DN,UDG,UDN}GraphyType; //图的种类typedef struct ArcNode //弧结点{ int adjVerxIndex; //该弧指向的顶点在图中顶点数组的下标 struct ArcNode* nextArc; //该弧在邻接表中的下一条弧}ArcNode;typedef struct VertexNode //顶点{ char data; //顶点数据 ArcNode* firstArc; //该顶点相连的第一条弧}VertexNode;typedef struct graphy //邻接表(图){ VertexNode vertex[MAXSIZE]; int verNum,arcNum; GraphyType type;//图的种类,若要简单可以舍去这一项}*AdjList;
再来看如何创建图:
int Locate(AdjList adj , char des) //通过顶点数据找到顶点下标{ for(int i = 0; i< adj->verNum; ++i) { if(des == adj->vertex[i].data) { return i; } } return -1;}void CreatAdjList(AdjList* adj)//创建图{ *adj = (AdjList)malloc(sizeof(graphy)); cout<<"请输入顶点数:"<<endl; cin>>(*adj)->verNum; cout<<"请输入边数:"<<endl; cin>>(*adj)->arcNum; (*adj)->type = DN; int i = 0; cout<<"请依次输入顶点的值:"<<endl; for(i = 0; i < (*adj)->verNum; ++i) { cin>>(*adj)->vertex[i].data; (*adj)->vertex[i].firstArc = NULL; } for(i = 0; i < (*adj)->arcNum; ++i) { char start,end; int ixS,ixE; cout<<"请输入第"<<i<<"条边的两个顶点值:"<<endl; cin>>start>>end; ixS = Locate(*adj,start); ixE = Locate(*adj,end); ArcNode* node = (ArcNode*)malloc(sizeof(ArcNode)); node->nextArc = (*adj)->vertex[ixS].firstArc; node->adjVerxIndex = ixE; (*adj)->vertex[ixS].firstArc = node;//头插法 }}
没什么难以理解的,就是把图结构体中的变量初始化,唯一要注意的是,在创建边的时候,采用头插还是尾插的方法对最后遍历结果有一定影响,实际上先遍历哪一个邻接点都没有关系,所以图的两种遍历结果其实都是不唯一的,只要某些关键点的前后顺序一致就行了。
二、图的深度优先遍历(DFS)
算法分析
图的深度优先遍历其实就是通常说的回溯,一般用递归实现,做法是依次对每个未访问的结点做DFS。
DFS:访问该顶点,然后在一个循环中分别对每一个邻接点做DFS,直到所有邻接点都已做完DFS返回,可见DFS使用了递归。
代码:
void Dfs(AdjList adj, int i){ if(flag[i]) { return; } cout<<adj->vertex[i].data<<" "; flag[i] = true; ArcNode* p = adj->vertex[i].firstArc; while(p) { Dfs(adj,p->adjVerxIndex); p = p->nextArc; }}
三、图的广度优先遍历(BFS)
算法分析
- 图的广度优先遍历一般用队列来实现,和深度优先遍历一样,依次对图中每一个未访问的顶点做BFS.
- BFS:访问一个节点之前,现将这个顶点入队,然后在访问,访问完毕之后,将他的所有邻接点入队。然后判断队列是否为空,若为空则表示访问完毕,退出循环,可见BFS未用递归。
代码:
void Bfs(AdjList adj,int i){ q.push(i); while(!q.empty()) { if(!flag[q.front()]) { cout<<adj->vertex[q.front()].data<<" "; flag[q.front()] = true; } ArcNode* p = adj->vertex[q.front()].firstArc; q.pop(); while(p) { q.push(p->adjVerxIndex); p = p->nextArc; } } }
四、整体实现及测试结果
画图分析:
整体代码:
#include<iostream>#include<malloc.h>#include<queue>#include<string.h>#define MAXSIZE 20using namespace std;typedef enum{DG,DN,UDG,UDN}GraphyType;bool flag[MAXSIZE] = {false}; queue<int> q;typedef struct ArcNode{ int adjVerxIndex; struct ArcNode* nextArc;}ArcNode;typedef struct VertexNode{ char data; ArcNode* firstArc;}VertexNode;typedef struct graphy{ VertexNode vertex[MAXSIZE]; int verNum,arcNum; GraphyType type;}*AdjList;void Dfs(AdjList adj, int i);void Bfs(AdjList adj,int i);int Locate(AdjList adj , char des){ for(int i = 0; i< adj->verNum; ++i) { if(des == adj->vertex[i].data) { return i; } } return -1;}void CreatAdjList(AdjList* adj){ *adj = (AdjList)malloc(sizeof(graphy)); cout<<"请输入顶点数:"<<endl; cin>>(*adj)->verNum; cout<<"请输入边数:"<<endl; cin>>(*adj)->arcNum; (*adj)->type = DN; int i = 0; cout<<"请依次输入顶点的值:"<<endl; for(i = 0; i < (*adj)->verNum; ++i) { cin>>(*adj)->vertex[i].data; (*adj)->vertex[i].firstArc = NULL; } for(i = 0; i < (*adj)->arcNum; ++i) { char start,end; int ixS,ixE; cout<<"请输入第"<<i<<"条边的两个顶点值:"<<endl; cin>>start>>end; ixS = Locate(*adj,start); ixE = Locate(*adj,end); ArcNode* node = (ArcNode*)malloc(sizeof(ArcNode)); node->nextArc = (*adj)->vertex[ixS].firstArc; node->adjVerxIndex = ixE; (*adj)->vertex[ixS].firstArc = node; }}void Print(AdjList adj){ for(int i = 0; i < adj->verNum; ++i) { if(flag[i]) { continue; } cout<<"DFS:"<<endl; Dfs(adj,i); } memset(flag,0,MAXSIZE); for(int i = 0; i < adj->verNum; ++i) { if(flag[i]) { continue; } cout<<endl<<"BFS:"<<endl; Bfs(adj,i); }}void Dfs(AdjList adj, int i){ if(flag[i]) { return; } cout<<adj->vertex[i].data<<" "; flag[i] = true; ArcNode* p = adj->vertex[i].firstArc; while(p) { Dfs(adj,p->adjVerxIndex); p = p->nextArc; }}void Bfs(AdjList adj,int i){ q.push(i); while(!q.empty()) { if(!flag[q.front()]) { cout<<adj->vertex[q.front()].data<<" "; flag[q.front()] = true; } ArcNode* p = adj->vertex[q.front()].firstArc; q.pop(); while(p) { q.push(p->adjVerxIndex); p = p->nextArc; } } } int main(){ AdjList adj; CreatAdjList(&adj); Print(adj); return 0;}
3.结果:
阅读全文
0 0
- 图的遍历:深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历算法
- 图的深度优先遍历和广度优先遍历实现
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的广度优先遍历和深度优先遍历
- 图的深度优先遍历和广度优先遍历
- 邻接图的广度优先遍历和深度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的深度优先遍历和广度优先遍历
- 图的建立、广度优先遍历和深度优先遍历
- 数据结构---图的广度优先遍历和深度优先遍历
- 图的深度优先遍历和广度优先遍历
- WebStorm使用参考手册
- Java学习之路
- Windows7下为PHP安装redis扩展
- ABAP检查日期and时间合法性的函数
- Word中的Visio图直接转换为图片
- 图的深度优先遍历和广度优先遍历
- IOS汉字转拼音首字母
- 算法编程题6-字符串拼接找到字典序最小组合问题
- 线程中sleep()方法和Object类中的wait()方法的区别
- MSPG2553 FLASH操作
- URI与url的区别
- robotframework中常遇到的问题
- Vue.js常用指令汇总(v-if、v-for等)
- linux ftp服务器配置