定义:由顶点集和边集组成,G=(E,V),其中V(G)=顶点个数,E(G)=边数
注:线性表可以是空表,树叶可以是空树,但图不可以是空,即V一定是非空集
种类
无向图
若E为无向边,则图为无向图,边(v,w)和顶点相关联;
-
度
-
顶点v的度是指依附于该顶点的边的条数,几位TD(v)。
-
度为边数*2;握手定理
-
-
路径
-
顶点v1到顶点v2之间的一条路径是指顶点序列,v1,v3,v4······v2;
-
-
回路
-
第一个顶点到最后一个顶点相同的路径称为回路或环;
-
-
简单路径
-
在路径序列中,定点不重复出现的路径称为简单路径。
-
-
简单贿赂
-
除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路;
-
-
路径长度
-
路径上边的数目
-
-
点到点的距离
-
从顶点u出发到顶点v的最短路径若存在则此路径的长度称为从u到v的距离。若从u到v根本不存在路径,则记该距离为无穷。
-
-
无向图中若从顶点v到顶点w有路径存在,则称v和w是连通的。
-
若无向图中任意两个顶点都是连通的,则称图G为连通图,否则称为非联通图。
-
n个顶点的无向图若为连通图,则最少有n-1条边
-
n个顶点的无向图若为连通图,则最多有n-1里面取条边
有向图
若E为有向边,则图为有向图,边<v,w>v称为弧尾,w称为弧头,<v,w>不等于<w,v>;
-
度
-
入度:是以顶点v为终点的有向边的数目,记为ID(v);
-
出度:是以顶点v为起点的有向边的数目,记为OD(v);
-
顶点v的度等于入度和出度之和,即TD(v)=ID(v)+OD(v).
-
入度之和=出度之和=边数
-
-
有向图中,若从顶点v到顶点w和从顶点w到顶点v之间都有路径,则称这两个顶点是强连通的
-
若图中任何一对顶点都是强连通的,则称此图为强连通图。
-
若为强连通图,则最少有n条边(形成回路)
简单图(数据结构常用)
简单图--1.不存在重复边;2.不存在顶点到自身的边;
多重图
多重图--图G中某两个节点之间的边数多于一条,又允许定点通过同一条边和自己关联,则G为多重图
子图
设有两个图G=(V,E)和G=(V
,E),若V
是v的子集,且E是E的子集,则称为G
是G的子图
生成子图
若有满足V(G`)=V(G)的子图,则称其为G的生成子图
连通分量
连通图:n-1条边
非连通图最多Cn-1 2条边
无向图中的极大连通子图称为连通分量
有向图中的极大强连通子图称为有向图的强连通分量
生成树
连通图的生成树是包含途中全部顶点的一个极小连通子图
生成森林
在非连通图中,连通分量的生成树构成了非连通图的生成森林
边的权,带权图/网
边的权--在一个图中,每条边都可以标上具有某种含义的数值,该数值称为该边的权值。
带权图/网--边上带有权值的图称为带权图,也称网。
带权路径长度--当图是带权图时,一条路径上所有边的权值之和,称为该路径的带权路径长度。
特殊的图
无向完全图--无向图中任意两个顶点之前都存在边。若其顶点数为|V|=n;|E|=[0,n(n-1)/2];
有向完全图--有向图中任意两个顶点之前都存在方向相反的两条弧。若其顶点数为|V|=n;|E|=[0,n(n-1)];
稀疏图--边很少的图(|E|<|V|log|V|)
稠密图--便很多的图
树--不存在回路,且连通的无向图(n个节点的树一定有n-1条边)
图的存储
邻接矩阵
#define MaxVertexNum 100 typedef struct{ char Vex[MaxVertexNum]; int Edge[MaxVertexNum][MaxVertexNum]; int vexnum,arcnum; }MGraph;
节点数为n的图G=(V,E)的邻接矩阵A是n*n的。将G的顶点编号为v1,v2······,vn;则
A[ i ] [ j ]={1,若(vi,vj)或<vi,vj>是E(G)中的边
{0,若(vi,vj)或<vi,vj>不是E(G)中的边
无向图:第i个结点的度=第i行(或第i列)的非零元素个数
有向图:第i个结点的出度=第i行的非零元素的个数
第i个结点的入度=第i列的非零元素个数
第i个结点的度=第i行,第i列的非零元素个数之和
注:邻接矩阵求顶点的度/出度/入度的时间复杂度为O(|V|)
邻接矩阵法存储带权图(网)
#define MaxVertexNum 100 //顶点数目的最大值 #define INFINITY 最大的int值 //宏定义常量“无穷” typedef char VertexType; //顶点的数据类型 typedef int EdgeType; //带权图中边上权值的数据类型 typedef struct{ VertexType Vex[MaxVertexNum]; //顶点 EdgeType Edge[MaxVertexNum][MaxVertexNum]; //边的权 int vexnum,arcnum; }MGraph; //图的当前顶点数和弧度
空间复杂度:O(|V|^2)--只和顶点数相关,和实际的边数无关
适合用于存储稠密图
无向图的邻接矩阵是对称矩阵,可以压缩存储(只存储上三角区/下三角区)
性质
A^n的元素A^n[i] [j]等于由顶点i到顶点j的长度为n的路径数目
邻接表法(顺序+链式存储)
边结点的数量是2|E|
适合存储稀疏图
表示方法不唯一
typedef struct{ AdjList vertices; int vexnum,arcnum; }ALGraph; typedef struct ArcNode{ int adjvex; //边弧指向哪个结点 struct ArcNode *next; //指向下一条弧的指针 //InfoType info; //边权值 }ArcNode; typedef struct VNode{ VertexType data; //顶点信息 ArcNode *first; //第一条边/弧 }VNode,AdjList[MaxVertexNum];
十字链表--存储有向图
空间复杂度:O(|V|+|E|)
弧结点:弧顶点编号,弧头顶点编号,权值,弧头相同的下一条弧。
顶点结点(用数组顺序存取):数据域,该顶点作为弧头的第一条弧,该顶点作为弧尾的第一条弧。
指定顶点的出边:绿色线路;
入边:橙色线路
邻接多重表--存储无向图
边结点:边结点两个顶点编号:i,j,info(权值)iLink依附于顶点i的下一条边,jLink依附于顶点j的下一条边。
顶点结点:data数据域,firstedge:与该顶点相连的第一条边
空间复杂度:O(|V|+|E|)
基本操作
图的基本操作:
-
Adjacent ( G , x , y ):判断图 G 是否存在边< x , y >或( x , y )。
-
Neighbors ( G , x ):列出图 G 中与结点 x 邻接的边
-
InsertVertex ( G , x ):在图 G 中插入顶点 x 。
-
DeleteVertex ( G , x ):从图 G 中删除顶点 x 。
-
AddEdge ( G , x , y ):若无向边( x , y )或有向边< x , y >不存在,则向图 G 中添加该边。
-
RemoveEdge ( G , x , y ):若无向边( x , y )或有向边< x , y >存在,则从图 G 中删除该边。
-
FirstNeighbor ( G , x ):求图 G 中顶点 x 的第一个邻接点,若有则返回顶点号。若 x 没有邻接点或图中不存在 x ,则返回﹣1
-
NextNeighbor ( G , x , y ):假设图 G 中顶点 y 是顶点 x 的一个邻接点,返回除 y 之外顶点 x 的下一个邻接点的顶点号,若 y 是 x 的最后一个邻接点,则返回﹣1。
-
Get _ edge _ value ( G , x , y ):获取图 G 中边( x , y )或< x , y >对应的权值。
-
Set _ edge _ value ( G , x , y , v ):设置图 G 中边( x , y )或< x , y >对应的权值为 v 。
图的遍历
广度优先遍历(代码会写)
-
找到与一个顶点相邻的所有顶点
-
标记那些定点被访问过
-
需要一个辅助队列:
-
FirstNeighbor ( G , x ):求图 G 中顶点 x 的第一个邻接点,若有则返回顶点号。若 x 没有邻接点或图中不存在 x ,则返回﹣1
-
NextNeighbor ( G , x , y ):假设图 G 中顶点 y 是顶点 x 的一个邻接点,返回除 y 之外顶点 x 的下一个邻接点的顶点号,若 y 是 x 的最后一个邻接点,则返回﹣1。
-
-
代码实现
bool visited [ MAX _ VERTEX _ NUM ]; //访问标记数组 void BFSTraverse ( Graph G ){//对图 G 进行广度优先遍历 for (i=0;i<G.vexnum;++i) visited[i]= FALSE; InitQueue (Q); for (i=0;i<G.vexnum;++i) if (!visited[i]) BFS ( G , i ); //访问标记数组初始化 //初始化辅助队列 Q //从0号顶点开始遍历 //对每个连通分量调用一次 BFS // vi 未访问过,从 vi 开始 BFS //广度优先遍历 void BFS (Graph G,int v){ //从顶点 v 出发,广度优先遍历图 G visit(v); //访问初始顶点 v visited[v]=TRUE; //对 v 做已访问标记 Enqueue(Q,v); //顶点 v 入队列 Q while(!isEmpty(Q)){ DeQueue(Q,v); //顶点 v 出队列 for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) //检测 v 所有邻接点 if(!visited[w]){ // w 为 v 的尚未访问的邻接顶点//问顶点 w visit(w); visited[w]=TRUE;//对 w 做已访问标记 EnQueue(Q,w);//顶点 w 入队列 }// if }// while }
深度优先遍历(代码会写)
bool visited [MAX_VERTEX_NUM]; //访问标记数组 void DFSTraverse(Graph G){ //对图 G 进行深度优先遍历 for(v=0;v<G.vexnum;++v) visited[v]=FALSE; //初始化已访问标记数据 for(v=0;v<G.vexnum;++v)//本代码中是从 v =0开始遍历 if(!visited[v]) DFS(G,v); } void DFS(Graph G,int v){ //从顶点 v 出发,深度优先遍历图 G visit(v); //访问顶点 v visited [v]=TRUE; //设已访问标记 for(w=FirstNeighbor(G,v);w>=0;w=NextNeighor(G,v,w)) if(!visited[w]){ // w 为 u 的尚未访问的邻接顶点 DFS(G,w); } // if }
时间复杂度:访问各节点所需的时间+探索各条边所需的时间
对无向图进行BFS/DFS遍历调用BFS/DFS函数的次数=连通分量数
对于连通图只需要调用一次。
最小生成树
连通图的生成树是包含全部顶点的一个极小连通子图。
对于一个带权连通无向图 G =( VE ),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设 R 为 G 的所有生成树的集合,若 T 为 R 中边的权值之和最小的生成树,则 I 称为 G 的最小生成树( Minimum - Spanning - Tree , MST )
-
最小生成树可能有多个,但边的权值之和总是唯一且最小的
-
最小生成树的边数=顶点数﹣1。砍掉一条则不连通,增加一条边则会出现回路
-
如果一个连通图本身就是一颗树,则其最小生成树就是它本身
-
只有连通图才有生成树,非连通图只有生成森林。
prim算法(选点)
时间复杂度:O(|V|^2),适用于稠密图
从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。
Kruskal算法(选边)
每次选择一条权值最小的边,使这两条边的两头联通(原本已经连通的就不选),直到所有结点都连通
时间复杂度:O(|E|log2|E|),适用于稀疏图。
最小路径问题
单源最短路径
-
BFS算法(无权图)
-
void BFS_MIN_Distance(Graph G,int u ){ for (i=0;i<G.vexnum;++i){ d[i]=∞; path[i]=-1; } d[u]=0; visited[u]=TRUE; EnQueue(Q,u); while(!isEmpty(Q)){ DeQueue(Q,v); //顶点 v 出队列 for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) if(!visited[w]){ // w 为 v 的尚未访问的邻接顶点//问顶点 w d[w]=d[u]+1; path[w]=u; visited[w]=TRUE;//对 w 做已访问标记 EnQueue(Q,w);//顶点 w 入队列 }// if }// while }
-
Dijkstra算法(带权图,无权图)不适用于带负权值的图
各顶点间的最短路径
-
Floyd算法(带权图,无权图)O(V^3)
有向无环图
AOV网
拓扑排序
-
从AOV网中选择一个没有前驱(入度为0)的顶点并输出。
-
从网中删除该顶点和所有以它为起点的有向边。
-
重复1和2直到当前的AOV网为空或当前网中不存在无前驱的顶点为止。
-
时间复杂度O(|V|+|E|),采用邻接矩阵需O(|V|^2)
逆拓扑排序
对一个AOV网,如果采用下列步骤进行排序,称之为逆拓扑排序:
-
从AOV网中选择一个没有后继(出度为0)的顶点并输出。
-
从网中删除该顶点和所有以它为终点的有向边。
-
重复1和2直到当前的AOV网为空。
AOE网
在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销,称之为用边表示的网络
只有一个入度为0的点(源点)
仅有一个出度为的顶点(汇点)
最大路径长度为关键路径