数据结构之最小生成树Prim算法建议收藏

普里姆算法介绍普里姆(Prim)算法,是用来求加权连通图的最小生成树算法基本思想:对于图G而言,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

普里姆算法介绍

  普里姆(Prim)算法,是用来求加权连通图的最小生成树算法

  基本思想:对于图G而言,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最小生成树中的边。 从所有uЄU,vЄ(V-U) (V-U表示出去U的所有顶点)的边中选取权值最小的边(u, v),将顶点v加入集合U中,将边(u, v)加入集合T中,如此不断重复,直到U=V为止,最小生成树构造完毕,这时集合T中包含了最小生成树中的所有边。

数据结构之最小生成树Prim算法建议收藏

代码实现

1. 思想逻辑

  (1)以无向图的某个顶点(A)出发,计算所有点到该点的权重值,若无连接取最大权重值#define INF    (~(0x1<<31))

  (2)找到与该顶点最小权重值的顶点(B),再以B为顶点计算所有点到改点的权重值,依次更新之前的权重值,注意权重值为0或小于当前权重值的不更新,因为1是一当找到最小权重值的顶点时,将权重值设为了0,2是会出现无连接的情况。

  (3)将上述过程一次循环,并得到最小生成树。

2. Prim算法

// Prim最小生成树
void Prim(int nStart)
{
    int i = 0;
    int nIndex=0;         // prim最小树的索引,即prims数组的索引 
    char cPrims[MAX];     // prim最小树的结果数组 
    int weights[MAX];    // 顶点间边的权值
    
    cPrims[nIndex++] = m_mVexs[nStart].data;

    // 初始化"顶点的权值数组",
    // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
    for (i = 0; i < m_nVexNum; i++)
    {
        weights[i] = GetWeight(nStart, i);
    }

    for (i = 0; i < m_nVexNum; i ++)
    {
        if (nStart == i)
        {
            continue;
        }
        
        int min = INF;
        int nMinWeightIndex = 0;
        for (int k = 0; k < m_nVexNum; k ++)
        {
            if (weights[k]!= 0 && weights[k] < min)
            {
                min = weights[k];
                nMinWeightIndex = k;
            }
        }

        // 找到下一个最小权重值索引
        cPrims[nIndex++] = m_mVexs[nMinWeightIndex].data;
        // 以找到的顶点更新其他点到该点的权重值
        weights[nMinWeightIndex]=0;
        int nNewWeight = 0;
        for (int ii = 0; ii < m_nVexNum; ii++)
        {
            nNewWeight = GetWeight(nMinWeightIndex, ii);
            // 该位置需要特别注意
            if (0 != weights[ii] && weights[ii] > nNewWeight)
            {
                weights[ii] = nNewWeight;
            }
        }
    }
    // 计算最小生成树的权重值
    int nSum = 0;
    for (i = 1; i < nIndex; i ++)
    {
        int min = INF;
        int nVexsIndex = GetVIndex(cPrims[i]);
        for (int kk = 0; kk < i; kk ++)
        {
            int nNextVexsIndex = GetVIndex(cPrims[kk]);
            int nWeight = GetWeight(nVexsIndex, nNextVexsIndex);
            if (nWeight < min)
            {
                min = nWeight;
            }
        }
        nSum += min;
    }

    // 打印最小生成树 
    cout << "PRIM(" << m_mVexs[nStart].data  <<")=" << nSum << ": "; 
    for (i = 0; i < nIndex; i++) 
        cout << cPrims[i] << " "; 
    cout << endl; 

}

3. 全部实现

数据结构之最小生成树Prim算法建议收藏
数据结构之最小生成树Prim算法建议收藏

#include "stdio.h"
#include <iostream>
using namespace std;

#define MAX 100
#define INF         (~(0x1<<31))        // 最大值(即0X7FFFFFFF)

class EData
{
public:
    EData(char start, char end, int weight) : nStart(start), nEnd(end), nWeight(weight){}
    
    char nStart;
    char nEnd;
    int nWeight;
};
//
struct ENode
{
    int nVindex;  // 该边所指的顶点的位置
    int nWeight;  // 边的权重
    ENode *pNext; // 指向下一个边的指针
};

struct VNode
{
    char data;  // 顶点信息
    ENode *pFirstEdge; // 指向第一条依附该顶点的边
};

// 无向邻接表
class listUDG
{
public:
    listUDG(){};
    listUDG(char *vexs, int vlen, EData **pEData, int elen)
    {
        m_nVexNum = vlen;
        m_nEdgNum = elen;

        // 初始化"邻接表"的顶点
        for (int i = 0; i < vlen; i ++)
        {
            m_mVexs[i].data = vexs[i];
            m_mVexs[i].pFirstEdge = NULL;
        }

        char c1,c2;
        int p1,p2;
        ENode *node1, *node2;
        // 初始化"邻接表"的边
        for (int j = 0; j < elen; j ++)
        {
            // 读取边的起始顶点和结束顶点
            c1 = pEData[j]->nStart;
            c2 = pEData[j]->nEnd;
            p1 = GetVIndex(c1);
            p2 = GetVIndex(c2);

            node1 = new ENode();
            node1->nVindex = p2;
            node1->nWeight = pEData[j]->nWeight;
            if (m_mVexs[p1].pFirstEdge == NULL)
            {
                m_mVexs[p1].pFirstEdge = node1;
            }
            else
            {
                LinkLast(m_mVexs[p1].pFirstEdge, node1);
            }

            node2 = new ENode();
            node2->nVindex = p1;
            node2->nWeight = pEData[j]->nWeight;
            if (m_mVexs[p2].pFirstEdge == NULL)
            {
                m_mVexs[p2].pFirstEdge = node2;
            }
            else
            {
                LinkLast(m_mVexs[p2].pFirstEdge, node2);
            }
        }

    }
    ~listUDG()
    {
        ENode *pENode = NULL;
        ENode *pTemp = NULL;
        for (int i = 0; i < m_nVexNum; i ++)
        {
            pENode = m_mVexs[i].pFirstEdge;
            if (pENode != NULL)
            {
                pTemp = pENode;
                pENode = pENode->pNext;

                delete pTemp;
            }
            delete pENode;
        }
    }

    void PrintUDG()
    { 
        ENode *pTempNode = NULL;
        cout << "邻接无向表:" << endl;
        for (int i = 0; i < m_nVexNum; i ++)
        {
            cout << "顶点:" << GetVIndex(m_mVexs[i].data)<< "-" << m_mVexs[i].data<< "->";
            pTempNode = m_mVexs[i].pFirstEdge;
            while (pTempNode)
            {
                cout <<pTempNode->nVindex << "->";
                pTempNode = pTempNode->pNext;
            }
            cout << endl;
        }
    }

    // Prim最小生成树
    void Prim(int nStart)
    {
        int i = 0;
        int nIndex=0;         // prim最小树的索引,即prims数组的索引 
        char cPrims[MAX];     // prim最小树的结果数组 
        int weights[MAX];    // 顶点间边的权值
        
        cPrims[nIndex++] = m_mVexs[nStart].data;

        // 初始化"顶点的权值数组",
        // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
        for (i = 0; i < m_nVexNum; i++)
        {
            weights[i] = GetWeight(nStart, i);
        }

        for (i = 0; i < m_nVexNum; i ++)
        {
            if (nStart == i)
            {
                continue;
            }
            
            int min = INF;
            int nMinWeightIndex = 0;
            for (int k = 0; k < m_nVexNum; k ++)
            {
                if (weights[k]!= 0 && weights[k] < min)
                {
                    min = weights[k];
                    nMinWeightIndex = k;
                }
            }

            // 找到下一个最小权重值索引
            cPrims[nIndex++] = m_mVexs[nMinWeightIndex].data;
            // 以找到的顶点更新其他点到该点的权重值
            weights[nMinWeightIndex]=0;
            int nNewWeight = 0;
            for (int ii = 0; ii < m_nVexNum; ii++)
            {
                nNewWeight = GetWeight(nMinWeightIndex, ii);
                // 该位置需要特别注意
                if (0 != weights[ii] && weights[ii] > nNewWeight)
                {
                    weights[ii] = nNewWeight;
                }
            }
        }
        // 计算最小生成树的权重值
        int nSum = 0;
        for (i = 1; i < nIndex; i ++)
        {
            int min = INF;
            int nVexsIndex = GetVIndex(cPrims[i]);
            for (int kk = 0; kk < i; kk ++)
            {
                int nNextVexsIndex = GetVIndex(cPrims[kk]);
                int nWeight = GetWeight(nVexsIndex, nNextVexsIndex);
                if (nWeight < min)
                {
                    min = nWeight;
                }
            }
            nSum += min;
        }

        // 打印最小生成树 
        cout << "PRIM(" << m_mVexs[nStart].data  <<")=" << nSum << ": "; 
        for (i = 0; i < nIndex; i++) 
            cout << cPrims[i] << " "; 
        cout << endl; 
    }
private:
    // 获取<start, end>的权值,若start和end不是连接的,则返回无穷大
    int GetWeight(int start, int end)
    {
        if (start == end)
        {
            return 0;
        }
        ENode *pTempNode = m_mVexs[start].pFirstEdge;
        while (pTempNode)
        {
            if (end == pTempNode->nVindex)
            {
                return pTempNode->nWeight;
            }
            pTempNode = pTempNode->pNext;
        }

        return INF;
    }

    // 返回顶点的索引
    int GetVIndex(char ch)
    {
        int i = 0;
        for (; i < m_nVexNum; i ++)
        {
            if (m_mVexs[i].data == ch)
            {
                return i;
            }
        }
        return -1;
    }

    void LinkLast(ENode *pFirstNode, ENode *pNode)
    {
        if (pFirstNode == NULL || pNode == NULL)
        {
            return;
        }
        ENode *pTempNode = pFirstNode;
        while (pTempNode->pNext != NULL)
        {
            pTempNode = pTempNode->pNext;
        }

        pTempNode->pNext = pNode;
    }

private:
    int m_nVexNum;   // 顶点数目
    int m_nEdgNum;   // 边数目
    VNode m_mVexs[MAX];
    VNode m_PrimVexs[MAX];
};

void main()
{
    char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 
    //
    EData *edges[] = { 
               // 起点 终点 权 
        new EData('A', 'B', 12),  
        new EData('A', 'F', 16),  
        new EData('A', 'G', 14),  
        new EData('B', 'C', 10),  
        new EData('B', 'F',  7),  
        new EData('C', 'D',  3),  
        new EData('C', 'E',  5),  
        new EData('C', 'F',  6),  
        new EData('D', 'E',  4),  
        new EData('E', 'F',  2),  
        new EData('E', 'G',  8),  
        new EData('F', 'G',  9)
    };
    int vlen = sizeof(vexs)/sizeof(vexs[0]); 
    int elen = sizeof(edges)/sizeof(edges[0]); 
    listUDG* pG = new listUDG(vexs, vlen, edges, elen); 

    pG->PrintUDG();   // 打印图 
    pG->Prim(0);

    for (int i = 0; i < elen; i ++)
    {
        delete edges[i];
    }
    return; 
}

View Code

数据结构之最小生成树Prim算法建议收藏

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120149.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 32H7_H7可以改H4吗

    32H7_H7可以改H4吗完整版教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547第38章STM32H7的FIR高通滤波器实现(支持逐个数据的实时滤波)本章节讲解FIR高通滤波器实现。目录38.1初学者重要提示38.2高通滤波器介绍38.3FIR滤波器介绍38.4Matlab工具箱filterDesinger生成高通滤波器C头文件38.5FIR高通滤波器设计38.5.1函数arm_fir_i…

    2025年8月31日
    6
  • linux如何退出编辑状态_linux编辑文件命令 vi

    linux如何退出编辑状态_linux编辑文件命令 vilinux退出编辑模式的命令linux退出编辑模式的命令有:vim有三种模式,注意:这三种模式有很多不同的叫法,我这里是按照鸟哥的linux书中的叫法。一般指令模式、编辑模式、指令列命令模式1.vim文件名进入一般模式;2.按i进行编辑进入编辑模式;(或者I,o,O,a,A,r,R)3.编辑结束,按ESC键跳到一般模式模式;4.按:进入指令列命…

    2022年10月1日
    4
  • 建立机制的重要性_机制的构成要素

    建立机制的重要性_机制的构成要素细细的读读神级代码werkzeug,研究其具体的实现逻辑,以及代码细节。

    2022年10月6日
    2
  • 编写java判断闰年_用Java程序判断是否是闰年的简单实例[通俗易懂]

    编写java判断闰年_用Java程序判断是否是闰年的简单实例[通俗易懂]我们知道,(1)如果是整百的年份,能被400整除的,是闰年;(2)如果不是整百的年份,能被4整除的,也是闰年。每400年,有97个闰年。鉴于此,程序可以作以下设计:第一步,判断年份是否被400整除,能的话,就是闰年。比如1600、2000、2400年是闰年。第二步,在第一步不成立的基础上,判断年份能否被100整除,如果是,则不是闰年。比如1900、2100、2200年不是闰年。第三步,在第二步不成…

    2022年7月8日
    20
  • fastclick

    fastclickfastclick–处理移动端click事件300毫秒延迟安装:npminstallfastclick–save   之后,在main.js中引入    importFastClickfrom’fastclick’    并绑定到bodyFastClick.attach(document.body);1、兼容性iOS3及更高版本的移动SafariiOS5及更高版本的C…

    2022年6月19日
    54
  • 各大技术团队博客_如何扩大团队规模

    各大技术团队博客_如何扩大团队规模BAT技术团队博客1.美团技术团队博客: 地址: http://tech.meituan.com/2. 腾讯社交用户体验设计(ISUX)地址:http://isux.tencent.com/3. 京东设计中心地址:http://jdc.jd.com4. QQ游戏设计中心地址:ht

    2022年8月13日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号