【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:





最小生成树——Prim(普利姆)算法的更多相关文章

  1. 普利姆算法(prim)

    普利姆算法(prim)求最小生成树(MST)过程详解 (原网址) 1 2 3 4 5 6 7 分步阅读 生活中最小生成树的应用十分广泛,比如:要连通n个城市需要n-1条边线路,那么怎么样建设才能使工程 ...

  2. 最小生成树-普利姆算法lazy实现

    算法描述 lazy普利姆算法的步骤: 1.从源点s出发,遍历它的邻接表s.Adj,将所有邻接的边(crossing edges)加入优先队列Q: 2.从Q出队最轻边,将此边加入MST. 3.考察此边的 ...

  3. 最小生成树-普利姆算法eager实现

    算法描述 在普利姆算法的lazy实现中,参考:普利姆算法的lazy实现 我们现在来考虑这样一个问题: 我们将所有的边都加入了优先队列,但事实上,我们真的需要所有的边吗? 我们再回到普利姆算法的lazy ...

  4. ACM第四站————最小生成树(普里姆算法)

    对于一个带权的无向连通图,其每个生成树所有边上的权值之和可能不同,我们把所有边上权值之和最小的生成树称为图的最小生成树. 普里姆算法是以其中某一顶点为起点,逐步寻找各个顶点上最小权值的边来构建最小生成 ...

  5. MST最小生成树及Prim普鲁姆算法

    MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...

  6. 查找最小生成树:普里姆算法算法(Prim)算法

    一.算法介绍 普里姆算法(Prim's algorithm),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之 ...

  7. POJ 1751 Highways(最小生成树Prim普里姆,输出边)

    题目链接:点击打开链接 Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has ...

  8. 最小生成树-普利姆(Prim)算法

    最小生成树-普利姆(Prim)算法 最小生成树 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一种特殊的图),或者 ...

  9. 图论---最小生成树----普利姆(Prim)算法

    普利姆(Prim)算法 1. 最小生成树(又名:最小权重生成树) 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一 ...

  10. 算法与数据结构(五) 普利姆与克鲁斯卡尔的最小生成树(Swift版)

    上篇博客我们聊了图的物理存储结构邻接矩阵和邻接链表,然后在此基础上给出了图的深度优先搜索和广度优先搜索.本篇博客就在上一篇博客的基础上进行延伸,也是关于图的.今天博客中主要介绍两种算法,都是关于最小生 ...

随机推荐

  1. 线程流量控制工具之Semaphore

    简介 Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源.很多年以来,我都觉得从字面上很难理解Semaphore所表达的含义,只能把它比作是 ...

  2. Windows 定时删除指定路径下N天前的日志文件

    Windows 定时删除指定路径下N天前的日志文件 Windows 下bat脚本文件的内容为 1. 删除指定路径下5天前的所有文件 @echo off set SrcDir=E:\WORK\Git s ...

  3. 【Linux】CentOS7 添加常用源

    CentOS 的官方源去掉了一些与版权有关的软件,因此想要安装这些软件或者手动下载安装,或者使用其他源. 下面是添加EPEL源和RPMforge源的步骤. 1.首先, 添加源之前要确定系统架构及版本 ...

  4. barrier and Fence

    barrier 管理的是commandbuffer里面 command之间 fence管理的是queue之间 queue和cpu之间的顺序 通过flag比如等待所有面片画完 ------------- ...

  5. 【C#】.NET提供了哪些类型来实现反射

    实现反射的类型大多数都定义在System.Reflection命名空间之下. Assembly 定义一个Assembly,它是可重用.无版本冲突并且可自我描述的公共语言运行库应用程序构造块. Asse ...

  6. Linux 下Office 软件名称

    Linux 下Office 软件名称

  7. python第一个web程序

    例一: import web urls= ('/(.*)','index') app= web.application(urls,globals()) class index: def GET(sel ...

  8. spark插件入门完整版本

    1 在spark项目中添加source folder文件夹,取名为src/plugins/testplugin/src/java 2 在此文件夹下新建包名,取名为com.jivesoftware.sp ...

  9. curl命令测试https

    curl -vosa --resolve pic.test.net::222.241.7.179 https://pic.test.net/UploadFiles/201312031744347965 ...

  10. Jquery跨域请求php数据(jsonp)

    Jquery跨域请求php数据 我们一般用到ajax的时候是在同服务器下,一般情况下不会跨域,但有时候需要调用其他域名或ip下的数据的时候,遇到跨域请求数据的时候. 今天在工作中碰到javascrip ...