Prim算法学习总结及实现
Prim算法的核心思想就是在上一步确定的两个互斥点集A,B中找出一对可以形成边的点,并且这一对点构成的边应该是两个点集中可构成的边里权值最小的。
然后把这一条边加入边集E,并且把终点加入到A集合,从B集合中去掉。再重复,直到B集为空或者A集满。
具体来讲
1、设立点集A,只包括一个点,设立点集B,包括图中剩余的其他点
2、从点集A,B各选一点a,b 满足a-b边是所有点集A与点集B的点构成的边的权值最小的。把a-b边加入边集,把b从点集B中去掉,添加到点集A。
重复2,直到B点集为空或A点集满。
3、由边集即可构成一个最小生成树。
至于代码,实现方式不少,主要差异在如何体现AB点集。
我的数据结构书上是利用该点的一个标志位(是否被访问过)来标定属于A,B点集的。
下面放上我的代码,因为基本上是照书上打的,所以基本没有注释。
// Prim.cpp : 定义控制台应用程序的入口点。
// 作者:王锦
// 邮箱:jinksw@vip.qq.com
#include "stdafx.h"
#include <iostream>
using namespace std;
class Edge{//定义边类
public:
int from,to,weight;
Edge(){
from = -1;
to = -1;
weight = 0;
}
Edge(int from,int to,int weight){
this->from = from;
this->to = to;
this->weight = weight;
}
};
class EdgeInfo{//定义邻接表边界点内数据类
public:
int vertex;
int weight;
};
template<class T>
class Node{//定义结点类
public:
T element;
Node *next;
Node(const T&element, Node *next = NULL){
this->element = element;
this->next = next;
}
Node(Node *next = NULL){
this->next = next;
}
};
template<class T>
class HeadNode{//定义头结点类
public:
Node<T> *head;
HeadNode(){
head = new Node<T>();
}
};
const int UNVISITED = -1;//定义未访问标记常量
const int VISITED = 1;//定义已访问标记常量
const int INFINITY = 100000;//定义无穷大常量
class Graph{//图类定义
public:
int vertexNum;
int edgeNum;
int *mark;
int *indegree;
Graph(int vertexNum){
this->vertexNum = vertexNum;
edgeNum = 0;
mark = new int[vertexNum];
indegree = new int[vertexNum];
for(int i = 0;i < vertexNum;i++){
mark[i] = UNVISITED;
indegree[i] = 0;;
}
}
~Graph(){
delete[] mark;
delete[] indegree;
}
virtual Edge getFirstEdge(int vertex) = 0;//以下四个方法供子类覆写
virtual Edge getNextEdge(Edge e) = 0;
virtual void setEdge(int from,int to,int weight) = 0;
virtual void delEdge(int from, int to) = 0;
int toVertex(Edge e){
return e.to;
}
int fromVertex(Edge e){
return e.from;
}
int getWeight(Edge e){
return e.weight;
}
int getVertexNum(){
return vertexNum;
}
bool isEdge(Edge e){
if(e.weight > 0 && e.weight < INFINITY && e.to >= 0)
return true;
return false;
}
};
class ListGraph:public Graph{//邻接表图类定义
private:
HeadNode<EdgeInfo> * graList;
public:
ListGraph(int vertexNum):Graph(vertexNum){
graList = new HeadNode<EdgeInfo>[vertexNum];
}
Edge getFirstEdge(int vertex){
Edge e;
e.from = vertex;
Node<EdgeInfo> * temp = graList[vertex].head;
if(temp->next != NULL){
e.to = temp->next->element.vertex;
e.weight = temp->next->element.weight;
}
return e;
}
Edge getNextEdge(Edge e){
Edge nextEdge;
nextEdge.from = e.from;
Node<EdgeInfo> *temp = graList[e.from].head;
while(temp->next != NULL && temp->next->element.vertex <= e.to){
temp = temp->next;
}
if(temp->next != NULL){
nextEdge.to = temp->next->element.vertex;
nextEdge.weight = temp->next->element.weight;
}
return nextEdge;
}
void setEdge(int from,int to,int weight){
Node<EdgeInfo> *temp = graList[from].head;
while(temp->next != NULL && temp->next->element.vertex < to){
temp = temp->next;
}
if(temp->next == NULL){
Node<EdgeInfo> *newEdge = new Node<EdgeInfo>(NULL);
newEdge->element.vertex = to;
newEdge->element.weight = weight;
temp->next = newEdge;
edgeNum++;
indegree[to]++;
return;
}
if(temp->next->element.vertex > to){
Node<EdgeInfo> *tempNext = temp->next;
Node<EdgeInfo> *newEdge = new Node<EdgeInfo>(tempNext);
newEdge->element.vertex = to;
newEdge->element.weight = weight;
temp->next = newEdge;
edgeNum++;
indegree[to]++;
return;
}
if(temp->next->element.vertex == to){
temp->next->element.weight = weight;
return;
}
}
void delEdge(int from, int to){
Node<EdgeInfo> *temp = graList[from].head;
while(temp->next != NULL && temp->next->element.vertex < to){
temp = temp->next;
}
if(temp->next == NULL)
return;
if(temp->next->element.vertex > to)
return;
if(temp->next->element.vertex == to){
Node<EdgeInfo> *tempNext = temp->next->next;
delete temp->next;
temp->next = tempNext;
edgeNum--;
indegree[to]--;
return;
}
}
};
class Dist{//定义最短路径信息类
public:
int index;
int length;
int pre;
};
int minVertex(Graph &g,Dist * &d){
int v;
for(int i = 0;i < g.getVertexNum();i++){
if(g.mark[i] == UNVISITED){
v = i;
break;
}
}
for(int i = 0;i < g.getVertexNum();i++){
if(g.mark[i] == UNVISITED && d[i].length < d[v].length)
v = i;
}
return v;
}
void addEdgetoMst(Edge e,Edge *mst,int index){
mst[index] = e;
}
void prim(Graph& g,int s,Edge * &mst){
int mstNum = 0;
mst = new Edge[g.getVertexNum() - 1];
Dist *d;
d = new Dist[g.getVertexNum()];
for(int i = 0;i < g.getVertexNum();i++){
g.mark[i] = UNVISITED;
d[i].index = i;
d[i].length = INFINITY;
d[i].pre = s;
}
d[s].length = 0;
g.mark[s] = VISITED;
int v = s;
for(int i = 0;i < g.getVertexNum() - 1;i++){
if(d[v].length == INFINITY)
return;
for(Edge e = g.getFirstEdge(v);g.isEdge(e);e = g.getNextEdge(e)){
if(g.mark[g.toVertex(e)] != VISITED && (d[g.toVertex(e)].length > e.weight)){
d[g.toVertex(e)].length = e.weight;
d[g.toVertex(e)].pre = v;
}
}
v = minVertex(g,d);
g.mark[v] = VISITED;
Edge edge(d[v].pre,d[v].index,d[v].length);
addEdgetoMst(edge,mst,mstNum++);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
while(true){
cout << "----------------------------------------------------" << endl;
cout << "->请输入您要创建的图的结点个数." << endl;
int vertexNum = 0;
cin >> vertexNum;
ListGraph g(vertexNum);
cout << "->请输入图中所有点关联的边的起始点 终点 权重.输入-1结束" << endl;
cout << "->例:若输入0 3 5则表示插入一条边,边的起点为0,终点为3,权重为5" << endl;
cout << "->例:若输入-1则表示所有边已录入完毕" << endl;
int startVertex;
int endVertex;
int weight;
while(true){
cin >> startVertex;
if(startVertex == -1)
break;
cin >> endVertex;
cin >> weight;
g.setEdge(startVertex,endVertex,weight);
g.setEdge(endVertex,startVertex,weight);
}
Edge *mst;
prim(g,0,mst);
cout << "->最小生成树的边集为:" << endl;
for(int i = 0;i < g.getVertexNum() - 1;i++){
cout << mst[i].from << " " << mst[i].to << " " << mst[i].weight << endl;
}
cout << "----------------------------------------------------" << endl;
}
}
浙公网安备 33010602011771号