DS-6-图
2021-07-30 11:59:17 1 举报
AI智能生成
数据结构 第六章 图 知识点梳理
作者其他创作
大纲/内容
方法
基本操作
时间复杂度 <br>
邻接矩阵
邻接表
<font color="#7B1FA2"><font color="#388E3C">bool</font> Adjacent</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">i</font>, <font color="#388E3C">vNode*</font> <font color="#1976D2">j</font>) <br>
O(1)
O(1)~O(|V|)
<font color="#7B1FA2"><font color="#388E3C">UDG::vNode[]</font> Neighbors</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">i</font>) <br>
O(|V|)
O(1)~O(|V|)
<font color="#7B1FA2"><font color="#388E3C">DG::<font color="#388E3C">vNode[]</font></font> Neighbors</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">i</font>) <br>
O(|V|)
Out:O(1)~O(|V|)<br>In:O|E|<br>
<font color="#7B1FA2"><font color="#388E3C">bool</font> Insert</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">x</font>) <br>
O(1)
O(1) <br>
<font color="#7B1FA2"><font color="#388E3C">UDG::bool</font> Insert</font>(<font color="#388E3C">arcNode <font color="#1976D2">edge</font></font>) <br>
O(1)
O(1) <br>
<font color="#7B1FA2"><font color="#388E3C">DG::bool</font> Insert</font>(<font color="#388E3C">arcNode <font color="#1976D2">arc</font></font>) <br>
O(1)
O(1) <br>
<font color="#7B1FA2"><font color="#388E3C">UDG::bool</font> Delete</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">i</font>) <br>
O(|V|)
O(1)~O(|E|)
<font color="#7B1FA2"><font color="#388E3C">DG::bool</font> Delete</font>(<font color="#388E3C">vNode*</font> <font color="#1976D2">i</font>) <br>
O(|V|)
Out:O(1)~O(|V|)<br>In:O|E|<br>
<font color="#1976D2">weight</font>{<font color="#7B1FA2">get</font>; <font color="#7B1FA2">set</font>;} <br>
O(1)
O(1)~O(|V|)
遍历<br>
广度优先BFS
树的BFS=层序遍历:Compare
需要一个辅助队列
实现
设置一个辅助队列Q
设置数组isVisited[]标记访问过的顶点
<font color="#7B1FA2"><font color="#388E3C">Graph::void</font> BFS</font>()<br>
foreach (i in graph)<br>{isVisited[i]=false;}<br>
Q.Clear();
foreach (i in graph) <br>if(!isVisited[i])<br>
i.visit();<br>
isVisited[i]=true;
Q.Enque(i);
While (!Q.isEmpty)
foreach (w in head<br>.Neighbors())<br> if(!isVisited[w])<br>
w.visit();
isVisited[w]=true;
Q.Enque(w);
Q.Deque(head);
//单次只能遍历一个连通区域,非连通图需要利用isVisited[]寻找其他的非连通区域<br>
性能分析<br>
空间复杂度
worst(星型)<span class="equation-text" data-index="0" data-equation="O(|V|)" contenteditable="false"><span></span><span></span></span>,best(链表)<span class="equation-text" data-index="1" data-equation="O(1)" contenteditable="false"><span></span><span></span></span><br>
时间复杂度
邻接矩阵<span class="equation-text" data-index="0" data-equation="O(|V|^2)" contenteditable="false"><span></span><span></span></span>,邻接表<span class="equation-text" data-index="1" data-equation="O(|V|+|E|)" contenteditable="false"><span></span><span></span></span><br>
顶点visit()次数+边Neighbor()次数:思路<br>
BFS生成树
可以根据遍历过程构造一棵BFS生成树
用邻接表表示的图,不唯一
非连通图构造出的是BFS生成森林<br>
深度优先DFS
树的DFS=先根遍历:Compare
实现
设置数组isVisited[]标记访问过的顶点
<font color="#7B1FA2"><font color="#388E3C">Graph::void</font> DFS</font>()<br>
foreach (i in graph)<br>{isVisited[i]=false;}<br>
foreach (i in graph) <br>if(!isVisited[i])<br>
//单次只能遍历一个连通区域,非连通图需要利用isVisited[]寻找其他的非连通区域<br>
i.visit();<br>
isVisited[i]=true;
foreach (v in i.Neighbors())<br>if(!isVisited[v])<br>{<font color="#7B1FA2">DFS</font>(<font color="#1976D2">v</font>);}<br>
性能分析
空间复杂度(递归深度)
worst(链表)<span class="equation-text" data-index="0" data-equation="O(|V|)" contenteditable="false"><span></span><span></span></span>,best(星型)<span class="equation-text" data-index="1" data-equation="O(1)" contenteditable="false"><span></span><span></span></span><br>
时间复杂度
邻接矩阵<span class="equation-text" data-index="0" data-equation="O(|V|^2)" contenteditable="false"><span></span><span></span></span>,邻接表<span class="equation-text" data-index="1" data-equation="O(|V|+|E|)" contenteditable="false"><span></span><span></span></span><br>
顶点visit()次数+边Neighbor()次数:思路<br>
DFS生成树
可以根据遍历过程构造一棵DFS生成树
用邻接表表示的图,不唯一
非连通图构造出的是DFS生成森林<br>
遍历轮数
无向图
连通分量数
有向图
1次~强连通分量数
最小生成树MST<br>(最小代价)<br>
性质
生成树:V'=V,不存在回路,且连通的<font color="#F44336">无向图</font>
是图,不是树,不区分根结点
可能不唯一,且和权必相等
<font color="#D32F2F">若一个连通图已经是一棵树,则其MST是它本身</font>
Prim算法<br>选点<br>
从某个顶点开始构建<br>
选出将树中顶点连接的所有边中<br>代价最小的边所指向的新顶点<br>
将其纳入生成树,<br>直到所有顶点均纳入<br>
<span class="equation-text" data-index="0" data-equation="O(|V|^2)" contenteditable="false"><span></span><span></span></span>:时间复杂度
适用于<font color="#D32F2F">边</font>稠密图<br>
Kruskal算法<br>选边<br>
在所有边中每次选择一条权值最小的
如果边的两端点有未连通的<br>则连通此边,否则选择次小的<br>
重复,直到所有顶点均连通
<span class="equation-text" data-index="0" data-equation="O(|E|\log_2|E|)" contenteditable="false"><span></span><span></span></span>:时间复杂度
适用于<font color="#D32F2F">边</font>稀疏图<br>
判断是否连通需要了解“并查集”之概念
最短路径问题<br>
单源
BFS算法<font color="#F44336">(无权)</font><br>
执行一次BFS就可得到每一个顶点的最小距离<br>
需要d[],path[]保存该顶点的最短距离以及前驱顶点
d[],path[]分别初始化为∞、-1
可以通过BFS生成树直接得到d[],path[]
Dijkstra算法<font color="#F44336">(通用)</font>
需要final[],d[],path[]保存该顶点是否找到最小路径,最短路径长度以及前驱顶点
初始化<br>
final[] = self ? true : false;
dist[] = self ? 0 : (this.next ? next.dist : ∞);<br>
path[] = this.next ? 0 : ∞;<br>
while (final[*]==false)<br>
找到 final[i] = FALSE 的顶点中dist[i]最小的<br>设final[i]=true<br>
遍历该点所有后继j,<br>若其dist[j]>dist[i]+weight[i,j],<br>则令其dist[j]=dist[i]+weight[i,j],<br>并设path[j]=i,否则不操作<br>
性能分析
时间复杂度<span class="equation-text" data-index="0" data-equation="O(n^2)" contenteditable="false"><span></span><span></span></span>
双重循环
<font color="#F44336">存在负权值的图可能会导致算法失效:NOTE</font>
Dijkstra的成就
goto有害论:OS,虚拟存储技术<br>
信号量机制PV原语:OS,进程同步
银行家算法:OS,死锁<br>
解决哲学家进餐问题:OS,死锁
Dijkstra算法:DS
任意顶点对
Floyd算法<font color="#F44336">(通用)<br>动态规划算法</font><br>
计算不允许中转的距离矩阵<span class="equation-text" data-index="0" data-equation="A^{-1}" contenteditable="false"><span></span><span></span></span>
遍历全部顶点<br>
计算在顶点<span class="equation-text" data-index="0" data-equation="i" contenteditable="false"><span></span><span></span></span>中转的距离矩阵<span class="equation-text" data-index="1" data-equation="A^i" contenteditable="false"><span></span><span></span></span>
若经<span class="equation-text" data-index="0" data-equation="i" contenteditable="false"><span></span><span></span></span>中转距离小于当前距离,则将当前距离改为中转距离<br>并将path中对应位置改为i,以表明该路径经i中转最短<br>
空间复杂度<span class="equation-text" data-index="0" data-equation="O(n^2)" contenteditable="false"><span></span><span></span></span>,时间复杂度<span class="equation-text" data-index="1" data-equation="O(n^3)" contenteditable="false"><span></span><span></span></span>:性能分析<br>
寻找i到j路径时,若<span class="equation-text" data-index="0" data-equation="path[i][j]=k" contenteditable="false"><span></span><span></span></span>,表明该路径经k中转最短,化为递归问题
<font color="#F44336">允许负权值。但负权值边不能参与成环</font>
有向无环图(DAG)<br>描述表达式<br>
叶子结点必不重复
用于合并表达式的重复部分
bool Same(A,B);
if(A.op!=B.op) return false;<br>if(AB为叶子) return (A==B);<br>if(Same(A.lc,B.lc) 且 Same(A.rc,B.rc)) return true;<br>
for(左叶子→右叶子;叶子→根;){<br>if(Same(A,B)){B.parent.B=A; Free(B)}<br>}<br>
DAG拓扑排序<br>(AOV网)<br>
以DAG表示含有多个活动的工程,某些活动i必须先于活动j完成,以有向边<i,j>记之。<br>这种网络称为AOV网<br>
输出拓扑排序序列<br>序列是不唯一的<br>且序列的前后元素间<br>在原图中不总有弧<br>
选择一个入度为0(即无前驱)的结点并输出
删除(isVisit记录)他及以他为起点的有向边
重复以上步骤直到AOV网
为空:排序完成
不为空且不存在无前驱顶点:排序失败,有回路
需要遍历出边,考察不同数据结构的特性:性能分析<br>
反向输出,从出度为0的开始,操作类似:逆拓扑排序
关键路径<br>(AOE网)<br>
以边表示活动,顶点表示“活动已完成”的事件
性质<br>
只有顶点代表的事件发生后,从顶点出发的边代表的活动才能开始
只有顶点入边事件全部完成后,从顶点代表的事件才能发生
关键路径
具有最大长度的路径
完成工程的最短时间
关键活动
决定完成工程的最短时间的边
成员
事件<span class="equation-text" data-index="0" data-equation="v_k" contenteditable="false"><span></span><span></span></span>发生的最早时间<span class="equation-text" data-index="1" data-equation="ve(k)" contenteditable="false"><span></span><span></span></span><br>
不影响工期的情况下,事件<span class="equation-text" data-index="0" data-equation="v_k" contenteditable="false"><span></span><span></span></span>发生的最迟时间<span class="equation-text" data-index="1" data-equation="vl(k)" contenteditable="false"><span></span><span></span></span><br>
活动<span class="equation-text" data-index="0" data-equation="a_i" contenteditable="false"><span></span><span></span></span>开始的最早时间<span class="equation-text" data-index="1" data-equation="e(i)" contenteditable="false"><span></span><span></span></span>
该弧终点的事件最迟发生的事件与该活动所需时间的差额:活动<span class="equation-text" data-index="0" data-equation="a_i" contenteditable="false"><span></span><span></span></span>开始的最迟时间<span class="equation-text" data-index="1" data-equation="l(i)" contenteditable="false"><span></span><span></span></span>
<span class="equation-text" data-index="0" data-equation="d(i)=l(i)-e(i)" contenteditable="false"><span></span><span></span></span>:时间余量<span class="equation-text" data-index="1" data-equation="d(i)" contenteditable="false"><span></span><span></span></span><br>
方法<br>
求<span class="equation-text" data-index="0" data-equation="ve(k),e(i),vl(k),l(i)" contenteditable="false"><span></span><span></span></span>
<br>
概念与性质<br>
定义
包含顶点集V和边集E组成一个图G
任意一条边必须连接两个顶点,且是V中的顶点
V不能为空,但是E可以为<span class="equation-text" data-index="0" data-equation="\empty" contenteditable="false"><span></span><span></span></span>
分类
按边种类
有向图
边称为有向边,也称弧
弧头:弧终点
弧尾:弧始点
无向图
边称为无向边,简称边
按连接方式
简单图
不存在重复边
不存在顶点到其自身的边
多重图
无向/有向完全图:任意两个顶点均存在边/双向的两条弧
有<span class="equation-text" data-index="0" data-equation="C_n^2" contenteditable="false"><span></span><span></span></span>条边或<span class="equation-text" data-index="1" data-equation="2C_n^2" contenteditable="false"><span></span><span></span></span>条弧
按连通性
连通图:任意一对顶点连通
至少具有<span class="equation-text" data-index="0" data-equation="n-1" contenteditable="false"><span></span><span></span></span>条边
强连通图:任意一对顶点均强连通
至少<span class="equation-text" data-index="0" data-equation="n" contenteditable="false"><span></span><span></span></span>条边(形成回路)<br>
非连通图:存在顶点与其他顶点不连通
最多有<span class="equation-text" data-index="0" data-equation="C_{n-1}^2" contenteditable="false"><span></span><span></span></span>条边<br>
按边数<br>
稀疏图:边少
稠密图:边多
成员
度D:连接顶点的边数<br>(有向图TD(v)=ID<font color="#B71C1C"><b>+</b></font>OD)<br>
入度ID(v):以顶点v为终点
出度OD(v):以顶点v为起点
<span class="equation-text" data-index="0" data-equation="\sum TD(v_i)=2|E|" contenteditable="false"><span></span><span></span></span><br>
路径<br>
顶点<span class="equation-text" data-index="0" data-equation="v_p" contenteditable="false"><span></span><span></span></span>到<span class="equation-text" data-index="1" data-equation="v_q" contenteditable="false"><span></span><span></span></span>的顶点序列(含端)(不唯一)
有向图中路径必须遵循弧的方向
回路/环:两端相同的路径
简单路径:除了端点外,其余顶点不重复
长度:路径上边的数目
距离:两个顶点最短路径的长度,不存在则为<span class="equation-text" data-index="0" data-equation="\infin" contenteditable="false"><span></span><span></span></span><br>
子图
取出V和E的子集V',E',能构成一个图G',则,G'是G的子图<br>
生成子图:当V'=V
生成树:连通且不存在回路的<font color="#F44336">无向图</font>
有向树:1个顶点ID=0,其余ID=1的<font color="#F44336">有向图<font color="#000000">(非强连通)</font></font><br>
强连通分量<br>(有向图)<br>
极大强连通子图
必须强连通
包含尽可能多的顶点
包含尽可能多的边
有向图中的极大强连通子图称强连通分量(不唯一)
连通分量<br>(无向图)
极大连通子图
必须连通
包含尽可能多的顶点
包含尽可能多的边
无向图中的极大连通子图称连通分量
生成树
包含全部顶点的一个极小连通子图
不是树,不区分根节点
生成树:V'=V,不存在回路,且连通的<font color="#F44336">无向图</font>
包含n-1条边
加边必成回路
减边必非连通
最小生成树MST:在带权的图中才有MST
有向树:1个顶点ID=0,其余ID=1的<font color="#F44336">有向图</font><br>
拓扑序列<br>(有向无环图)<br>
派生
带权图/网:每条边带权
带权路径长度:路径上的权之和
DAG图<br>
AOV网:(Activity on Vertices)
AOE网:(Activity on Edges)
存储
邻接矩阵
无向图
有向图
带权图(自定义方式表示<span class="equation-text" data-index="0" data-equation="\infin" contenteditable="false"><span></span><span></span></span>)
空间复杂度<span class="equation-text" data-index="0" data-equation="O(n^2)" contenteditable="false"><span></span><span></span></span><br><font color="#D32F2F">太高!</font><br>
适合稠密图<br>
边数=2|E|<br>
可以应用对称矩阵压缩
约定:元素代表的边方向均为行号<span class="equation-text" data-index="0" data-equation="\rightarrow" contenteditable="false"><span></span><span></span></span>列号
对于不带权的图,<span class="equation-text" data-index="0" data-equation="A^n[i][j]=(A^n)[i][j]" contenteditable="false"><span></span><span></span></span>,可表示顶点<span class="equation-text" data-index="1" data-equation="v_i" contenteditable="false"><span></span><span></span></span>到顶点<span class="equation-text" data-index="2" data-equation="v_j" contenteditable="false"><span></span><span></span></span>长度为<span class="equation-text" data-index="3" data-equation="n" contenteditable="false"><span></span><span></span></span>的路径数
方法
求入度:时间复杂度O(n)<br>求出度:时间复杂度O(n)<br>
删边
方便
删结点
大量移动数据
邻接表<br>(不唯一)<br>
结构
typedef {Sqlist<vNode<T>> vertices, int vexNum, int arcNum} map<T><br>
typedef {T data, ArcNode* firstArc} vNode<T>
typedef {int tailVertex, ArcNode* nextArc} ArcNode<br>
无向图:边数=2|E|,空间复杂度O(|V|+2|E|)<br>有向图:边数=|E|,空间复杂度O(|V|+|E|)<br>
适合稀疏图
方法
求出度:O(n)
求入度:O(|V||E|) <font color="#D32F2F">太高!</font><br>
删结点/边:极为不便
派生:逆邻接表
十字链表<br>有向图<br>
结构<br>
typedef {<font color="#388E3C">Sqlist</font><<font color="#388E3C">vNode</font><<font color="#F57C00">T</font>>> <font color="#1976D2">vertices</font>, <font color="#388E3C">int</font> <font color="#1976D2">vexNum</font>, <font color="#388E3C">int</font> <font color="#1976D2">arcNum</font>} <font color="#388E3C">map</font><<font color="#F57C00">T</font>>
typedef {<font color="#F57C00">T</font> <font color="#1976D2">data</font>, <font color="#388E3C">ArcNode*</font> <font color="#1976D2">firstInArc</font>, <font color="#388E3C">ArcNode*</font> <font color="#1976D2">firstOutArc</font>} <font color="#388E3C">vNode</font><<font color="#F57C00">T</font>>
typedef {<font color="#388E3C">int</font> <font color="#1976D2">tailVex</font>, <font color="#388E3C">int</font> <font color="#1976D2">headVex</font>, <font color="#388E3C">float</font> <font color="#1976D2">weight</font>, <font color="#388E3C">ArcNode*</font> <font color="#1976D2">nextArcCohead</font>, <font color="#388E3C"><br>ArcNode*</font> <font color="#1976D2">nextArcCotail</font>} <font color="#388E3C">ArcNode</font><br>
空间复杂度O(|V|+|E|)
方法<br>
求出度:
找到firstOutArc指针指向的弧,再按其nextArcCotail指针寻找
求入度:<br>
找到firstInArc指针指向的弧,再按其nextArcCohead指针寻找
邻接多重表<br>无向图<br>
结构<br>
typedef {<font color="#388E3C">Sqlist</font><<font color="#388E3C">vNode</font><<font color="#F57C00">T</font>>> <font color="#1976D2">vertices</font>, <font color="#388E3C">int</font> <font color="#1976D2">vexNum</font>, <font color="#388E3C">int</font> <font color="#1976D2">arcNum</font>} <font color="#388E3C">map</font><<font color="#F57C00">T</font>>
typedef {<font color="#F57C00">T</font> <font color="#1976D2">data</font>, <font color="#388E3C">ArcNode*</font> <font color="#1976D2">firstEdge</font>} <font color="#388E3C">vNode</font><<font color="#F57C00">T</font>>
typedef {<font color="#388E3C">int</font> <font color="#1976D2">iVex</font>, <font color="#388E3C">int</font> <font color="#1976D2">jVex</font>, <font color="#388E3C">float</font> <font color="#1976D2">weight</font>, <font color="#388E3C">ArcNode*</font> <font color="#1976D2">nextEdgeCo_i</font>, <font color="#388E3C"><br>ArcNode*</font> <font color="#1976D2">nextEdgeCo_j</font>} <font color="#388E3C">ArcNode</font><br>
//注 i,j相同,顺序不同的边是同一条边。<br>
空间复杂度O(|V|+|E|)
方法<br>
删除结点i
删除结点i,删除i指向的边,逐次删除边的共i指针指向的边
0 条评论
下一页