6-图

1.基本概念

图不能为空
图G由顶点集V和边集E组成,G=(V,E),其中V(G)表示图G中顶点的有限非空集,E(G)表示图G中顶点之间的关系集合
例:V={A,B,C,D,E}; E={(A,B),(A,C),(A,E),(B,C),(C,D),(C,E)}
|V|表示图中顶点的个数。|E|表示图中边的条数

1.1 图的表示

1)无向图
没有方向,(v,w)=(w,v),v,w互为邻接点

  • 连通:若顶点v到顶点w有路径存在,则称v和w是连通的
  • 连通图:任意两个结点之间都是连通的,最少有n-1条边
  • 连通分量(极大连通子图):对于G的一个连通子图G’,若不存在另一个连通子图G’’,使得G’∈G’'则称G’是G的连通分量
  • 极小连通子图:连通子图且包含的边最少
  • 生成树:连通图包含全部顶点的一个极小连通子图
  • 生成森林:非连通图所有连通分量的生成树组成生成森林
  • ** 顶点的度:**以v为端点的边的个数,记为TD(V),n顶点,e条边的无向图中度的总数为
    ∑ i = 1 n T D ( V i ) = 2 e \sum_{i=1}^nTD(V_i)=2e i=1nTD(Vi)=2e

2)有向图
有方向的边,弧尾(v)、弧头(w)<v,w>v邻接到w,或w邻接自v

  • 强连通:若顶点v到顶点w有路径存在且w到v也存在路径,则称v和w是强连通的
  • 强连通图:任意两个结点之间都是强连通的,最少n条边
  • 强连通分量(极大强连通子图):对于G的一个强连通子图G’,若不存在另一个强连通子图G’’,使得G’∈G’'则称G’是G的强连通分量
  • 出度:以v为起点的有向边的条数,记为OD(v);
  • 入度:以v为终点的有向边的条数,记为ID(v)
  • **顶点的度:**为出度与入度的和n顶点,e条边的无向图中度的总数为
    ∑ i = 1 n T D ( V i ) = e \sum_{i=1}^nTD(V_i)=e i=1nTD(Vi)=e

3)简单图
无重复边,不存在结点到自身的边
4)多重图
有重复边或存在结点到自身的边
5)完全图
a)无向完全图:任意两个顶点都存在边,n个顶点有n(n-1)/2条边
b)有向完全图:任意两个顶点之间都存在方向相反的弧n(n-1)条边
6)子图:若图G=(V,E),图G’=(V’,E’)且V’是V的子集,E’是E的子集,则称G’是G的子图,且当V(G)=V(G’)时,称G’为G的生成子图,原图也可称为子图
7)网:带权重的图
8)稠密图与稀疏图
9)有向树:一个顶点的入度为0,其余顶点的入度均为1的有向图

2.存储及操作

2.1邻接矩阵法

行号表示弧尾,列号表示弧头

#define MaxVertexNum 100
typedef char VertexType;
typedef int EdgeType;
typedef struct {
    VertexType Vex[MaxVertexNum];//一维数组存放顶点
    EdgeType Edge[MaxVertexNum][MaxVertexNum];//二维数组存放边
    int vexnum,arcnum;
}MGraph;

性质
1)邻接矩阵的空间复杂度为O(n^2),适用于稠密图
2)无向图的邻接矩阵为对称矩阵;
3)无向图中第i行(或第i列)非0元素(非正无穷)的个数为第i个顶点的度;
4)有向图中第i行(或第i列)非0元素(非正无穷)的个数为第i个顶点的出度(入度);
5 ) A n [ i ] [ j ] 表 示 从 顶 点 V i 到 顶 点 V j 长 度 为 n 的 路 径 条 数 5) A^n[i][j]表示从顶点V_i到顶点V_j长度为n的路径条数 5)An[i][j]ViVjn

2.2邻接表法

为每一个顶点建立一个单链表存放与它相邻的边
顶点表:采用顺序存储,每个数据元素存放顶点的数据和边表的指针
边表(出边表):采用链式存储,单链表存放与一个顶点相邻的所有边,一个链表结点表示一条从该顶点到链表结点顶点的边

#define MaxVertexNum 100
typedef struct 
{
    int adjvex;
    struct ArcNode *next;
    //权重InfoType info;
}ArcNode;//边表结点
typedef struct VNode{
    VertexType data;
    ArcNode *first;
}VNode, AdjList[MaxVertexNum];//顶点表
typedef struct {
    AdjList vetics;
    int vexnum,arcnum;
}AlGraph;//邻接表

邻接矩阵 VS 邻接表
稠密图 适用性 稀疏图
顺序存储 存储方式 顺序存储+链式存储
效率高 判断顶点间存在边 效率低
效率低 找出某顶点相邻的边 效率高

2.3十字链表法

有向图的一种链式存储结构

#define MaxVertexNum 100
typedef struct 
{
    int tailvex,headvex;
    struct ArcNode *hlink,*tlink;
    //权重InfoType info;
}ArcNode;//边表结点
typedef struct VNode{
    VertexType data;
    ArcNode *firstin,*firstout;
}VNode;//顶点表
typedef struct {
    VNode slist[MaxVertexNum];
    int vexnum,arcnum;
}GlGraph;//十字链表

2.4邻接多重表

无向图的一种链式存储结构

#define MaxVertexNum 100
typedef struct 
{
    int ivex,jvex;
    struct ArcNode *ilink,*jlink;
    //权重InfoType info;
    //标记bool mark;
}ArcNode;//边表结点
typedef struct VNode{
    VertexType data;
    ArcNode *firstedge;
}VNode;//顶点表
typedef struct {
    VNode adjmulist[MaxVertexNum];
    int vexnum,arcnum;
}AlGraph;//邻接多重表

十字链表 VS 邻接多重表
链式存储结构
有向图 无向图
顶点/边表结点 顶点/边表结点

2.5图的基本操作

Adjacent(G,x,y):判断图G是否存在边<x,y>或(x,y);
Neighbor(G,x):列出图G中与结点x相邻的边;
InsertVertex(G,x):在图中插入顶点x;
DeleteVertex(G,x):在图G中删除顶点x;
AddEdge(G,x,y):若有向边<x,y>或无向边(x,y)不存在,则在图G中创建该边;
RemoveEdge(G,x,y):若有向边<x,y>或无向边(x,y)存在,则在图G中删除该边;

3.图的遍历

从图中某一顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点访问一次且仅访问一次

3.1广度优先搜索(BFS算法)

  • 访问起始顶点v;
  • 由出发依此访问v各个未被访问的邻接顶点W1,W2…;
  • 然后依此访问W1,W2的所有未被访问的邻接顶点…;
bool visited[Max_Tree_Size];
void BFSTraverse(Graph G){
    for (int i=0;i<G.vexnum;++i)
        visited[i]=FALSE;
    InitQueue(Q);
    for (int i;i<G.vexnum;++i)
        if(!visited[i])
            BFS(G,i);
}
void BFS(Graph G,int v){
    visit (v);
    visit [v]=True;
    EnQueue(Q,v);
    while(!isEmpty(Q)){
        DeQueue(Q,v);
        for (w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
            if(!visited[w]){
                visit(w);
                visited[w]=TRUE;
                EnQueue(Q,w);

            }
    }
}
3.1.1无权图单源最短路径问题
3.1.2广度优先生成树

邻接矩阵法的广度优先生成树唯一,邻接表法的不唯一

3.2深度优先搜索(DFS)

  • 访问起始顶点v;
  • 由v出发依访问v的任意一个邻接且未被访问的邻接顶点W…;
  • 然后再访问W邻接且未被访问的邻接顶点y…;
  • 若W没有邻接且未被访问的邻接顶点,退回它的上一层顶点v;
  bool visited[Max_Tree_Size];
  void BFSTraverse(Graph G){
    for (int i=0;i<G.vexnum;++i)
        visited[i]=FALSE;
    for (int i;i<G.vexnum;++i)
        if(!visited[i])
            DFS(G,i);
  }
  void DFS(Graph G,int v){
    visit (v);
    visited[v]=True;
    for (w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
  	if(!visited[w])
  		DFS(G,w)
  }

邻接矩阵的DFS序列唯一,邻接表法的不唯一

3.3遍历与连通性

在无向图中,在任意结点出发进行一次遍历(调用一次BFS或DFS时),若能访问全部结点,说明无向图是连通的
在无向图中,调用遍历函数(BFS或DFS)的次数为连通分量的个数

4图的应用

4.1最小生成树

生成树:连通图包含全部顶点的一个极小连通子图
最小生成树:对于带权无向连通图G,G的所有生成树当中边的权值之和最小的生成树
性质:

  • 最小生成树的树型不一定唯一:当带权无向连通图G的各边权值不等或G中只有结点数-1条边时,唯一;
  • 最小生成树的权值唯一,且最小;
  • 最小生成树的边数为顶点数-1;
4.1.1

贪心算法(考研不做考察):

//伪代码
void GenRtc_MST(G){
	T=NULL;
	while T 未形成一棵树;
		do 找到一条最小代价边(u,v)并且加入T后不会产生回路;
		T=T∪(u,v);
}
4.1.2 Prim(普里姆)算法

从某一顶点开始查找最小的权值

//伪代码
void Prim(G,T){
	T=φ;//初始化空树
	U={w}; //添加任意顶点w
	while ( (V-U) !=(空集){//若树中不含全部顶点
		设(u,v)是使u∈U与v∈(V-U),且权值最小的边;
		T=T∪{(u,v)};//边归入树
		U=U∪{v};//顶点归入树
	}
}

时间复杂度O=V^2即顶点的2次方,稠密图

4.1.3Kruskal(克鲁斯卡尔)算法

在所有边中挑出最小的一条边,重复

//伪代码
void Kruskal(V,T){
	T=V;
	numS=n;
	while(num>1){
		从E中选取权值最小的边(v,u);
		if (v和u属于T中不同的连通分量){
			T=T∪{(V,u)};
			numS--;
		}
	}
}

时间复杂度:O=E * log_2E 稀疏图

4.2最短路径–Dijkstra算法

4.3拓扑排序

4.3.1有向无环图

若一个有向图中不存在环,则称为有向无环图,简称 DAG 图 。

4.3.2 AOV网

有向无环图,表示一个工程,顶点表示活动

4.3.3拓扑排序

在图论中,由一个有向无环图的顶点组成的序列, 当且仅当满足下列条件时,称为该图的一个拓扑排序:

  • 每个顶点出现且只出现一次;
  • 若顶点 A 在序列中排在顶点 B 的前面,则在图中不存在从顶点 B 到顶点 A 的路径
    每个AOV网可能有一个或多个拓扑序列

4.4关键路径

AOE网(顶点表示事件,有向边表示活动,以边上的权值表示完成该活动的开销)

  • 只有在顶点代表的时间发生后,从顶点出发的各有向边所代表的活动才能开始;
  • 只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生,另外有些活动可以并行进行的;

AOE的网只有1个入度为0的顶点称为开始顶点(源点),只有0个出度的顶点称为结束顶点(汇点),从源点到汇点的最大路径长度称为关键路径,路径上的活动称为关键活动。关键路径长度即工程完成的最短时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值