普利姆算法的测试数据如下:每行数据表示边的两个端点和权值
10 13
1 0 4
2 1 2
3 0 3
4 3 8
5 1 2
5 2 2
5 4 1
6 3 10
7 4 4
8 5 4
8 7 6
9 6 5
9 7 2
普利姆最小生成树算法:
/*
时间:2017.1.1
描述:普利姆算法求解最小生成树
*/
#include<iostream>
#include<climits>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<fstream>
#define INF INT_MAX
#define FILEINPUT 1
using namespace std;
typedef struct edgeNode
{
int from,to;
int cost;
}
EDGENODE;
void creatMatrix(int **AdjMatrix,int n,int e); //构建无向图的邻接矩阵
void printMatrix(int **AdjMatrix,int n); //输出图的邻接矩阵
void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start); //初始化边集
int chooseEdge(EDGENODE *edgeSet,int n,int index); //从候选边集中选取权重最小的边
void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to);//调整候选边集
void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start); //普利姆算法
void printMst(EDGENODE *edgeSet,int n); //输出最小生成树选举结果
int main()
{
//freopen("data.txt","r",stdin);
#if FILEINPUT //条件编译:输入重定向到文件(输入邻接矩阵数据)
ifstream fin("data.txt");
streambuf *strm_buf=cin.rdbuf();
cin.rdbuf(fin.rdbuf());
#endif
int i,n,e,start;
int **AdjMatrix; //存储邻接矩阵
EDGENODE *edgeSet; //存储最小生成树选的边集
cout<<"Enter the number of nodes and edges:"<<endl;
cin>>n>>e;
AdjMatrix=(int **)malloc(sizeof(int *)*n); //为邻接矩阵分配存储空间
for(i=0;i<n;i++)
AdjMatrix[i]=(int *)malloc(sizeof(int)*n);
edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*n); //为最小生成树边集合配存储空间
creatMatrix(AdjMatrix,n,e); //构建无向图的邻接矩阵
printMatrix(AdjMatrix,n); //输出图的邻接矩阵
#if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
cin.rdbuf(strm_buf);
#endif
while(1)
{
cout<<"Enter the start position of the Graph: ";
cin>>start;
primMst(AdjMatrix,edgeSet,n,start);
printMst(edgeSet,n);
}
#if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
fin.close();
#endif
return 0;
}
void creatMatrix(int **AdjMatrix,int n,int e)
{
int i,j,from,to,cost;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
AdjMatrix[i][j]=INF;
cout<<"<from----to----cost>"<<endl;
for(i=0;i<e;i++)
{
cin>>from>>to>>cost;
AdjMatrix[from][to]=cost;
AdjMatrix[to][from]=cost;
}
}
void printMatrix(int **AdjMatrix,int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
if(AdjMatrix[i][j]==INF)
cout<<setiosflags(ios::left)<<setw(6)<<"INF";
else
cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j];
cout<<endl;
}
}
void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start)
{
int i,index=0;
for(i=0;i<n;i++)
if(i!=start)
{
edgeSet[index].from=start;
edgeSet[index].to=i;
edgeSet[index].cost=AdjMatrix[start][i];
index++;
}
}
int chooseEdge(EDGENODE *edgeSet,int n,int index)
{
int minCost=INF,minPos,i;
for(i=index;i<n-1;i++)
if(edgeSet[i].cost<minCost)
{
minCost=edgeSet[i].cost;
minPos=i;
}
if(minCost==INF)
{
cout<<"The Graph is disconnected!"<<endl;
exit(1);//图不连通,程序结束
}
return minPos;
}
void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to)
{
int i,cost;
for(i=index;i<n-1;i++)
{
cost=AdjMatrix[to][edgeSet[i].to];
if(cost<edgeSet[i].cost)
{
edgeSet[i].cost=cost;
edgeSet[i].from=to;
}
}
}
void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start)
{
int iter,minPos,to;
EDGENODE edge;
initEdgeSet(AdjMatrix,edgeSet,n,start); //初始化边集合
for(iter=0;iter<n-1;iter++)
{
minPos=chooseEdge(edgeSet,n,iter); //从边集中选择取值最小边
edge=edgeSet[minPos]; //将选择的最小边edgeSet[iter]
edgeSet[minPos]=edgeSet[iter];
edgeSet[iter]=edge;
to=edgeSet[iter].to; //将选择的边结点加入U集合
modfiyEdgeSet(AdjMatrix,edgeSet,n,iter,to);//调整候选边结点
}
}
void printMst(EDGENODE *edgeSet,int n)
{
int index;
int totalCost=0;
for(index=0;index<n-1;index++)
{
cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl;
totalCost+=edgeSet[index].cost;
}
cout<<"totalCost: "<<totalCost<<endl;
}
克鲁斯科尔算法的测试数据:第一行表示图的顶点数和边数;从第二行开始表示表的顶点编号和权值
10 13
0 1 4
1 2 2
0 3 3
3 4 8
1 5 2
2 5 2
4 5 1
3 6 10
4 7 4
5 8 4
7 8 6
6 9 5
7 9 2
克鲁萨卡尔算法:
/*
时间:2017.1.1
描述:结合并查集实现克鲁斯卡尔算法求最小生成树
*/
#include<iostream>
#include<climits>
#include<iomanip>
#include<cstring>
#include<fstream>
#include<algorithm>
#define INF INT_MAX
#define FILEINPUT 1
using namespace std;
typedef struct edgeNode
{
int from,to;
int cost;
}
EDGENODE;
bool operator<(const EDGENODE &a,const EDGENODE &b)
{
if(a.cost!=b.cost)
return a.cost<b.cost;
else if(a.from!=b.from)
return a.from<b.from;
else
return a.to<b.to;
}
int flag[512];
void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e);
void printMatrix(int **AdjMatrix,int n);
void printEdgeSet(EDGENODE *edgeSet,int e);
void kruskalMst(EDGENODE *edgeSet,int n,int e);
int findRootEdge(int nodeNumber);
int mergeEdge(int nodeFrom,int nodeTo);
int main()
{
//freopen("data.txt","r",stdin);
#if FILEINPUT //条件编译:输入重定向到文件(输入邻接矩阵数据)
ifstream fin("data.txt");
streambuf *strm_buf=cin.rdbuf();
cin.rdbuf(fin.rdbuf());
#endif
int i,n,e;
int **AdjMatrix; //存储邻接矩阵
EDGENODE *edgeSet; //边集合
cout<<"Enter the number of nodes and edges:"<<endl;
cin>>n>>e;
AdjMatrix=(int **)malloc(sizeof(int *)*n); //为邻接矩阵分配存储空间
for(i=0;i<n;i++)
AdjMatrix[i]=(int *)malloc(sizeof(int)*n);
edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*e); //为边集合分配存储空间
for(i=0;i<n;i++) //初始化并查集
flag[i]=i;
creatMatrix(AdjMatrix,edgeSet,n,e);
printMatrix(AdjMatrix,n);
kruskalMst(edgeSet,n,e);
#if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
cin.rdbuf(strm_buf);
fin.close();
#endif
return 0;
}
void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e)
{
int i,j,from,to,cost;
EDGENODE edge;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
AdjMatrix[i][j]=INF;
cout<<"<from----to----cost>"<<endl;
for(i=0;i<e;i++)
{
cin>>from>>to>>cost;
AdjMatrix[from][to]=cost;
AdjMatrix[to][from]=cost;
edge.from=from;
edge.to=to;
edge.cost=cost;
edgeSet[i]=edge;
}
}
void printMatrix(int **AdjMatrix,int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(AdjMatrix[i][j]==INF)
cout<<setiosflags(ios::left)<<setw(6)<<"INF";
else
cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j];
}
cout<<endl;
}
}
void printEdgeSet(EDGENODE *edgeSet,int e)
{
int index=0;
for(index=0;index<e;index++)
cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl;
}
int findRootEdge(int nodeNumber)
{
int i,j,root;
root=nodeNumber;
while (flag[root]!=root) //循环结束,则找到同一边集中的最小结点编号
root= flag[root];
i=nodeNumber;
while(i!=root) //本循环修改查找路径中所有边结点编号
{
j=flag[i];
flag[i]=root;
i=j;
}
return root;
}
int mergeEdge(int nodeFrom,int nodeTo) //边结点合并到连通图中
{
int indexFrom=findRootEdge(nodeFrom);
int indexTo=findRootEdge(nodeTo);
if(flag[indexFrom]<flag[indexTo])
flag[indexTo]=indexFrom;
else
flag[indexFrom]=indexTo;
if(indexFrom==indexTo)
return 1;
else
return 0;
}
void kruskalMst(EDGENODE *edgeSet,int n,int e)
{
int index=0;
int countEdge=0;
int minCost=0;
//cout<<"------------------------------------"<<endl;
//printEdgeSet(edgeSet,e);
sort(edgeSet,edgeSet+e); //对边集进行快速排序
//cout<<"------------------------------------"<<endl;
//printEdgeSet(edgeSet,e);
//cout<<"------------------------------------"<<endl;
while(index<e)
{
int from=edgeSet[index].from;
int to=edgeSet[index].to;
int cost=edgeSet[index].cost;
if(mergeEdge(from,to)==0) //利用并查集判断环路,同时对查找路径进行压缩合并
{
countEdge++;
minCost+=cost;
cout<<"("<<from<<","<<to<<") "<<cost<<endl;
index++;
}
else
{
index++;
}
if(countEdge==n-1)
{
break;
}
}
if(index<e)
cout<<"minCost: "<<minCost<<endl;
else
{
cout<<"The Graph is disconnected!"<<endl; //index>=e则不能构造最小生成树
}
}