最小生成树
生成树概念:
一个连通图的生成树是一个极小连通子图,它含有图中全部n个顶点和构成一棵树的(n-1)条边。
可以通过遍历方法产生生成树:
- 由深度优先遍历得到的生成树称为深度优先生成树。
- 由广度优先遍历得到的生成树称为广度优先生成树。
最小生成树概念:
- 对于带权连通图G (每 条边上的权均为大于零的实数),可能有多棵不同生成树。
- 每棵生 成树的所有边的权值之和可能不同。
- 其中权值之和最小的生成树称为图的最小生成树。
普里姆(Pim)算法
用普里姆(Pim)算法构造过程:
(1)初始化U={v}。v到其他顶点的所有边为候选边;
(2) 重复以下步骤n-1次,使得其他n-1个顶点被加入到U中:
➊从候选边中挑选权值最小的边输出,设该边在V-U中的顶点是k,将
k加入U中;
❷考察当前V-U中的所有顶点,修改候选边:若(, k)的权值小于原来
和顶点k关联的候选边,则用(k, j)取代后者作为候选边。
算法演示:
。。。。。。。。
从上面的流程我们可以知道:先将出发点0存在一个集合U,然后其余的存在另一个集合V-U,然后在这两个集合中选择一条最小边添加到T中,然后依次操作直到U中包含所以顶点。
这里算法就不给出来,但要知道的是改算法中有两重for循环, 所以时间复杂度为O(n²)。该算法的执行时间与图中边e无关,所以它适合于稠密图求最小生成树。
克鲁斯卡尔(Kruskal)算法
克鲁斯卡尔(Kruskal)算法是按权值的递增次序选择合适的边来构造最小生成树的方法。
算法构造过程:
(1)置U的初值等于V (即包含有G中的全部顶点), TE的初值为
空集(即图T中每一个顶点都构成一个连通分量)。
(2)将图G中的边按权值从小到大的顺序依次选取:
➊若选取的边未使生成树T形成回路,则加入TE;
❷否则舍弃,直到TE中包含(n-1)条边为止。
算法演示:
。。。。。。。。
到第5号边时出现回路,则抛弃它,再判断第6号边
。。。。。。。。
从以上的流程我们可以知道:先将图中所有边按权值递增排序,T中包含所以顶点,然后依次选择最小边加入T中,每次加入时判断是否形成回路,若形成回路则从比它小一级的再开始遍历。
上述算法不是最优的。改进:堆排序、并查集
改进后Kruskal算法的时间复杂度为O(elog2e)。可以看出Kruskal算法执行时间与图中的边e有关,所以该算法适用于稀疏图求最小生成树。
最短路径
路径的概念:考虑带权有向图,把一条路径(仅仅考虑简单路径)上 所经边的权值之和定义为该路径的路径长度或称带权路径长度。
路径长度=c1+c2+…+cm
路径:(v,v1,v2,…,u)
从源点到终点可能不止一条路径,把路径长度最短的那条路径称为最短路径。
狄克斯特拉(Dijkstra)算法
该算法计算的是一个顶点到其余顶点的最短路径。
算法构造过程:
第1组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径v,… ,u,就将u加入到集合S中,直到全部顶点都加入到S中,算法就结束了)。
第2组为其余未求出最短路径的顶点集合(用U表示)。
算法演示:
首先将开始顶点放入S集合,其余顶点放在集合U中,dist[] 用于存储初始顶点0所有顶点最短权值,path[]用于存放顶点i到j的最短路径上顶点j的前一个顶点的编号。
我们通过流程图可以分析到:顶点0到顶点1的距离最短,所以将顶点1,放入集合S。然后将顶点1作为判断点,可以发现顶点1离顶点2最近,所以将顶点1,放入集合S,修改path中与顶点1有边的顶点2,4,将值修改为1;同理得到以下数据。
利用dist和path求最短路径长度和最短路径:
Dijkstra算法的时间复杂度为O(n²)。
弗洛伊德(Floyd)算法
该算法计算的是每对顶点之间的最短路径。
算法构造过程:
假设有向图G=(V, E)采用邻接矩阵存储。设置一个二维数组A用于存放当前顶点之间的最短路径长度,分量A[i][]表示当前顶点i中j的最短路径长度。
递推产生一个矩形序列:
A0,A1。。。An-1
Ak[i][j]:i到j的路径上所经过的顶点编号不大于k的最短路径长度。
- 0初始时,有AIilj]=g.edges[i][j]。
- 考虑从i到j的最短路径经过编号为k顶点的情况:
算法遍历:
。。。。。。。。
(1) 用二维数组A存储最短路径长度:
●Ak[i][j]表示考虑顶点0~k后得出的i到j的最短路径长度。
●An-1[i][j]表示最终的i到j的最短路径长度。
(2)用二维数组path存放最短路径:
●path k[i][j]表示考虑顶点0~k后得出的i到j的最短路径。
●path n-1[i][j]表示最终i到j的最短路径。
●path n-1[i][j]的值为j的前一个顶点。
从上述遍历我们可以看到:
初始时path-1就是该图邻接矩阵的表示,然后考虑顶点0,A0[i][j]表示最终的i到j经0的最短路径长度。经过比较没有任何路径上得到修改(即考虑顶点0时,不存在最短路径了)。
考虑顶点1,0到2由原来没有路径变成0-1-2,长度为9,所以A1[0][2]修改为9,path1[0][2]由-1修改为1
。。。
考虑顶点3,0-2由原来最短长度9,路径为0-1-2,但此时有一条更短的路径:0-3-2,长度为8。所以修改A3[0][2]为8,path3[0][2]由1改为3,依次推下去,得到所有结果
➊求最短路径长度:
由A3数组可以直接得到两个顶点之间的最短路径长度。
如A3[1][0]=6,说明顶点1到0的最短路径长度为6。
❷求最短路径:
求顶点1到0的最短路径:
path3[1][0]=2
path3[1][2]=3
path3[1][3]=1
顶点序列为0、2、3、1,则顶点1到0的最短路径为1-→3-→2-→0。
最后该算法的时间复杂度为O(n³)。