1.问题
举一个实例,画出采用Kruskal算法构造最小生成树的过程,并按实验报告模板编写算法。
2.解析
克鲁斯卡尔算法的基本思想是以边为主导地位,始终选择当前可用(所选的边不能构成回路)的最小权植边。所以Kruskal算法的第一步是给所有的边按照从小到大的顺序排序。这一步可以直接使用库函数qsort或者sort。接下来从小到大依次考察每一条边(u,v)。
具体实现过程如下:
<1> 设一个有n个顶点的连通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T={V,空},图中每个顶点自成一格连通分量。
<2> 在E中选择一条具有最小权植的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点落到同一连通分量 上,则将此边舍去(此后永不选用这条边),重新选择一条权植最小的边。
<3> 如此重复下去,直到所有顶点在同一连通分量上为止。
3.设计
[核心伪代码]
// 把所有边排序,记第i小的边为e[i] (1<=i<=m)m为边的个数
// 初始化最小生成树为空
// 初始化连通分量,使每个点各自成为一个独立的连通分量
for (int i = 0; i < m; i++)
{
if (e[i].u和e[i].v不在同一连通分量)
{
// 把边e[i]加入最小生成树
// 合并e[i].u和e[i].v所在的连通分量
}
}
4.分析
[算法复杂度推导]
1、初始化生成树的边集A为空集:O(1)
2、对集合中的每一个顶点,都将它的集合初始化为自身:O(V)
4、将边按权值进行排序:O(ElogE)
5、对排序好后的边从小到大进行判断,如果这条边所连的2个顶点不在同一个集合中,则将这条边加入到生成树的边集A中,并将此边所连的两个顶点u和v的集合做一个联合操作,如此循环加到生成树中的边集数量为n-1时停止:O(V+E)
6、所以克鲁斯卡尔算法的算法复杂度为
O(E * log(V))
以上为克鲁斯卡尔算法
以下是prim算法
1.问题
[描述算法问题,首选形式化方式(数学语言),其次才是非形式化方式(日常语言)]
举一个实例,画出采用Prim算法构造最小生成树的过程,并按实验报告模板编写算法。
2.解析
[问题的理解和推导,可用电子版直接在此编写,也可用纸笔推导,拍照嵌入本文档]
已知图V={…},用Prim算法构造一个最小生成树T
第一步:随意选取起点
第二步:在前一步的基础上寻找最小权值
第三部:继续寻找最小权值,之后以此类推,直到遍历完所有的节点
实例:
图V如下所示
(1)任意选中一个点,这里我选中V1点
与V1有边相连的是V2,V3和V4,边的权值分别是3,5,3
选择权值最小的边,我们这里选择的是V1-V2
(2)V1与V4相连,V2与V3相连,权值分别为3和4
所以选择V1-V4
(3)V3与V2,V1相连,权值分别为4,5,V3-V2(4) V3-V1(5)
V5与V4相连, 权值为7 V5-V4(7)
所以选择V3-V2(4)
(4)V5与V3有边,V5与V4有边 V5-V3(3) V5-V4(7)
所以选择V5-V3(3)
至此该图的最小生成树就已经构造好了。
3.设计
[核心伪代码]
void MinPrimTree(Graph *G){
将V0点直接放进最小生成树;
for(int i = 1;itotalNum;i++){
将各边与Vk点之间的权值都赋值给数组weight[];//k的初始值为0;
将与Vk点有边相连的点存在Adjvex[]数组中;
}
for(int i=1;itotalNum;i++){
int j=1;
While(jtotalNum){
if(weight[i]!=0 && weight[i]<Min){
Min = wight[i];
更换新的起始点;
}
}
j++;
打印边和权值信息;
for(int i=1;itotalNum;i++){
更新新的节点和其他节点的最小权值和关联关系。
}
}
}
4.分析
[算法复杂度推导]
n次
n次
n次
1次
n次
T(n)=n+n*(n+1+n)
=n+2*n^2+n
=O(n^2)
GitHub地址
https://github.com/henryzhang6686/myAlgorithmCode