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;
	}
}

 

 

posted @ 2013-05-24 04:48  Jinks  阅读(819)  评论(0编辑  收藏  举报