大白话解析Prim最小生成树算法

Prim最小生成树算法实现思路

image-20210427152511333

思路

  1. 从某一个顶点开始创建树
  2. 从生成树与未加入生成树的顶点相连的边中选取最小开销的边加入生成树
  3. 更新生成树到未加入生成树的顶点的开销
  4. 反复2,3步骤

逻辑存储结构

typedef struct Adjacenc_Matrix
{
    int vex[MaxSize];
    int T[MaxSize][MaxSize];
} Adjacenc_Matrix;

typedef struct Prim
{
    bool isjoin[MaxSize];//标记顶点是否加入生成树
    int lowCost[MaxSize];//记录顶点到生产树的最小开销
    Adjacenc_Matrix Adj;
} Prim;

例如从v0开始创建最小生成树

  1. 首先初始化,存入生成树{v0}到未加入生成树的顶点{v1,v2,v3,v4,v5}的距离

    顶点下标012345
    isjoin100000
    lowCost0651无穷无穷
  2. 从生成树{v0}与未加入生成树的顶点{v1,v2,v3,v4,v5}的边中选取最小开销的边加入生成树,即(v0,v3)

  3. 如果生成树{v0,v3}与未加入生成树的顶点{v1,v2,v4,v5}的距离小于原来的距离,则更新

    1. 新加入生成树的v3到v1的开销为:5<6,更新

    2. 新加入生成树的v3到v2的开销为:4<5,更新

    3. 新加入生成树的v3到v4的开销为:6<65535,更新

    4. 新加入生成树的v3到v5的开销为:4<65535,更新

      顶点下标012345
      isjoin100000
      lowCost06->55->41无穷->6无穷->4
  4. 重复步骤2,3,则可生成最小生成树

image-20210427194009743

全部代码

#include <iostream>
#include <string>
using namespace std;
#define MaxSize 6
#define InitWeight 65535

typedef struct Adjacenc_Matrix
{
    int vex[MaxSize];
    int T[MaxSize][MaxSize];
} Adjacenc_Matrix;

typedef struct Prim
{
    bool isjoin[MaxSize];
    int lowCost[MaxSize];
    Adjacenc_Matrix Adj;
} Prim;
bool Init(Prim &p)
{
    for (int i = 0; i < MaxSize; i++)
    {
        cin >> p.Adj.vex[i];
        p.isjoin[i] = false;
        for (int j = 0; j < MaxSize; j++)
        {
            if (i == j)
            {
                p.Adj.T[i][j] = 0;
                continue;
            }
            p.Adj.T[i][j] = InitWeight;
        }
    }
    return true;
}
bool CreateTable(Prim &p)
{
    for (int i = 0; i < MaxSize; i++)
    {
        int j, weight;
        cin >> p.Adj.vex[i];
        while (true)
        {
            if (cin.get() == '\n')
            {
                break;
            }
            cin >> j >> weight;

            p.Adj.T[i][j] = weight;
        }
    }
    return true;
}
//遍历邻接矩阵
void VisitAdj(Prim p)
{
    printf("------------------邻接矩阵------------------\n");
    for (int i = 0; i < MaxSize; i++)
    {
        for (int j = 0; j < MaxSize; j++)
        {
            printf("%d\t", p.Adj.T[i][j]);
        }
        printf("\n");
    }
    printf("------------------------------------------\n");
}
void VisitIsjoinLowCost(Prim p)
{
    printf("------------------------------------------\n");
    for (int i = 0; i < MaxSize; i++)
    {
        printf("%d\t", p.isjoin[i]);
    }
    printf("\n");
    for (int i = 0; i < MaxSize; i++)
    {
        printf("%d\t", p.lowCost[i]);
    }
    printf("\n");
    printf("------------------------------------------\n");
}
void GetMinWeight(Prim p)
{
    int sum = 0;
    for (int i = 0; i < MaxSize; i++)
    {
        sum += p.lowCost[i];
    }
    printf("最小生成树权值之和:%d\n", sum);
}
bool MinSpanTree(Prim &p, int start)
{
    //初始化
    p.isjoin[start] = true;
    for (int i = 0; i < MaxSize; i++)
    {
        p.lowCost[i] = p.Adj.T[start][i];
    }
    //构建最小生成树
    VisitIsjoinLowCost(p);
    for (int k = 1; k < MaxSize; k++)
    {
        //找出与生成树相连并且最小开销的路径,并加入生成树
        int min = InitWeight;
        int index;
        for (int i = 0; i < MaxSize; i++)
        {
            if (p.lowCost[i] < min && !p.isjoin[i])
            {
                min = p.lowCost[i];
                index = i;
            }
        }
        printf("min:%d index:%d\n", min, index);
        p.isjoin[index] = true;
        for (int i = 0; i < MaxSize; i++)
        {
            //如果新加入生成树的顶点到未加入生成树的顶点开销<原来的开销,则更新生成树到未加入生成树的顶点开销
            if (!p.isjoin[i] && p.Adj.T[i][index] < p.lowCost[i])
            {
                p.lowCost[i] = p.Adj.T[i][index];
            }
        }
        VisitIsjoinLowCost(p);
    }
    return true;
}
int main()
{
    /* 
0 1 2 3 4 5
0 1 6 2 5 3 1
1 0 6 3 5 4 3
2 0 5 3 4 2 5
3 0 1 1 5 4 6 5 4 2 4
4 1 3 3 6 5 6
5 4 6 3 4 2 2
*/
    Prim p;
    Init(p);
    CreateTable(p);
    VisitAdj(p);
    MinSpanTree(p, 0);
    GetMinWeight(p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值