图论简介及深度优先遍历和广度优先遍历实现
作者:互联网
图论简介
图论简介
图的定义
图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");
}
- 连通图&非连通图
-
实验现象
- 非连通图
- 连通图
- 非连通图
标签:优先,遍历,连通,numNodes,int,图论,邻接矩阵,++,顶点 来源: https://blog.csdn.net/Brid_ger/article/details/120241874