王道数据结构6(图)
Posted 晨沉宸辰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了王道数据结构6(图)相关的知识,希望对你有一定的参考价值。
图
一.概念
顶点
V(顶点的有穷非空集合)
VR(两个顶点之间的关系集合)
弧:(有向图,无向图)
n图中顶点的数目
e表示边和弧的数目
无向完全图(有n(n-1)/2条边的无向图)
有向完全图(有n(n-1)条弧有向图)
稀疏图,稠密图
权
网:带网的图
子图:
邻接点:顶点之间邻接
顶点的度:
入度(ID)和出度(OD)
路径长度
回路
简单路径:序列中顶点不重复的路径
环回路:除第一个顶点和最后一个顶点之外,其余顶点不重复出现
连通图
连通分量:无向图的极大连通子图
强连通图
强连通分量:有向图的极大强连通子图称为有向图的强连通分量。
一个连通图的生成树:是一个极小连通子图,它含有图中全部顶点,但只有足以构成一棵树的n-1条边。
二.图的储存结构(邻接矩阵法)
1.数组表示法
【1】有向图
G1的邻接矩阵为:
【2】无向图
G2的邻接矩阵为:
网的邻接矩阵定义为:
a[i][j]:
(1) Wij 若<vi,vj> 或(vi,vj )∈VR(2)∞ 反之
说明:1.对于无向图,顶点vi的度是邻接矩阵中第i行(或第i列)的元素之和,
TD(vi)= ∑ a[i][j]
2.对于有向图,顶点VI的出度OD(vi)是邻接矩阵中第i行的元素之和,顶点vi的出度ID(vi)是邻接矩阵中第j列)的元素之和,
2. 定义邻接矩阵的结构
#define INFINITY INT_MAX
#define MAX_VERTEXT_NUM 20
typedef enumDG,DN,AG,ANGraphKind;
typedef struct ArcCell
VRType adj;//对无向图,用0,1表示是否相邻,对于带权图,为权值
InfoType *info;//该弧相关信息的指针
RrcCell,AdjMatrix[MAX_VERTEXT_NUM][MAX_VERTEXT_NUM];//邻接矩阵
3. 定义图的结构
//定义图的结构
typedef struct
VertextType exs[MAX_VERTEXT_NUM];
AdjMatrix arcs[MAX_VERTEXT_NUM][MAX_VERTEXT_NUM];
int vexnum,arcnum;
GraphKind kind;
MGraph;
4. 构造图G
status CreateGraph(MGraph &G)
scanf(&G.kind)
case DG:return CreateDG(G);
case DN:return CreateDN(G);
case UDG:return CreateUDG(G);
case UDN:return CreateDGN(G);
default:return ERROR;
//用无向图为例
status CreateUDN(MGraph &G)
scanf(&G.arcnum,&G.vexnum,&IncInfo);//输入点数和边数
//给顶点进行数字化编号
for(i=0;i<G.vexnum;i++)
scanf(&G.exs[i]);//定义顶点数组(如果顶点本身就是1~n的数字无需这一步)
//初始化邻接矩阵
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=ININITY,NULL;
//通过边数进行遍历
for(k=0;k<G.arcnum;K++)
scanf(&V1,&V2,&W);//输入邻接的连个顶点
i=locatteVex(G,V1);j=locateVex(G,V2);//查找V1,V2的位置
G.arcs[i][j].adj=w;//给邻接矩阵赋值
if(IncInfo)
INPUT(*G.arcs[i][j].info);
G.arcs[j][i]=G.arcs[i][j];//由于是无向图,对称
return ok;
5. 特点
优点:
-
无向图邻接矩阵是对称矩阵,同一条边表示了两次
-
顶点v的度:等于二维数组对应行(或列)中1的个数
-
判断两顶点v、u是否为邻接点:只需判二维数组对应分量是否为1
-
在图中增加、删除边:只需对二维数组对应分量赋值1或清0
-
占用存储空间只与它的顶点数有关,与边数无关;适用于边稠密的图
-
对有向图的数组表示法可做类似的讨论
缺点: -
不便于删除和增加顶点
-
不便于统计边的数目,需要扫描邻接矩阵所有元素才能统计完毕,时间复杂度为O(n2 )
-
空间复杂度高,对于有向图,n个顶点需要n2 个单元存储边,对于无向图,n(n-1)/2个单元,空间复杂度为O(n2 )
三. 储存结构(邻接表表示法)
1. 储存方式
【1】无向图
- 把从一个顶点出发的边链接在一个单链表(又名边链表)中把从一个顶点出发的边链接在一个单链表(又名边链表)中
- 所有边链表的表头指针放在一个顺序表中
【2】有向图
注意,在有向图的邻接表中不易找到指向该顶点的弧。
2. 结构
【1】顶点的结点结构
———————
| data | firstarc |
———————
- data数据域:储存顶点vi
- firstarc链域:指向链表中第一个结点
【2】弧的结点结构
——————————
| adjvex | info | nextarc |
——————————
- adjvex邻接点域:与顶点vi邻接的点在图中的位置
- info数据域:储存和边相关的信息,如权值
- nextarc链域:与顶点vi的点在图中的位置
3.图的邻接表存储表示(算法)
#define MAX_VERTEXT_NUM 20
//建立边结点
typedef struct ArcNode
int adjvex; // 该弧所指向的顶点的位置
struct ArcNode *nextarc; // 指向下一条弧
InfoType *info; // 该弧相关信息(可选)
ArcNode;
// 顶点结点
typedef struct VNode
VertexType data; // 顶点信息
ArcNode *firstarc; // 指向第一条依附该顶点的弧
VNode,AdjList[MAX_VERTEXT_NUM];
//邻接表
typedef struct
Adjlist vertices;
int vexnum,arcnum;
int kind;
ALGraph;
//建立邻接表算法
//初始化一个结点总数为num的图,k为图的类型,num为结点总数
void InitG(ALGraph G,enum GraphKind k,int num)
G.kind=k;
G.vexnum=num;
G.vertices=new VNode[vexnum];
for(int i=0;i<G.vexnum;i++)
G.vertices[i].Firstarc=NULL;
cin>>G.vertics[i].data;
//有向图(网)增加弧的算法,将弧(from,to,weight)加入图
void InsertArc(ALGragh G,int from,int to,int weight)
ArcNode *s=new ArcNode;
s->weight=weight;
s->adjvex=to;
s->nextarc=G.vertices[from].firstarc;//插到链表vertices[from]的头
G.vertices[from].firstarc=s;
- 在邻接表中,同一条边对应两个结点;
- 顶点v的度:等于v 对应的链表的长度;
- 判定两顶点v,w是否邻接:要看v对应的链表中有无对应的结点w(相反判断也行);
- 增减边:要在两个单链表插入、删除结点;
- 占用存储空间与顶点数、边数均有关;适用于边稀疏的图
四.图的遍历
1. 图遍历的概述
1、定义——从某顶点出发,沿着一些边访问连通图中所有顶点,且使每个顶点仅访问一次的运算。
2、为避免重复访问,可设置辅助数组Visited[ ],各分量初值为0,当顶点被访问,对应分量被置为1。
3、方法——深度优先(depth first search DFS)
广度优先(breadth first search BFS)
2.深度优先遍历
###(1)算法描述
从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到。
~
W1、W2和W3 均为 V 的邻接点,SG1、SG2 和 SG3 分别为含顶点W1、W2和W3 的子图。
从上页的图解可见::
- 从深度优先搜索遍历连通图的过程类似于树的先根遍历;
- 如何判别V的邻接点是否被访问?
解决的办法是:为每个顶点设立一个 “访问标志数组bool visited[vexnum]”。
###(2)算法实现
- 邻接矩阵
int visited[MAX];//设置一个数组,判断是否遍历过,false/1为遍历过
void DFGTraverse(Graph G,int v)
for(v=0;v<G.vexnum;v++)
visited[v]=0;//初始化判断数组
for(v=0;v<G.vexnum;v++)
if(!visited[v])//如果没有遍历过
DFS(G,V);//进行遍历
void DFS(Graph G,int v)//进行递归遍历
visited[v]=1;printf(v);//改变判断数组,输出点
for(w=FirstVex(G,v);w!=0;w=NextVex(G,v))//从每一行第一个邻接矩阵值为1的,跳转到下一个值为1的
if(!visited[w])
DFS(G,v);
int FirstVex(Graph G,int v)//判断第一个不是0的
int i;
for(i=0;i<G.vexnum;i++)
if(G.arcs[v][i]==1&&visited[i]==False)
return i;
return -1;
void NextVex(Graph G,int v)//判断下一个不是0的
int i;
for(i=w;i<G.vexnum;i++)
if(G.arcs[v][i]==1&&visited[i]!=False)
return i;
return -1;
2.邻接表
void DFS(Graph G,int v)
cout<<G.vertices[v].data<<" ";
visited[v]=true;
ArcNode *p=G.vertices[v].firstarc;
while(p!=NULL)
int w=p->adjvex;
if(!visited[w])
DFS(G,w);
p=p->nextarc;a
(3)时间复杂度
T(n)=o(n2) 邻接矩阵
T(n)=O(e+n) 邻接表
3. 广度优先遍历
(1)算法描述
- 从图中某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。
- 对于非连通图,可能此时尚有顶点未被访问,则另选图中一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。
(2)例子:
(3)算法
以上是关于王道数据结构6(图)的主要内容,如果未能解决你的问题,请参考以下文章
计算机组成原理 王道考研2021 第二章:数据的表示和运算 -- 浮点数的表示和IEEE754标准
计算机组成原理 王道考研2021 第二章:数据的表示和运算 -- 定点数vs浮点数定点数的表示(原/反/补/移码)原/反/补/移码作用