最小生成树——Prim(普利姆)算法

原创 2015年11月20日 15:21:57

【0】README

0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解Prim算法的idea 并用 源代码加以实现;
0.2)最小生成树的基础知识,参见 http://blog.csdn.net/pacosonswjtu/article/details/49947085


【1】Prim算法相关

1.1)计算最小生成树的一种方法是使其连续地一步一步长成。在每一步, 都要吧一个节点当做根并往上加边,这样也就把相关联的顶点加到增长中的树上;
1.2)在算法中的任一时刻, 我们都可以看到一个已经添加到树上的顶点集, 而其余顶点尚未加到这颗树中。此时, 算法在每一阶段都可以通过选择边(u, v),使得(u, v)的值是所有u 在树上但v不在树上的边的值中的最小者, 而找出一个新的顶点并吧它添加到这颗树中;
1.3)具体步骤概括为:

  • step1)给定一个顶点为根节点;
  • step2)每一步加一条边和一个顶点; (这也迎合了 顶点个数-边个数=1 );

1.4)看个荔枝:

对上图的分析(Analysis):
A1)可以看到, 其实Prim算法基本上和求最短路径的 Dijkstra算法一样, 因此和前面一样,我们对每一个顶点保留值 Dv和Pv 以及一个指标,指示该顶点是已知的还是未知的。这里,Dv是连接v 到已知顶点的最短边的权, 而 Pv则是导致Dv改变的最后的顶点。
A2)算法的其余部分一样, 唯一不同的是: 由于Dv的定义不同, 因此它的更新法则不一样。事实上,Prim算法的更新法则比 Dijkstra算法简单:在每一个顶点v被选取后, 对于每一个与 v 邻接的未知的w, Dw=min(Dw, Cw,v);
这里写图片描述
对上图的分析(Analysis):
A1)该算法整个的实现实际上和 Dijkstra算法的实现是一样的, 对于 Dijkstra算法分析所做的每一件事都可以用到这里。 不过要注意, Prim算法是在无向图上运行的, 因此当编写代码的时候要记住要吧每一条变都要放到两个邻接表中。
A2)不用堆时的运行时间为O(|V|^2), 它对于稠密图来说是最优的; 使用二叉堆的运行时间为 O(|E|log|V|), 它对于稀疏图是一个好的界限;


【2】source code + printing results(将我的代码打印结果 同 上图中的手动模拟的prim算法的结果进行比较,你会发现, 它们的结果完全相同,这也证实了我的代码的可行性)

2.1)download source code: https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter9/p237_prim
2.2)source code at a glance(for complete code , please click the given link above):

#include "prim.h"

//allocate the memory for initializing unweighted table
WeightedTable *initWeightedTable(int size)
{   
    WeightedTable* table;
    int i;

    table = (WeightedTable*)malloc(sizeof(WeightedTable) * size);
    if(!table)
    {
        Error("out of space ,from func initWeightedTable");
        return NULL;
    }

    for(i = 0; i < size; i++)
    {
        table[i] = makeEmptyWeightedTable();        
        if(!table[i])
            return NULL;
    }

    return table;
} 

// allocate the memory for every element in unweighted table  
WeightedTable makeEmptyWeightedTable()
{
    WeightedTable element;

    element = (WeightedTable)malloc(sizeof(struct WeightedTable));
    if(!element)
    {
        Error("out of space ,from func makeEmptyWeightedTable");
        return NULL;
    }   
    element->known = 0; // 1 refers to accessed , also 0 refers to not accessed
    element->distance = MaxInt;
    element->path = -1; // index starts from 0 and -1 means the startup vertex unreaches other vertexs

    return element;
}

// allocate the memory for storing index of  vertex in heap and let every element -1
int *makeEmptyArray(int size)
{
    int *array;
    int i;

    array = (int*)malloc(size * sizeof(int));
    if(!array)
    {
        Error("out of space ,from func makeEmptyArray");
        return NULL;
    }       
    for(i=0; i<size; i++)
        array[i] = -1;

    return array;
}

//computing the unweighted shortest path between the vertex under initIndex and other vertexs
void prim(AdjTable* adj, int size, int startVertex, BinaryHeap bh)
{       
    int adjVertex;  
    int tempDistance;
    WeightedTable* table;
    int vertex;     
    AdjTable temp;  
    Distance tempDisStruct;
    int *indexOfVertexInHeap;
    int indexOfHeap;

    table = initWeightedTable(size);        
    tempDisStruct = makeEmptyDistance();
    indexOfVertexInHeap = makeEmptyArray(size);

    tempDisStruct->distance = table[startVertex-1]->distance;
    tempDisStruct->vertexIndex = startVertex-1;
    insert(tempDisStruct, bh, indexOfVertexInHeap); // insert the (startVertex-1) into the binary heap  

    table[startVertex-1]->distance = 0;// update the distance 
    table[startVertex-1]->path = 0;// update the path of starting vertex

    while(!isEmpty(bh))
    {       
        vertex = deleteMin(bh, indexOfVertexInHeap).vertexIndex; // return the minimal element in binary heap
        //printBinaryHeap(bh);

        table[vertex]->known = 1; // update the vertex as accessed, also let responding known be 1
        temp = adj[vertex]->next;
        while(temp)
        {
            adjVertex = temp->index; 
            if(table[adjVertex]->known == 1) // judge whether table[adjVertex]->known is 1 or not
            {
                temp = temp->next;
                continue;
            }

            //tempDistance = table[vertex]->distance + temp->weight; // update the distance
            tempDistance = temp->weight;
            if(tempDistance < table[adjVertex]->distance)
            {
                table[adjVertex]->distance = tempDistance;
                table[adjVertex]->path = vertex; //update the path of adjVertex, also responding path evaluated as vertex                           

                // key, we should judge whether adjVertex was added into the binary heap                
                //if true , obviously the element has been added into the binary heap(so we can't add the element into heap once again)
                if(indexOfVertexInHeap[adjVertex] != -1) 
                {
                    indexOfHeap = indexOfVertexInHeap[adjVertex];
                    bh->elements[indexOfHeap]->distance = tempDistance; // update the distance of corresponding vertex in binary heap
                }
                else // if not ture
                {
                    tempDisStruct->distance = table[adjVertex]->distance;
                    tempDisStruct->vertexIndex = adjVertex;
                    insert(tempDisStruct, bh, indexOfVertexInHeap); // insert the adjVertex into the binary heap
                }
            }            
            temp = temp->next;      
        }       
        printPrim(table, size, startVertex);        
        printBinaryHeap(bh);
        printf("\n");
    }       

    printf("\n");
} 

//print unweighted table
void printPrim(WeightedTable* table, int size, int startVertex)
{
    int i;  
    char *str[4] = 
    {
        "vertex",
        "known",
        "distance",
        "path"
    };

    printf("\n\t === storage table related to Prim alg as follows: === ");  
    printf("\n\t %6s%6s%9s%5s", str[0], str[1], str[2], str[3]);    
    for(i=0; i<size; i++)
    {       
        if(i != startVertex-1 && table[i]->path!=-1) 
            printf("\n\t %-3d   %3d   %5d      v%-3d  ", i+1, table[i]->known, table[i]->distance, table[i]->path+1);
        else if(table[i]->path == -1)
            printf("\n\t %-3d   %3d   %5d      %-3d  ", i+1, table[i]->known, table[i]->distance, table[i]->path);
        else
            printf("\n\t *%-3d  %3d   %5d      %-3d  ", i+1, table[i]->known, table[i]->distance, 0);
    }    
}

int main()
{ 
    AdjTable* adj;  
    BinaryHeap bh;
    int size = 7;
    int capacity;
    int i;
    int j;  
    int startVertex;

    int adjTable[7][7] = 
    {
        {0, 2, 4, 1, 0, 0, 0},
        {2, 0, 0, 3, 10, 0, 0},
        {4, 0, 0, 2, 0, 5, 0},
        {1, 3, 2, 0, 7, 8, 4},
        {0, 10, 0, 7, 0, 0, 6},
        {0, 0, 5, 8, 0, 0, 1},
        {0, 0, 0, 4, 6, 1, 0},
    };

    printf("\n\n\t ====== test for Prim alg finding weighted shortest path from adjoining table ======\n");
    adj = initAdjTable(size);       

    printf("\n\n\t ====== the initial weighted adjoining table is as follows:======\n");
    for(i = 0; i < size; i++)
        for(j = 0; j < size; j++)   
            if(adjTable[i][j])          
                insertAdj(adj, j, i, adjTable[i][j]); // insertAdj the adjoining table over

    printAdjTable(adj, size);   

    capacity = 7;
    bh = initBinaryHeap(capacity+1);
    //conducting prim alg to find minimum spanning tree(MST)
    startVertex = 1; // you should know our index for storing vertex starts from 0
    prim(adj, size, startVertex, bh);   

    return 0;
} 

2.3)printing results:

这里写图片描述
这里写图片描述
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

算法导论--最小生成树(Kruskal和Prim算法)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175关于图的几个概念定义: 连通图:在无向图中,若任意两...
  • luoshixian099
  • luoshixian099
  • 2016年07月14日 16:58
  • 13401

最小生成树Prim算法理解

MST(Minimum Spanning Tree,最小生成树)
  • yeruby
  • yeruby
  • 2014年08月16日 18:49
  • 85782

prim最小生成树算法原理

prim 最小生成树算法原理 主要需要了解算法的原理、算法复杂度、优缺点 、刻画和度量指标 评价等 可以查阅相关的文献,这部分内容主要整合了两篇博客的内容 分别是:http://blog.csdn....
  • lynnucas
  • lynnucas
  • 2016年05月03日 16:51
  • 3853

数据结构:最小生成树--Prim算法

最小生成树 给定一无向带权图,顶点数是n,要使图连通只需n-1条边,若这n-1条边的权值和最小,则称有这n个顶点和n-1条边构成了图的最小生成树(minimum-cost spanning ...
  • zhangxiangDavaid
  • zhangxiangDavaid
  • 2014年08月05日 00:30
  • 10285

图的最小生成树之Prim算法

图的最小生成树是指一颗连接图中所有顶点,具有权重最小的树,树的权重为所有树边的权重之和。最小生成树可以应用在电路规划中,规划出既能连接各个节点又能使材料最为节省的布局。计算最小生成树有两个经典算法,分...
  • Ivan_zgj
  • Ivan_zgj
  • 2016年05月31日 18:48
  • 2080

最小生成树之Prim算法

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。该算法于1930年由捷...
  • luomingjun12315
  • luomingjun12315
  • 2015年08月23日 07:28
  • 2666

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

Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (...
  • gettogetto
  • gettogetto
  • 2016年11月18日 15:11
  • 3286

最小生成树prime算法

  • 2013年06月18日 16:21
  • 4KB
  • 下载

算法:图解最小生成树之普里姆(Prim)算法

我们在图的定义中说过,带有权值的图就是网结构。一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边。所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接...
  • Simba888888
  • Simba888888
  • 2013年04月30日 21:32
  • 17290

普利姆(prim)算法和克鲁斯卡尔(kruskal)算法

连通网的最小生成树算法: 1.普里姆算法——”加点法”。 假设N=(V,{E})是连通网,TE为最小生成树的边集合。 (1)初始U={u0}(u0∈V),TE=φ; (2)在所有u∈U,...
  • Solo95
  • Solo95
  • 2016年05月18日 17:36
  • 1251
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:最小生成树——Prim(普利姆)算法
举报原因:
原因补充:

(最多只允许输入30个字)