最小生成树贪心算法,Prim算法和Kruskal算法的实现

生成树:包含图中全部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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kentos(acoustic ver.)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值