首页 > 代码库 > 最小生成树--prim算法
最小生成树--prim算法
一个无向图G的最小生成树就是由该图的那些连接G的所有顶点的边构成的树,且其总价值最低,因此,最小生成树存在的充分必要条件为图G是连通的,简单点说如下:
1.树的定义:有n个顶点和n-1条边,没有回路的称为树
生成树的定义:生成树就是包含全部顶点,n-1(n为顶点数)条边都在图里就是生成树
最小:指的是这些边加起来的权重之和最小
2.判定条件:向生成树中任加一条边都一定构成回路
充分必要条件:最小生成树存在那么图一定是连通的,反过来,图是连通的则最小生成树一定存在
上图的红色的边加上顶点就是原图的一个最小生成树。
给定一个图G,如何计算出该图的最小生成树,最通用的算法有两个,一是Prim算法,二是Kruskal算法,这里先讨论Prim算法。
Prim算法和Dijkstra算法类似,我们对每一个顶点计算值dv和pv以及一个指标,该指标表示该顶点是已知的还是未知的,dv是连接v到已知顶点的最短边的权,pv是导致dv改变的最后的顶点,和Dijkstra算法不同的是dv的更新规则:在每一个顶点v被选取以后,对于每一个与v邻接的未知点w,dw=min{dw,cost(w,v)}.
代码如下:
#include<iostream> using namespace std; #define Inf 65535 #define NotAVerter -1 /////////////////////邻接表的相关定义////////////////////// typedef struct EdgeNode *position; typedef struct Led_table* Table; struct EdgeNode //边表结点 { int adjvex; // 邻接点域,存储该顶点对应的下标 int weight; // 对应边的权值 position next; // 链域,指向下一个邻接点 }; struct Led_table // 邻接表结构 { int data; //邻接表的大小 position *firstedge; //边表头指针,可以理解为数组 }; //////////////////////////邻接表相关函数定义/////////////// Table Creat_Lable (int MaxElements) //MaxElements参数为希望创建的节点数 { Table table1 = static_cast<Table> (malloc(sizeof(struct Led_table))); table1->data = http://www.mamicode.com/MaxElements;"out of space!!!"; } table1->firstedge = static_cast<position*>(malloc(sizeof(position)*(table1->data))); if (table1->firstedge == NULL) { cout << "out of space!!!"; } //给每个表头赋值,从0开始 for (int i = 0; i <= table1->data - 1; ++i) { table1->firstedge [i] = static_cast<position>(malloc(sizeof(EdgeNode))); //申请一个节点 if (table1->firstedge [i] == NULL) { cout << "out of space!!!"; } table1->firstedge [i]->adjvex = 0; table1->firstedge [i]->weight = 0; //此参数在此时没有意义 table1->firstedge [i]->next = NULL; } return table1; } void Insert (Table table1, int v, int w, int weig) //表示存在一条边为<v,w>,且权重为weig { position p = static_cast<position>(malloc(sizeof(EdgeNode))); //申请一个节点 if(p == NULL) { cout << "out of space!!!"; } p->adjvex = w; p->weight = weig; p->next = table1->firstedge [v]->next; table1->firstedge [v]->next = p; } void Double_Insert (Table table1, int v, int w, int weig) //无向边,双向插入 { Insert (table1, v, w, weig); Insert (table1, w, v, weig); } /////////////////////最小生成树Prim算法///////////////////////// typedef struct Prim_tree *Prim_node ; struct Prim_tree // { bool know; int dist; // 邻接点域,存储该顶点对应的下标 int path; // 对应边的权值 }; Prim_node Prim_init(Table table1, int start) //节点初始化 { Prim_node Node = static_cast<Prim_node>(malloc(sizeof(Prim_tree)*(table1->data))); if (Node == NULL) { cout << "out of space!!!"; } for(int i = 0; i != table1->data; ++i) { Node[i].know = false; Node[i].dist = Inf; Node[i].path = NotAVerter; } Node[start].dist = 0; //起点处的距离设为0 return Node; } void Prim_Algorithm (Table table1,Prim_node Node) //prim 算法 { int v; for (int j = 0; j != table1->data; ++j) { int zh = Inf; for (int i = 0; i != table1->data; ++i) //找路径最小且没有标记过的点 { if(!Node[i].know && zh > Node[i].dist ) //如果这个点是未知的,且距离比较小 { zh = Node[i].dist; v = i; } } Node[v].know = true; //标记这个点 position p = table1->firstedge [v]->next; while (p != NULL) // { if(!Node[p->adjvex].know && Node[p->adjvex].dist > p->weight ) { Node[p->adjvex].dist = p->weight; Node[p->adjvex].path = v; } p = p->next; } } } int main () { Table table_1 = Creat_Lable (7); //创建一个大小为7的邻接表 //根据图来为邻接表插入数据 Double_Insert (table_1, 0, 1, 2);Double_Insert (table_1, 0, 2, 4);Double_Insert (table_1, 0, 3, 1); Double_Insert (table_1, 1, 3, 3);Double_Insert (table_1, 1, 4, 10); Double_Insert (table_1, 2, 5, 5); Double_Insert (table_1, 3, 2, 2);Double_Insert (table_1, 3, 5, 8);Double_Insert (table_1, 3, 6, 4); Double_Insert (table_1, 4, 3, 7);Double_Insert (table_1, 4, 6, 6); Double_Insert (table_1, 6, 5, 1); Prim_node Node_1 = Prim_init(table_1, 0); //初始化节点 Prim_Algorithm (table_1,Node_1); for (int i = 0; i != table_1->data; ++i) { cout << Node_1[i].dist << endl; } return 0; }
与Dijkstra算法的代码类似,做点修改就好,该代码所用的例子就是上面的图,计算的结果也是那样的。
夜深了,,,
推荐一首歌《cry on my shoulder》
最小生成树--prim算法
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。