【克鲁斯卡尔算法描述】设无向网络N=(v(n),E(n)),待求得最小生成树为T=(V(T),E(T))。
1.初始化:后继数组parent(N)全都置为零(目的是用于算法中判断节点间是否形成回路)
2.从E(N)中选取一条权值最小的边(v,u),快速排序后此时应为E(1),假若当其加入E(T)后使得T不构成回路,即先找到v,u各自的后继,如果不相等,则将(v,u)并入E(T),同时更新网络中顶点的后继,否则舍掉该边,将决策过的(v,u)从E(N)中删掉。
3.重复步骤2(即循环遍历E(N)),直到网络中任意两节点是相通的,此时E(T)中正好有N-1条边。
#include<stdio.h>
#define MAXVER 50
#define MAXEDGE 200
typedef struct edgeNode
{
int begin; // 起点
int weight; // 权值
int end; // 末点
} edgeNode;
//快速排序
int Partition(edgeNode E[],int low,int high)
{
edgeNode u=E[low];//指定参考值u大小
while(low<high)
{
//从后往前搜比u小的元素,找到后跳出循环
while(low<high&&E[high].weight>=u.weight)
{
high--;
}
if(low<high)//并填充E[low],同时low向后移动
{
E[low]=E[high];
low++;
}
//从前往后搜比u大的元素,找到后跳出循环
while(low<high&&E[low].weight<u.weight)
{
low++;
}
if(low<high)//并填充到E[high],同时high向前移动
{
E[high]=E[low];
high--;
}
}
E[low]=u;//保存分界点,当low和high相等时,此时u为分界点,u左边是比其小的元素,右边是比起大的元素
//返回分界点u的位置low
return low;
}
void QuickSort(edgeNode E[],int low,int high)
{
int i;
if(low<high)//停止排序的条件依旧是找到了分界点位置,即low和high相等
{
i=Partition(E,low,high);
QuickSort(E,low,i-1);//分治的思想进行各自的排序
QuickSort(E,i+1,high);
}
}
void CreatGraph(edgeNode E[],int &vexs,int &edges)//创建无向网络
{
printf("please input vertexs and edges:\n");
scanf("%d %d",&vexs,&edges);
setbuf(stdin,NULL);
for(int i=1;i<=edges;i++)
{
printf("please input NO.%d begin,end and weight:\n",i);
scanf("%d %d %d",&E[i].begin,&E[i].end,&E[i].weight);
setbuf(stdin,NULL);
}
printf("\n");
}
int Find(int *parent, int f)//用于找到顶点的后继
{
while (parent[f] > 0)
f = parent[f];
return f;
}
void MiniSpanTree_Kruskal(edgeNode E[],int vernum,int edgenum)
{
int i = 1, n = 0, m = 0;
int parent[MAXVER];//作用仅仅是判断两节点是否回路
for ( ; i < vernum; ++i)//初始化后继
parent[i] = 0;
for (i = 1; i <=edgenum; ++i)//遍历所有的边,找到权重和最小的边
{
n = Find(parent, E[i].begin);//通过节点的后继判断是否形成回路,同时剔除已形成回路的边
m = Find(parent, E[i].end);
if (n != m)//如果各自后继不相等,表明该两节点不联通,
{
parent[n] = m;//更新网络中节点的后继
printf("%d,%d,%d\n",E[i].begin,E[i].end,E[i].weight);
}
}
}
int main()
{
edgeNode E[MAXEDGE];
int vernum,edgenum;
CreatGraph(E,vernum,edgenum);//创建无向网络
QuickSort(E,1,edgenum);//快速排序所有的边
MiniSpanTree_Kruskal(E,vernum,edgenum);
return 0;
}
【小结】
1.克鲁斯卡尔算法的运算量取决于无向网络的边数,时间复杂度为O(edgenum),因此它适用于稀疏网求最小生成树
2.快速排序算法的时间复杂度为O(nlog2n),空间复杂度取决于递归深度