图论简介及深度优先遍历和广度优先遍历实现

图论简介

图的定义

图G =(V,E),V是顶点的又穷非空集合,E是边集合。
V(G)和E(G)分别表示G的顶点集合和边集合。其中,E(G)可以为空集。
若E(G)为有向边的集合,则G为有向图,反之为无向图。
<x,y>表示有向图的边,称之为弧,x为起点,y为终点。(x,y)表示无向图的边,没有特定方向。

图的基本术语

n表示图中的顶点数,e表示边的数目。
(1)子图:G=(V,E)和G’=(V’,E’),如果V’、E’都分别含于V、E,则G’是G的子图。

(2)无向完全图和有向完全图:对于无向图,若有n(n-1)/2条边,则成为无向完全图;对于有向完全图,若有n(n-1)条弧,则称为有向完全图。

(3)稀疏图和稠密图:区分关键在于
e < n l o g 2 n ? e<nlog_2n\quad? e<nlog2n?
(4)权和网:带权的图称为网,权值可以标在边上。

(5)邻接点:顶点v和v’如果存在一边/弧,则成为v和v’互为邻接点/相关联。

(6)度、入度和出度:顶点v的度是指和v相关联的边数,记为TD(v)。对有向图而言,还有入度和出度的概念,入度表示以v为头的弧的数目,出度表示以v为尾的弧的数目。

(7)连通,连通图,连通分量:连通,两顶点之间有路径即连通,任意两顶点均存在路径即连通图,非连通图可以有连通分量。

(8)强连通图:对有向图而言。

图的类型定义及实现–基于邻接矩阵表示法

邻接矩阵表示法

  • 图的邻接矩阵:

A [ i ] [ j ] = { 1 若 < v i , v j > 或 ( v i , v j ) ∈ E 0 反 之 A[i][j]= \begin{cases} 1\qquad若<v_i,v_j>或(v_i,v_j)\in E\\ 0\qquad反之 \end{cases} A[i][j]={1<vi,vj>(vi,vj)E0

  • 网的邻接矩阵:

A [ i ] [ j ] = { w i , j 若 < v i , v j > 或 ( v i , v j ) ∈ E ∞ 反 之 A[i][j]= \begin{cases} w_{i,j}\qquad若<v_i,v_j>或(v_i,v_j)\in E\\ \infty\qquad反之 \end{cases} A[i][j]={wi,j<vi,vj>(vi,vj)E

  • 代码实现
#define MAXVEX 20
#define INFINITY 32768

typedef char VertexType; /* 顶点类型应由用户定义  */
typedef int EdgeType; /* 边上的权值类型应由用户定义 */
typedef struct MyGraph
{
	VertexType vexs[MAXVEX]; /* 顶点表 */
	EdgeType arc[MAXVEX][MAXVEX];/* 邻接矩阵,可看作边表 */
	int numNodes, numEdges; /* 图中当前的顶点数和边数  */
}MyGraph;

图的基本操作

  • 创建无向网

    算法步骤:

    • 输入总顶点数和总边数
    • 依次输入顶点信息
    • 初始化邻接矩阵使每个权值初始化为最大值
    • 构造邻接矩阵。依次输入边所依附的顶点和权值,并在对称位置赋相同值。如果是有向图,只对弧所对应的顶点赋权值即可。
Status CreatUDN(MyGraph& G)
{
	cout << "输入总顶点数,总边数,以空格或回车隔开" << endl;
	cin >> G.numNodes >> G.numEdges;
	cout << "依次输入顶点的信息" << endl;
	for (int i = 0; i < G.numNodes; i++)
		cin >> G.vexs[i];
	//初始化邻接矩阵,将权值均置为极大值
	for (int i = 0; i < G.numNodes; i++)
		for (int j = 0; j < G.numNodes; j++)
			G.arc[i][j] = INFINITY;	//如果是图,INFINITY置0即可
	cout << "输入一条边依附的顶点及权值" << endl;
	for (int k = 0; k < G.numEdges; k++)
	{
		VertexType v1, v2;
		EdgeType w;
		cin >> v1 >> v2 >> w;
		int i = LocateVex(G, v1), j = LocateVex(G, v2);
		G.arc[i][j] = w;			//如果是图,赋值为1即可
		G.arc[j][i] = G.arc[i][j];	//如果是有向网或有向图,注掉此行即可
	}
	return OK;
}
  • 返回顶点位置
    查找顶点u是否在G内。如果在,返回顶点位置;否则,返回-1。
int LocateVex(MyGraph G,VertexType u)
{
	for (int i = 0; i < G.numNodes; i++)
		if (u == G.vexs[i])
			return i;
	return -1;
}
  • 查找第一个邻接点

    查找该顶点是否存在邻接点。如果存在,返回邻节点位置,否则,返回-1。

int FirstAdjVex(MyGraph G, int v)
{
	for (int i = 0; i < G.numNodes; i++)
	{
		if (G.arc[v][i] != INFINITY)
			return i;
	}
	return -1;
}
  • 查找下一个邻接点

    给出当前邻接点,查找该顶点是否存在下一个邻接点。如果存在,返回顶点位置,否则,返回-1。

int NextAdjVex(MyGraph G, int v, int w)
{
	for (int i = w + 1; i < G.numNodes; i++)
	{
		if (G.arc[v][i] != INFINITY)
			return i;
	}
	return -1;
}
  • 输出图的邻接矩阵

    遍历输出邻接矩阵数组

    void PrintfUDN(MyGraph G)
    {
    	for (int i = 0; i < G.numNodes; i++)
    	{
    		for (int j = 0; j < G.numNodes; j++)
    			cout << G.arc[i][j] << "=>";
    		cout << endl;
    	}
    }
    

图的深度优先遍历

算法简介
  • 从图中某顶点v出发,先访问顶点v,此时,记录visited[v] = true
  • 对连通图:依次从v的未访问的邻接点出发,对图进行深度优先遍历;直至图中和v连通的顶点都被访问。
  • 对于非连通图:如果此时图中尚有未被访问的顶点,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问为止。
  • 可以通过栈结构或递归来实现
算法实现
//连通图
void DFS(MyGraph G, int v)
{
	cout << G.vexs[v]; visited[v] = true;
	for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
	{
		if (!visited[w])
			DFS(G, w);
	}
}
//非连通图
void DFSTraverse(MyGraph G)
{
	for (int v = 0; v < G.numNodes; v++)
	{
		visited[v] = false;
	}
	for (int v = 0; v < G.numNodes; v++)
	{
		if (!visited[v])
			DFS(G,v);
	}
}
//邻接矩阵
void DFSMyGraph(MyGraph G, int v)
{
	for (int v = 0; v < G.numNodes; v++)
	{
		visited[v] = false;
	}
	cout << G.vexs[v]; visited[v] = true;
	for (int w = 0; w < G.numNodes; w++)
	{
		if ((G.arc[v][w] != INFINITY) && (!visited[w]))
			DFS(G, w);
	}
}

图的广度优先遍历

算法简介
  • 靠近节点v的首先被访问,先进先出,和队列的思想吻合
  • 从图中某顶点v出发,先访问顶点v,将v放入队列Q。此时,记录visited[v] = true
  • 对于连通图:队列Q中顶点出队,依次访问图中未被访问的邻接点,若存在未被访问的顶点,则将其放入队列Q,直至队列Q为空
  • 对于非连通图:如果此时图中尚有未被访问的顶点,则从一个未被访问的顶点出发,重新进行广度优先遍历,直到图中所有顶点均被访问为止。
算法实现
//对于连通图
void BFS(MyGraph G, int v)
{
	MySqQueue Q;
	for (int v = 0; v < G.numNodes; v++)
	{
		visited[v] = false;
	}
	cout << G.vexs[v]; visited[v] = true;
	InitQueue(Q);
	EnQueue(Q, v);
	while (!QueueEmpty(Q))
	{
		int u;
		DeQueue(Q, u);
		for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w))
		{
			if (!visited[w])
			{
				cout << G.vexs[w]; visited[w] = true;
				EnQueue(Q, w);
			}
		}
	}
}
//对于非连通图
void BFSTraverse(MyGraph G)
{
	for (int v = 0; v < G.numNodes; v++)
	{
		visited[v] = false;
	}
	for (int v = 0; v < G.numNodes; v++)
	{
		if (!visited[v])
			BFS(G, v);
	}
}
//邻接矩阵
void BFSMyGraph(MyGraph G, int v)
{
	for (int v = 0; v < G.numNodes; v++)
	{
		visited[v] = false;
	}
	BFS(G, w);
}

BFS和DFS实验验证

  • 测试代码
#include "Graph.h"
MyGraph graph;
int main()
{
	CreatUDN(graph);
	PrintfUDN(graph);
	system("pause");
	cout << "逐节点深度优先遍历:" << endl;
	for (int i = 0; i < graph.numNodes; i++)
	{
		cout << "\n以节点"<<graph.vexs[i]<<"开始" << endl;
		DFSMyGraph(graph, i);
	}
	system("pause");
	DFSTraverse(graph);
	system("pause");
	cout << "逐节点广度优先遍历:" << endl;
	for (int i = 0; i < graph.numNodes; i++)
	{
		cout << "\n以节点" << graph.vexs[i] << "开始" << endl;
		BFSMyGraph(graph,i);
	}
	system("pause");
	BFSTraverse(graph);
	system("pause");
}
  • 连通图&非连通图

在这里插入图片描述

  • 实验现象

    • 非连通图
      在这里插入图片描述
    • 连通图
      在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值