生成树:包含图中全部n个顶点的极小连通子图,包含n-1条边且没有环
Prim
-稠密图O(E^2)
-类似Dijkstra
-用邻接矩阵存图 邻接表存树
(图结点、边结点、邻接表、邻接矩阵的定义见前)
找未被收录顶点中dist最小者
Vertex FindMinDist(MGraph Graph, WeightType dist[])
{
Vertex MinV, V;
WeightType MinDist = INFINITY; //INFINITY表示不联通
for(V = 0; V<Graph->Nv; V++) {
if(dist[V]!=0 && dist[V]<MinDist) { //若V未被收录且dist[V]更小
MinDist = dist[V]; //更新最小距离
MinV = V; //更新对应顶点
}
}
if(MinDist < INFINITY)
return MinV;
else
return ERROR;
}
Prim算法
-parent[]:保存当前生成树生长过程中,每个顶点的父结点,其中parent[0] = -1,表示v0已加入生成树
-dist[]:保存集合中顶点与生成树中个顶点最短边的权值,dist[v] = 0表示顶点v已添加进最小生成树中
int Prim(MGraph Graph, LGraph MST)
{
WeightType dist[MaxVertexNum]; //dist是一个顶点V到生成树的最小距离
WeightType TotalWeight;
Vertex parent[MaxVertexNum], V, W;
int VCount; //收录的顶点数
Edge E;
//初始化
for(V = 0; V<Graph->Nv; V++) { //默认源点下标为0
dist[V] = Graph->G[0][V];
parent[V] = 0;
}
TotalWeight = 0; //权重和初始化为0
VCount = 0;
MST = CreateGraph(Graph->Nv); //将最小生成树保存为邻接表存储顶点
E = (Edge)malloc(sizeof(struct ENode));
dist[0] = 0;
VCount++;
parent[0] = -1;
while(1) {
V = FindMinDist(Graph, dist);
if(V == ERROR)
break;
E->V1 = parent[V];
E->V2 = V;
E->Weight = dist[V];
InsertEdge(MST, E);
dist[V] = 0;
VCount++;
for(W = 0; W<Graph->Nv; W++)
if(dist[W] != 0 && Graph->G[V][W]<INFINITY) {
if(Graph->G[V][W] < dist[W]) { //若收录V使得dist[W]变小
dist[W] = Graph->G[V][W]; //更新dist[W]
parent[W] = V; //更新树
}
}
}
if(VCount < Graph->Nv)
TotalWeight = ERROR;
return TotalWeight;
}
Kruskal
-将森林合并成树
-均用邻接表
-稀疏图O(ElogE)
按路段长度冒泡排序边
Edge Listsort(LGraph Graph, Edge E)
{
Edge p; //临时量
LengthType temp; //临时量
Edge L; //返回已经排好的边结点
Edge e = E; //原来边的头指针
L = e; //初始化指向第一个结点
while(L != NULL) {
p = L;
//如果前面的那个比后面的那个大,就交换它们之间的是数据域
if (p->length > p->Next->length) {
temp = p->length;
p->length = p->Next->length;
p->Next->length = temp;
}
L = L->Next;
}
return L;
}
查找并返回根结点
int findroot(Edge L, LGraph MST, int tag)
{
if (tag == 1)
return L->root;
else if (tag == 2)
return MST->root;
else
return ERROR;
}
并查集
bool join(Edge L, LGraph MST)
{
int x = findroot(L,MST,1); //L的根结点
int y = findroot(L,MST,2); //MST的根结点
if(x == y) //E和MST原本就在同一棵树上,若加入这条边则会成环
return false;
else {
L->root = MST->root; //将E添加到最小生成树上
return true;
}
}
添加边到最小生成树
void InsertL(LGraph MST, Edge L)
{
PAdjVNode NewNode;
NewNode = (PAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->length = L->length;
NewNode->Next = MST->G[L->V1].FirstEdge;
MST->G[L->V1].FirstEdge = NewNode;
}
Kruskal算法得到最小生成树
int findshortest(LGraph Graph, Edge E, Edge L)
{
LengthType TotalLength;
int VCount; //收录的顶点数
LGraph MST; //最小生成树
//初始化
TotalLength = 0; //权重和初始化为0
VCount = 0;
MST = CreateGraph(Graph->Ne); //将最小生成树保存为邻接表存储边
L = Listsort(Graph, E); //按照路径长短排好的边的头指针
while(MST->Nv < Graph->Nv-1 && L) { //如果最小生成树还没有找完且边还没有遍历完
L = L->Next;
if(join(L, MST)) //如果这条边不在MST中构成回路
InsertL(MST, L); //将该边加入MST
else
break;
}
if(VCount < Graph->Nv-1) //没有找到最小生成树
TotalLength = ERROR;
return TotalLength;
}