算法导论 第二十三章:最小生成树

如下无向图G=(V,E),首先确定几个概念:

割(Cut): 如果无向图(u,v)∈E的一端点属于S,而另一个端点属于V-S时,则称(u,v)通过割(S,V-S)

轻边(Light edge): 如果某条边的权值是通过一个割的所有边中最小的,则称该边为通过这个割的一条轻边。

安全边(Safe edge): 如果一条边(u,v)能够加入集合A中而不违反循环不变式,则该边称为安全边。也即A∪(u,v)也是最小生成树的子集


Kruskal算法

伪代码:


Prim算法

伪代码:

Prim算法运行时间:

采用不同的数据结构,其运行时间不同,具体如下:

  TExtract-MinTDecrease-Key    Total
Queue    O(V)     O(1) O(V²)
Binary Heap     Θ(lgV)     O(lgV) O(ElgV)
Fibonacci
Heap
     O(lgV)     O(1) O(E+VlgV)


================================================================================================================================

Kruskal算法完整代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<vector>
using namespace std;

#define N 256

typedef char vType;
typedef struct setNode{
	vType key;
	int rank;
	setNode *parent;
	setNode(vType k):key(k),rank(0),parent(NULL){}
	}setNode;

typedef struct edge{
	vType u;
	vType v;
	int weight;  
	}edge;

typedef struct Graph{
	int vNum;
	int eNum;
	vType *V;
	edge *E;
	}Graph;


setNode *Make_Set(vType k)
{
	setNode *x = new setNode(k);
	x->parent = x;
	return x;
	}

setNode *Find_Set(setNode *x)
{
	if(x != x->parent)
		x->parent=Find_Set(x->parent);
	return x->parent;
	}
void Link(setNode *x,setNode *y)
{
	if(x->rank > y->rank)
		y->parent = x;
	else
 	 { 
		x->parent = y;
		if(x->rank == y->rank)
			y->rank = y->rank + 1;
		}
	}
void Set_Union(setNode *x,setNode *y)
{
	Link(Find_Set(x),Find_Set(y));
	setNode *z=Find_Set(x);
	}
void Graph_Init(Graph &G, vType *Vertex,edge *Edge)
{
	G.V=new vType[G.vNum];
	G.E=new edge[G.eNum];
	for(int i=0; i<G.vNum; i++)
		G.V[i] = Vertex[i];
	for(int i=0; i<G.eNum; i++)
		G.E[i] = Edge[i];

	}
/*-------------------------Kruskal Algorithm-----------------------------*/
bool compare(const edge &a, const edge &b)
{
	return a.weight < b.weight;    //sort in nondecreasing order by weight
	}

vector<edge> Graph_MST_Kruskal(Graph &G)
{
	vector<edge> A;
	A.clear();   //clear the vector

	//make the vertex of Graph become node set
	setNode *vSet[N];
	for(int i=0; i<G.vNum; i++)
	{  
		vType v = G.V[i];
		vSet[(int)v] = Make_Set(v);   //the stored index is ASCII,Eg,a:97
 	 	}

	//sort the edge of G.E into nondecreasing order by weight
	sort(G.E,G.E+G.eNum,compare);
	
	//considering every edge
	for(int i=0; i<G.eNum; i++)
	 { 
		edge e = G.E[i];
		setNode *uNode = vSet[(int)e.u];
		setNode *vNode = vSet[(int)e.v];
		if(Find_Set(uNode) != Find_Set(vNode))
	 	{ 
			A.push_back(e);
			Set_Union(uNode ,vNode);

		 	}
		}  
	return A;
	}
void MST_Print(vector<edge> A)
{
	for(int i=0; i<A.size(); i++){
		edge etemp = A[i];
		cout<<etemp.u<<"   "<<etemp.v<<"   "<<etemp.weight<<endl;
		} 
	}
/*-----------------------------------------------------------------------*/

int main()
{
	vType vertex[]={'a','b','c','d','e','f','g','h','i'};
	 edge edgeArray[]={{'a','b',4},{'a','h',8},{'b','c',8},
					  {'b','h',11},{'h','i',7},{'h','g',1},
					  {'i','c',2},{'i','g',6},{'c','d',7},
					  {'c','f',4},{'g','f',2},{'d','f',14},
					  {'d','e',9},{'e','f',10}
	                  };	
	Graph G;
	G.vNum=sizeof(vertex)/sizeof(vType);
	G.eNum=sizeof(edgeArray)/sizeof(edge);
	Graph_Init(G,vertex,edgeArray);
	cout<<"The MST is(Kruskal Algorithm):"<<endl;
	vector<edge> mstResult;
	mstResult = Graph_MST_Kruskal(G);
    MST_Print(mstResult);
	return 0;
	}
运行结果:


Prim算法完整代码:

#include<iostream>
#include<climits>
#include<cstdlib>
#include<queue>
#include<vector>
#include<functional>
using namespace std;

#define UDG 0
#define DG  1

typedef char vType;
typedef struct gEdge{
	vType adjVertex;   //the adjacency vertex pointed by this edge.
	int weight;        //the weight of this edge
	gEdge *nextEdge;   //Point to the next edge
	}gEdge;

typedef struct gVertex{
	vType key;         // the key of the vertex
	int flag;          // denote the flag infomation,when excuting
	vType parent;   // the key of parent node
	gEdge *firstEdge;  // point to the first edge attached to the vertex;
	}gVertex;
typedef struct ALGraph{
	int vNum;
	int eNum;
	int kind;   //the kind of Graph 
	gVertex *HeadVertex;	
	}ALGraph;

typedef struct edge{
	vType start;
	vType end;
	int weight;
	}edge;

int Locate(ALGraph &G,vType s)
{//locate the start vertex of one edge in head vertex of the graph
	for(int i=0;i<G.vNum;i++)
		if(G.HeadVertex[i].key == s)
			return i;
	return -1;
	}
void LinkEdgeToGraph(ALGraph &G, edge e)
{//add edge to head vertex
		gEdge *arc=new gEdge();
		arc->adjVertex=e.end;
		arc->weight = e.weight;

		int headV_i=Locate(G,e.start);	
		arc->nextEdge=G.HeadVertex[headV_i].firstEdge;
		G.HeadVertex[headV_i].firstEdge = arc;
	}
void Graph_Create(ALGraph &G, vType V[], edge E[])
{
	//init the head vertex
	G.HeadVertex= new gVertex[G.vNum];
	for(int  i=0;i<G.vNum; i++){
		G.HeadVertex[i].key=V[i];
		G.HeadVertex[i].firstEdge=NULL;
	} 

	//add edge to head vertex in order to create a graph
	if(G.kind == DG) //undirected graph
		for(int i=0; i<G.eNum; i++)
			LinkEdgeToGraph(G,E[i]);
	if(G.kind == UDG) // directed graph
		for(int i=0; i<G.eNum; i++)
 		{ 
			LinkEdgeToGraph(G,E[i]);
			// link again after reversed
			edge temp;
			temp.start = E[i].end;
			temp.end   = E[i].start;
			temp.weight = E[i].weight;
			LinkEdgeToGraph(G,temp);
 			} 
	}
void Graph_Print(ALGraph G)
{
	for(int i=0; i<G.vNum; i++)
	{
		cout<<G.HeadVertex[i].key;
		gEdge *e = G.HeadVertex[i].firstEdge;
		while(e != NULL)
 		{
			cout<<" -->"<<"("<<e->weight<<")"<< e->adjVertex;
			e = e->nextEdge;
 		 	}
		cout<<endl;
 	 	} 
	}
/*-----------------------Prim's Algorithm--------------------------*/
struct cmp{
	bool operator()(gVertex *a,gVertex *b){
		return a->flag > b->flag;
 		} 
	};

void Queue_Print( priority_queue<gVertex*,vector<gVertex*>,cmp> que)
{//Print Queue
	cout<<"The queue is:"<<endl;
	while(!que.empty()){ 
		gVertex *u = que.top();
		cout<<u->key<<"   "<<u->flag<<endl;
		que.pop();
		}
	}

bool isContain(priority_queue<gVertex*,vector<gVertex*>,cmp> q,gVertex *v)
{//judge whether the node v is contained by the queue  
	while(!q.empty()){    
		if(v->key == q.top()->key)
			return true;
		q.pop();
		}
	return false;
	}
gVertex *QElement_Reset(priority_queue<gVertex*,vector<gVertex*>,cmp> q,gVertex *v)
{//return the pointer of a node in queue 
	while(!q.empty()){   
		if(v->key == q.top()->key)
			return q.top();
		q.pop();
	 	}
	}
void Graph_MST_Prim(ALGraph &G, vType s)
{//Prim's Algorithm

	//init every vertex node
	for(int i=0; i<G.vNum; i++)
	{  
		gVertex *u = &G.HeadVertex[i];
		u->flag = INT_MAX;
		u->parent= '0';
	 	}
	//init the string vertex node
	int s_i=Locate(G,s);
	gVertex *sNode = &G.HeadVertex[s_i];
	sNode->flag = 0;

	//init minmum priority queue
	priority_queue<gVertex *,vector<gVertex *>,cmp> Q;
	for(int i=0; i<G.vNum; i++)
		Q.push(&G.HeadVertex[i]);
	//add adjacency vertex
	while(!Q.empty())
	{
		gVertex *uNode = Q.top(); Q.pop(); //extarct the minimum node in the queue

		//consider each adjecency node v
		int u_i = Locate(G,uNode->key);
		gEdge *e = G.HeadVertex[u_i].firstEdge;
		while(e)
	 	{  
			vType v = e->adjVertex;
			int v_i = Locate(G,v);
			gVertex *vNode = &G.HeadVertex[v_i];
			if(isContain(Q,vNode) && e->weight < vNode->flag)
		  	{//the node v is in the queue and the weight of edge is less than the flag of the node v
				//modify the information of the node
				vNode = QElement_Reset(Q,vNode); 
				vNode->parent = uNode->key;
				vNode->flag = e->weight;
				//resort the queue Q
				priority_queue<gVertex *,vector<gVertex *>,cmp> tQ;
				while(!Q.empty()){
					tQ.push(Q.top());
					Q.pop();
		 			}
				Q = tQ;
		 		}

			e = e->nextEdge;
	 	 	}	  
	 	}  
	}

void MSTPrim_Print(ALGraph G)
{
	cout<<"The MST(Prim) is:"<<endl;
	for(int i=0; i<G.vNum; i++)
	{
		gVertex *u = &G.HeadVertex[i];
		cout<<u->parent<<"  "<<u->key<<": "<<u->flag<<endl;
		} 
	}
int main()
{
	vType vertex[]={'a','b','c','d','e','f','g','h','i'};
 	 edge edgeArray[]={{'a','b',4},{'a','h',8},{'b','c',8},
					  {'b','h',11},{'h','i',7},{'h','g',1},
					  {'i','c',2},{'i','g',6},{'c','d',7},
					  {'c','f',4},{'g','f',2},{'d','f',14},
					  {'d','e',9},{'e','f',10}
	                  };	 
	ALGraph G;
	G.vNum=sizeof(vertex)/sizeof(vType);
	G.eNum=sizeof(edgeArray)/sizeof(edge);
	G.kind=UDG;
	Graph_Create(G,vertex,edgeArray);
	cout<<"----------------Create Graph------------------"<<endl;
	cout<<"The created graph is:"<<endl;
	Graph_Print(G);
	cout<<"----------------Prim Algorithm----------------"<<endl;
	vType s;
	cout<<"Please input the starting position:";
	cin>>s;
	Graph_MST_Prim(G,s);
	MSTPrim_Print(G);
	cout<<"-----------------------------------------------"<<endl;
	return 0;
	}

运行结果:




【注:若有错误,请指正~~~】


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值