栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

图的深度广度(矩阵与表四种可执行)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

图的深度广度(矩阵与表四种可执行)

功名半纸,风雪千山

不得不说八个字,真的是充满佛性

文章目录
  • 前言
  • 一、深度优先遍历(DFS)
    • 思想
    • 深度优先(邻接矩阵)
    • 效果截图
    • 深度优先(邻接表)
    • 运行截图
  • 二、广度优先(BFS)
    • 思想
    • 广度优先(邻接矩阵)
    • 运行截图
    • 深度优先(邻接表)
    • 运行截图
  • 可执行代码汇总


前言

提示:以下是本篇文章正文内容,下面案例可供参考
上一篇我们写过创建一个图的常用的三种方式,也写了对应的打印方式,第一希望读者自己打一遍,因为你都不知道你自己怎么放的数据,你又和谈操作呢?,脑子中最起码要有它怎么放的,这里同样附上链接,但是我们打印却只是检查存储是否正确,今天我们就来唠唠关于图的遍历的那些事,之前树那一个章节的时候 我们就说过,其实三种遍历方式也就是深度优先,层序遍历也就是广度遍历 这里图也是分为广度和深度

一、深度优先遍历(DFS) 思想

其实思想就是一直往下找若是与当前结点邻接的顶点都被遍历过了,则返回此结点的上一个顶点 继续检查,因为要检查所以我们需要另外再定义一个数组,来判断此时的点 是否遍历过,直到所有返回到根,并且根的所有顶点也被访问过,不知道你有没有听懂,这里我们使用一个图来讲解一下 本来想画图的 但是相当太丑了,还是使用word来写了

基于上图 最后的遍历顺序就是ACBED 有人可能会问为什么在图的讲解中使用的是树,就遍历来说没有区别,思路都是一样的,至于这里为什么使用使用这个图 给你一点提示 “凯佐苦喔尼,喔类哇纳鲁” 真中二,哈哈哈,收… 下面写出代码

深度优先(邻接矩阵)

解析放在代码中了

void DFS(AMGraph G,int i){//给一个结点给一个图
	//我们来看结点i的所有关联点从中找到一个未遍历的
	//这里使用的是邻接表 所以它的邻接点就是数组的行
	for(int j=0;j
		if(G.arcs[i][j]!=0&&visited[j]==false){//i结点与j结点存在边 并且j结点没有被访问过  
			visited[j]=true;
			cout<
	for(int i=0;i//因为有可能是非连通图 
		if(visited[i]==false){//若是没有遍历则遍历 
			visited[i]=true;
			cout< 
效果截图 

深度优先(邻接表)

邻接表的深度需要绕一点点弯 但是思想与邻接矩阵是一样的 第一个我们启动的时候传入的是第一个图的第一个顶点 我们要找到第一个点邻接的点cur->adjvex 判断这些邻接中那些没有被访问过,我们就深入,这个时候其实就需要脑子中有递归的执行方式 而不是像一些‘大神’说的递归简单的理解成将问题变小处理小问题就行

void DFSChart(AdjoinChart G,int i){//从顶点i连接的点中选择一个没有被遍历过的  然后深入 
	ArcNode* cur=G.vertices[i].firstarc; 
	while(cur){
		if(visited[cur->adjvex]==false){
			visited[cur->adjvex]=true;
			cout<adjvex].data<<" ";
			DFSChart(G,cur->adjvex);
		}
		cur=cur->nextarc;
	}
}
//深度优先遍历(邻接表)
void DFSTrevelChart(AdjoinChart G){
	for(int i=0;i//因为有可能是非连通图 
		if(visited[i]==false){//若是没有遍历则遍历 
			visited[i]=true;
			cout< 
运行截图 

因为是无向图 输入的时候也就需要AC CA 各输入一次 边的个数也就变成了两倍

二、广度优先(BFS) 思想

这里对上述的图进行一波修改 其实与树中的层序遍历有点类似 所以这里依然是使用的队列来进行的操作 所以这个时候可能有人问了 所以上面的深度优先可以使用栈?这里认为是可以的,而且应该是前序的方式,不知道大家是否记得我们写过树的前序遍历 而且不止一种方式

广度优先(邻接矩阵)

这里我第一次写也写错了 只要是一直将他类比成树种 但这里使用的是数组 我刚开始的时候就是没有确定队首元素的位置 调试的时候才发现的,还有就是要注意第一次来到一个

//从i点开始进行广度 
void BFSAdjoin(AMGraph G,int i){
	queue Q;
	cout<
		char first=Q.front();
		int h=0;while(first!=G.vexs[h++]);//来寻找队列中第一个字母在顶点表终点位置
		//int size=Q.size();//就跟前面写过的层序遍历一样 这里也分层输出  明显一点
		for(int j=0;j
			if(G.arcs[h-1][j]!=0&&visited[j]==false){
				cout<
	for(int i=0;i//为了避免非连通图的情况 
		if(visited[i]==false)BFSAdjoin(G,i); 
	} 
}
运行截图

深度优先(邻接表)
//广义邻接表 
void BFSCharst(AdjoinChart G,int i){//其实跟上面是一样的  就是对数据的操控  
	queue Q;
	cout<
		VNode first=Q.front();
		//此时我们要找到i的邻接点  并且没有被访问过的
		ArcNode* cur=first.firstarc;
		while(cur){
			if(visited[cur->adjvex]==false){
				visited[cur->adjvex]=true;
				cout<<"将"<adjvex].data<<"放入队列"<adjvex].data<<" ";
				Q.push(G.vertices[cur->adjvex]); 
			}
			cur=cur->nextarc;
		}
		Q.pop();
	} 
} 
//广义优先(邻接表)
void  BFSTravelChart(AdjoinChart G){
	for(int i=0;i//为了避免非连通图的情况 
		if(visited[i]==false)BFSCharst(G,i); 
	} 
} 

运行截图

因为邻接表的插入是头插入,所以也就导致不一样的输入方式 就有不一样的运行结果 但是一层一层还是不会变得 因为是无向图,所以输入的个数要是正反两个方向都要输入

可执行代码汇总
#include
using namespace std;
#define MaxInt 32767  //表示极大值∞  其实就是一种无穷标志
#define MVNum  100    //表示最大顶点数 
typedef char VerTexType;//假设顶点的数据结构类型为char 
typedef int  ArcType;//假设权值类型为整形
//下面的是邻接矩阵的 
typedef struct{
	 VerTexType vexs[MVNum];//顶点表 
	 ArcType  arcs[MVNum][MVNum];//邻接矩阵 
	 int vexnum;//图的当前顶点数
	 int arcnum;//图的当前边数
}AMGraph;


//需要判读此时点是否遍历过 所以需要一个数组来与点对应
bool visited[MVNum]={false};


//下面的结构体是邻接表的 
typedef struct ArcNode{//边结构
  int adjvex;//该边所指向的顶点的位置
  struct ArcNode *nextarc;//指向下一条边的指针 
  int info; //和边相关的信息如权重等  若是没有权值也可以省略 省略之后就可以于点结构相统一
}ArcNode; 
typedef struct VNode{//顶点结构
	VerTexType  data;
	ArcNode *firstarc;	//指向第一条依附该顶点的边的指针 
}VNode; 
//相当于多个链表 将首结点存放于一个数组中  就像单链表中存放长度一样 这里存放的是点与边的个数  
typedef struct AdjoinChart{//邻接表 
	VNode vertices[MVNum];//因为顶点中已经存在边的信息了 也就不需要在添加了 
	int vexnum;//图当前的顶点数 
	int arcnum;//图当前的边数 
}AdjoinChart; 

//打印邻接矩阵 
void PrintAMG(AMGraph G){
	cout<<" "<<" ";
	for(int i=0;i
		cout<
		cout<
			cout<
	cout<<"请输入顶点数和边数"<>G.vexnum>>G.arcnum; 
	cout<<"请输入各个顶点名称"<
		cin>>G.vexs[i]; 
	}
	for(int h=0;h
		char vex1;char vex2;
		cout<<"请输入弧的两个顶点"<>vex1>>vex2; 
		//首先来看是否存在这两个顶点  若是存在则找到这两个点对应的下标
		// 当然创建的时候一种更加简单的方式就是遍历二维数组 一个一个输入
		int i=0;while(G.vexs[i++]!=vex1);
		int j=0;while(G.vexs[j++]!=vex2);
		if(i>G.vexnum||j>G.vexnum){//没有找到 
			cout<<"你输入的结点值不正确"<
			cout<<"请输入此边对应的权重"<>G.arcs[i-1][j-1];
			G.arcs[j-1][i-1]=G.arcs[i-1][j-1];
		}
	}
	PrintAMG(G);
}
//打印邻接表  每打印一个顶点 需要打印出相对应的链表 
void PrintAdjoinChart(AdjoinChart G){
	for(int i=0;i
		ArcNode* cur=G.vertices[i].firstarc;
		while(cur){
			cout<"<adjvex].data<<" ";
			cur=cur->nextarc;
		}
		cout<
	cout<<"请输入顶点数以及边的个数"<>G.vexnum>>G.arcnum;
	cout<<"请输入顶点名称"<
		cin>>G.vertices[i].data;
	}
	//输入一个边有点类似于单链表的插入
	for(int h=0;h
		cout<<"请一个弧的两个边,类如从A指向B则 输入A B"<>vex1>>vex2;
		//依然需要判断输入的结点是否存在;
		int i=0;while(G.vertices[i++].data!=vex1);
		int j=0;while(G.vertices[j++].data!=vex2);
		if(i>G.vexnum||j>G.vexnum){
			cout<<"你输入的位置不正确"<//这里使用头插插入一个弧 
			ArcNode* NewAcr=(ArcNode*)malloc(sizeof(ArcNode));
			NewAcr->nextarc=G.vertices[i-1].firstarc;
			G.vertices[i-1].firstarc=NewAcr;
			cout<<"请输入此边对应的权值"<>NewAcr->info;
			NewAcr->adjvex=j-1;
		}
	}
	PrintAdjoinChart(G);
}
//深入优先邻接矩阵 
void DFSAdjoin(AMGraph G,int i){//给一个结点给一个图
	//我们来看结点i的所有关联点从中找到一个未遍历的
	//这里使用的是邻接表 所以它的邻接点就是数组的行
	for(int j=0;j
		if(G.arcs[i][j]!=0&&visited[j]==false){//i结点与j结点存在边 并且j结点没有被访问过  
			visited[j]=true;
			cout<
	for(int i=0;i//因为有可能是非连通图 
		if(visited[i]==false){//若是没有遍历则遍历 
			visited[i]=true;
			cout<
	queue Q;
	cout<
		char first=Q.front();
		int h=0;while(first!=G.vexs[h++]);//来寻找队列中第一个字母在顶点表终点位置
		//int size=Q.size();//就跟前面写过的层序遍历一样 这里也分层输出  明显一点
		for(int j=0;j
			if(G.arcs[h-1][j]!=0&&visited[j]==false){
				cout<
	for(int i=0;i//为了避免非连通图的情况 
		if(visited[i]==false)BFSAdjoin(G,i); 
	} 
}
//广义邻接表 
void BFSCharst(AdjoinChart G,int i){//其实跟上面是一样的  就是对数据的操控  
	queue Q;
	cout<
		VNode first=Q.front();
		//此时我们要找到i的邻接点  并且没有被访问过的
		ArcNode* cur=first.firstarc;
		while(cur){
			if(visited[cur->adjvex]==false){
				visited[cur->adjvex]=true;
				cout<<"将"<adjvex].data<<"放入队列"<adjvex].data<<" ";
				Q.push(G.vertices[cur->adjvex]); 
			}
			cur=cur->nextarc;
		}
		Q.pop();
	} 
} 
//广义优先(邻接表)
void  BFSTravelChart(AdjoinChart G){
	for(int i=0;i//为了避免非连通图的情况 
		if(visited[i]==false)BFSCharst(G,i); 
	} 
} 

//深度优先邻接表 
void DFSChart(AdjoinChart G,int i){//从顶点i连接的点中选择一个没有被遍历过的  然后深入 
	ArcNode* cur=G.vertices[i].firstarc; 
	while(cur){
		if(visited[cur->adjvex]==false){
			visited[cur->adjvex]=true;
			cout<adjvex].data<<" ";
			DFSChart(G,cur->adjvex);
		}
		cur=cur->nextarc;
	}
}
//深度优先遍历(邻接表)
void DFSTravelChart(AdjoinChart G){
	for(int i=0;i//因为有可能是非连通图 
		if(visited[i]==false){//若是没有遍历则遍历 
			visited[i]=true;
			cout<
	cout<<"1、邻接矩阵 2、邻接表 "<
	int choice=0;
	cout<<"请输入你要使用何种方式来创建一个表"<>choice;
	switch(choice){
		case 1:{
			AMGraph G;
			CreateAdjoin(G);
			cout<<"是否要对图进行遍历"<>flag;
			if(1==flag){
				DFSTravel(G);	
			}
			else if(2==flag){
				BFSTravel(G);
			} 
			break;
		}
		case 2:{
			AdjoinChart G;
			CreateAdjoinChart(G);
			cout<<"是否要对图进行遍历"<>flag;
			if(1==flag){
				DFSTravelChart(G);	
			}
			else if(2==flag){
				BFSTravelChart(G); 
			} 
			else{
				;	
			}
			break;
		}
		default:break;
	}
} 

感觉对你有帮助的话 点歌赞呗 你的点赞是对作者的一种莫大鼓励

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/887399.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号