最小生成树之prim算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树之prim算法相关的知识,希望对你有一定的参考价值。

图片描述

技术分享

技术分享

技术分享

 

 

 

 


 

算法思想

  在算法中的每一步,把一个节点当作根并往上加边,这样就可以把相关联的顶点加到增长中的树中

  选择边(u,v),使得(u,v)的值是所有u在树上但是v不在树上的边中值最小的,从而找出新顶点v加入到这棵树中


 

算法思路

  Prim算法基本和Dijkstra算法一样

  顶点结构包括

    dist ——> 连接v到已知顶点的最短边的权

    path——> 导致顶点v的dist改变的最后的顶点

    kown——>标记该顶点是否为处理过

  1.选取一个顶点作为树根

  2.从到该树根最近的顶点v为中心(标记处理),探索能到达v的顶点w的dist是否需要被更新

      此处

        dist = min(dist,Cv,w)

  3.顶点v作为树根

  4.重复2-3步骤


 

代码实现

    邻接链表实现

#include <iostream>
#include <cstdlib>


#define VERSIZE 7
#define NotVertex -1
#define Infinity 100000

using namespace std;

typedef int Vertex;

typedef struct vernode VerNode;//定义顶点结构
typedef struct tablelist Table;//定义邻接表

struct vernode
{
    Vertex ver;
    int weight;//权重
    VerNode * pNext;
};

struct tablelist
{
    VerNode header;//表头
    bool known;
    int dist;//连接v到已知顶点的最短边的权
    Vertex path;//导致dist最后改变的顶点
}T[VERSIZE];


//初始化标表+读图
void InitTable(Table T[], int n, int m)//顶点数n 边数m
{
    int i = 0;
    for (i = 1; i <= n; i++)//初始化表头
    {
        T[i].header.ver = i;
        T[i].header.weight = 0;//到自身的权重为0
        T[i].header.pNext = NULL;
        T[i].dist = Infinity;
        T[i].known = false;
        T[i].path = NotVertex;
    }
    Vertex u, v;//边(u,v)
    int wei = 0;
    VerNode * ptemp;
    for (i = 1; i <= m; i++)
    {
        cout << "请输入第" << i << "条边:";
        cin >> u >> v;
        cout << "请输入边(" << u << "," << v << ")的权重:";
        cin >> wei;
        ptemp = (VerNode*)malloc(sizeof(VerNode));//将权重记到两个表中
        ptemp->ver = v;
        ptemp->weight = wei;
        ptemp->pNext = T[u].header.pNext;
        T[u].header.pNext = ptemp;
        ptemp = (VerNode*)malloc(sizeof(VerNode));
        ptemp->ver = u;
        ptemp->weight = wei;
        ptemp->pNext = T[v].header.pNext;
        T[v].header.pNext = ptemp;
    }
}

//找出到上一个点距离最小的顶点
Vertex FindMinIndex(Table T[], int n)
{
    int i = 0;
    int min = Infinity;
    Vertex min_index = NotVertex;
    for (i = 1; i <= n; i++)
    {
        if (!T[i].known && T[i].dist < min)
        {
            min = T[i].dist;
            min_index = i;
        }
    }
    return min_index;
}

int prim(Table T[], Vertex source,int n)
{    
    int sum = 0;
    int i = 0;
    T[source].dist = 0;//源点到源点的距离为0
    T[source].known = true;//源点已知
    sum = T[source].dist;

    //在做循环处理前 初始化
    VerNode * ptemp;
    ptemp = T[source].header.pNext;
    Vertex w;
    while (ptemp)
    {
        w = ptemp->ver;
        T[w].dist = ptemp->weight;
        T[w].path = source;
        ptemp = ptemp->pNext;
    }

    Vertex v;
    //处理n-1个顶点
    for (i = 1; i <= n - 1; i++)
    {
        //找出到上一个点距离最小的顶点
        v = FindMinIndex(T, n);
        if (v == NotVertex)
            break;
        T[v].known = true;
        sum += T[v].dist;
        ptemp = T[v].header.pNext;//找出顶点V所能到的顶点看是否能跟新他们的dist
        while (ptemp)
        {
            w = ptemp->ver;
            if (!T[w].known && T[w].dist > ptemp->weight)//进行跟新操作
            {
                T[w].dist = ptemp->weight;
                T[w].path = v;
            }
            ptemp = ptemp->pNext;
        }
    }
    return sum;
}

int main()
{
    Table T[VERSIZE];
    InitTable(T, 7, 12);
    cout << prim(T, 1, 7)<< endl;
    system("pause");
    return 0;
}

    邻接矩阵实现

#include <iostream>
#include <cstdlib>

#define Infinity 10000
#define VERSIZE  8
#define notvertex -1

using namespace std;
typedef int  Vertex;

int dist[VERSIZE];//连接v到已知顶点的最短边权
bool S[VERSIZE];//将处理过的顶点设置为true
Vertex path[VERSIZE];//存储到该顶点的上一个顶点

void ReadGraph(int Graph[VERSIZE][VERSIZE], int m)// 边m
{
    int i = 0;
    Vertex u, v;
    int weight;
    for (i = 1; i <= m; i++)
    {
        cout << "请输入第" << i << "条边:";
        cin >> u >> v;
        cout << "请输入边(" << u << "," << v << ")的权重:";
        cin >> weight;
        Graph[u][v] = weight;
        Graph[v][u] = weight;
    }
}

//在没处理过的顶点里 找出距离源点最近的顶点
Vertex FindMinIndex()
{
    int min = Infinity;
    Vertex min_index = 0;
    for (int i = 1; i< VERSIZE; i++)
    {
        if (!S[i] && dist[i]<min)
        {
            min = dist[i];
            min_index = i;
        }
    }
    return min_index;
}

//算法关键
int prim(int Graph[VERSIZE][VERSIZE], Vertex source)
{
    int sum = 0;
    int i = 0;
    // 初始化数组  从顶点为1开始能直接到达source的 初始化dis数组 0代表不可达
    for (i = 1; i < VERSIZE; i++)
    {
        dist[i] = (Graph[source][i] == 0 ? Infinity : Graph[source][i]);
        S[i] = false;
        if (dist[i] != Infinity)
            path[i] = source;
        else
            path[i] = notvertex;
    }

    //源点到自身
    dist[source] = 0;
    S[source] = true;
    sum = dist[source];
    //循环VERSIZE-1次
    for (int count = 1; count < VERSIZE; count++)
    {
        Vertex u = FindMinIndex();//找出距离源点最近的顶点
        S[u] = true;//标记为已知
        sum += dist[u];

        for (int v = 1; v < VERSIZE; v++)
        {
            if (Graph[u][v] != 0 && !S[i])//u可达v 且 v未知
            {
                if (dist[v] >Graph[u][v])
                {
                    dist[v] = Graph[u][v];
                    path[v] = u;
                }
            }
        }
    }
    return sum;
}


int main()
{
    int i = 0, j = 0;
    int Graph[VERSIZE][VERSIZE] = { 0 };
    for (i = 1; i < VERSIZE; i++)//初始化二维数组
    {
        for (j = 1; j < VERSIZE; j++)
            Graph[i][j] = 0;
    }
    ReadGraph(Graph,12);
    cout << prim(Graph, 1) << endl;
    system("pause");
    return 0;
}

 

实验结果

技术分享


    THOUGHTS

    Prim算法和Dijkstra算法十分相似,于是用了我上篇的博客,改了dist的判断

    嗯,每天努力一点就好。

    博客参考自《数据结构与算法分析》

 

以上是关于最小生成树之prim算法的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树之Kruskal算法和Prim算法

最小生成树之Prim算法

最小生成树之Prim算法

最小生成树之prim算法

24最小生成树之Prim算法

最小生成树之Prim算法