如下无向图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-Min | TDecrease-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;
}
运行结果:
【注:若有错误,请指正~~~】