图、广度优先算法与深度优先算法
文章目录
图(Graph)
结构类型 | 研究方向 |
---|---|
线性结构 | 研究数据元素之间的一对一关系。 |
树结构 | 研究数据元素之间的一对多关系。 |
图结构 | 研究数据元素之间的多对多关系。 |
线性结构:研究数据元素之间的一对一关系。在这种结构中,除第一个和最后一个元素外,任何一个元素都有唯一的一个直接前驱和直接后继。
树结构:研究数据元素之间的一对多关系。在这种结构中,每个元素对下(层)可以有0个或多个元素相联系,对上(层)只有唯一的一个元素相关,数据元素之间有明显的层次关系。
图结构:研究数据元素之间的多对多关系。在这种结构中,任意两个元素之间可能存在关系。即结点之间的关系可以是任意的,图中任意元素之间都可能相关。
基本概念
图的定义
定义:图定义为一个偶对(V,E) ,记为G=(V,E) 。
其中: V是顶点(Vertex)的非空有限集合,记为V(G);E是无序集V&V的一个子集,记为E(G) ,其元素是图的弧(Arc)。
形式化定义:
G=(V ,E)
V={v|vdata object}
E={<v,w>| v,wV∧p(v,w)}
P(v,w)表示从顶点v到顶点w有一条直接通路。
图的相关术语
弧(Arc):表示两个顶点v和w之间存在一个关系,用顶点偶对<v,w>表示。通常根据图的顶点偶对将图分为有向图和无向图。
有向图: 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是有序的,称图G是有向图。
在有向图中,若 <v,w>E(G) ,表示从顶点v到顶点w有一条弧。 其中:v称为弧尾或始点,w称为弧头或终点。
无向图: 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是无序的,称图G是无向图。
在无向图中,若<v,w>E(G) ,有<w,v>E(G) ,即E(G)是对称,则用无序对(v,w) 表示v和w之间的一条边(Edge),因此(v,w) 和(w,v)代表的是同一条边。
注意:有序对和无序对所用的括号不一样,有序对使用尖括号,无序对使用圆括号。
度、入度、出度:对于无向图G=(V,E), viV,图G中依附于vi的边的数目称为顶点vi的度,记为TD(vi)。
显然,在无向图中,所有顶点度的和是图中边的2倍。 即 ∑TD(vi)=2e i=1, 2, …, n ,e为图的边数。
对有向图G=(V,E),若vi V ,图G中以vi作为起点的有向边(弧)的数目称为顶点vi的出度,记为OD(vi) ;以vi作为终点的有向边(弧)的数目称为顶点vi的入度,记为ID(vi) 。顶点vi的出度与入度之和称为vi的度,记为TD(vi) 。即
TD(vi)=OD(vi)+ID(vi)
抽象数据定义
ADT Graph{
数据对象V:具有相同特性的数据元素的集合,称为顶点集。
数据关系R:R={VR}
//VR={<v,w>|<v,w>| v,wV∧p(v,w) ,<v,w>表示从v到w的弧,P(v,w)定义了弧<v,w>的信息 }
基本操作P:
Create_Graph() : 图的创建操作。
初始条件:无。
操作结果:生成一个没有顶点的空图G。
GetVex(G, v) : 求图中的顶点v的值。
初始条件:图G存在,v是图中的一个顶点。
操作结果:生成一个没有顶点的空图G.
… …
DFStraver(G,V):从v出发对图G深度优先遍历。
初始条件:图G存在。
操作结果:对图G深度优先遍历,每个顶点访问且只访问一次。
BFStraver(G,V):从v出发对图G广度优先遍历。
初始条件:图G存在。
操作结果:对图G广度优先遍历,每个顶点访问且只访问一次。
} ADT Graph
图的存储结构
图的存储结构相对复杂,其复杂性主要表现在:
- 任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系。
- 图中顶点的度不一样,有的可能相差很大,如果按照度数最大的顶点设计结点结构,则会浪费很多存储单元,反之按照每个顶点自己的度设计不同结构则会影响操作。
常用存储结构:邻接矩阵、邻接链表、十字链表、临界多重表和边表。
邻接矩阵(Matrix)
基本思想:对于有n个顶点的图,用一维数组vexs[n]存储顶点信息(类似于线性表中的数据域),用二维数组A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中,以顶点在vexs数组中的下标代表顶点,邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关系的信息。
无向无权图G=(V,E)有n(n≧1)个顶点,其邻接矩阵是n阶对称方阵,如图7-5所示。其元素的定义如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F16cqmsG-1591419259863)(./G.png)]
建立图(Graph)类
#define MaxVnum 50//设置最大顶点数50
typedef double Matrix[MaxVnum][MaxVnum];//建立一个二位矩阵类型
class Graph
{
public:
Graph();
~Graph();
void printArcs();
void printvexnum();
void reset();
void DFS(int v);
void BFS();
private:
int vexnum = 8;//顶点数
int arcnum = 9;//孤数
int vexs[8];//顶点集
Matrix arcs;//邻接矩阵
bool visited[8];//用于判断顶点是否被访问了
};
初始化Graph对象
Graph::Graph()
{
for (int i = 0; i < vexnum; i++)
{
for (int j = 0; j < vexnum; j++)
{
arcs[i][j] = 0;
}
}
arcs[0][1] = 1;
arcs[0][2] = 1;
arcs[1][0] = 1;
arcs[1][3] = 1;
arcs[1][4] = 1;
arcs[2][0] = 1;
arcs[2][5] = 1;
arcs[2][6] = 1;
arcs[3][1] = 1;
arcs[3][7] = 1;
arcs[4][1] = 1;
arcs[4][7] = 1;
arcs[5][2] = 1;
arcs[5][6] = 1;
arcs[6][2] = 1;
arcs[6][5] = 1;
arcs[7][3] = 1;
arcs[7][4] = 1;
for (int i = 0; i < vexnum; i++)
{
vexs[i] = i + 1;
}
}
图的深度优先算法
void Graph::DFS(int v)
{
visited[v] = true;
cout << vexs[v] << " ";//输出顶点中的数据
for (int i = 0; i < vexnum; i++)
{
if (arcs[v][i]==1&&visited[i]==false)
{
DFS(i);
}
}
}
图的广度优先算法
#include "Queue.h"//循环队列
void Graph::BFS()
{
CirQueue Q;
for (int i = 0; i < vexnum; i++)
{
if (visited[i]==false)
{
Q.EnQueue(i);
visited[i] = true;
while (!Q.Empty())
{
int t = Q.DeQueue();
cout << vexs[t] << " ";
for (int j = 0; j < vexnum; j++)
{
if (arcs[t][j]==1&&visited[j]==false)
{
Q.EnQueue(j);
visited[j] = true;
}
}
}
}
}
}