补上今天刚写完,并通过运行的最下生成树的类的实现,觉得数据结构很多的算法都是比划着简单,实现难啊...
共享一下我刚通过运行的程序,大家参考:
#ifndef MINSPANHEAP_H
#define MINSPANHEAP_H
#include<iostream.h>
#include<stdlib.h>
#include"Graphlink.h"
#include"Graphmtx.h"
#include"MinHeap.h"
#include"UFSet.h"
const float maxValue=10000;
const int defaultsize=30;
//////////////////////////////////////////////////
//MSTEdgeNode结构 最小生成树边结点的声明
//本最小生成树采用边的集合进行表示
//////////////////////////////////////////////////
template<class T,class E>
struct MSTEdgeNode
{
int head; //边的一个端点
int tail; //边的另一个端点
E weight; //当前边权值
MSTEdgeNode() //默认构造函数
{head=-1;tail=-1;weight=0;};
/*以下重载关系运算符*/
bool operator>(MSTEdgeNode<T,E>& Node)
{return weight>Node.weight;};
bool operator>=(MSTEdgeNode<T,E>& Node)
{return weight>=Node.weight;};
bool operator<(MSTEdgeNode<T,E>& Node)
{return weight<Node.weight;};
bool operator<=(MSTEdgeNode<T,E>& Node)
{return weight<=Node.weight;};
bool operator==(MSTEdgeNode<T,E>& Node)
{return weight==Node.weight;};
};
///////////////////////////////MSTEdgeNode结构结束
//////////////////////////////////////////////////
//MinSpanTree类模 最小生成树的实现
//T是顶点数据域的类型,E是边的权值的数据类型
//////////////////////////////////////////////////
template<class T,class E>
class MinSpanTree
{
protected:
MSTEdgeNode<T,E>* EdgeValue; //边集合数组
int maxSize; //边集合数组
int currentSize; //当前数组的长度
public:
MinSpanTree(int sz=defaultsize) //构造函数
{
maxSize=sz;currentSize=0; //初始化数据成员
EdgeValue=new MSTEdgeNode<T,E>[maxSize];
if(EdgeValue==NULL)
{
cout<<"内存分配失败!"<<endl;
exit(1);
};
};
~MinSpanTree() //析构函数
{delete [] EdgeValue;};
bool Insert(MSTEdgeNode<T,E>& Node);//把一条边插入到当前的生成树中
void Cruskal(Graph<T,E>& G); //Cruskal算法:通过图G来构造当前的最小生成树
void Prim(Graph<T,E>& G,int start); //Prim算法:通过图G来构造当前的最小生成树
//友元重载<<输出运算符输出当前的最小生成树
friend ostream& operator<<(ostream& os,MinSpanTree<T,E>& MST);
};
/////////////////////////////////MinSpanTree类模板
//////////////////////////////////////////////////
//Insert()公有成员函数
//在当前的最小生成树中插入一条边,插入成功返回true
//////////////////////////////////////////////////
template<class T,class E>
bool MinSpanTree<T,E>::Insert(MSTEdgeNode<T,E>& Node)
{
if(currentSize==maxSize)
{
cout<<endl
<<"当前的最小生成树的空间已经满了!"
<<endl;
return false;
};
//把边插入其中
EdgeValue[currentSize]=Node;
currentSize++;
return true;
};
//////////////////////////Insert()公有成员函数结束
//////////////////////////////////////////////////
//Cruskal()公有成员函数
//利用克鲁斯卡尔算法通过当前图来构造一棵最小生成树
//即所谓的贪心算法,每次都取剩下的最大或者最小,但
//该边两个的顶点不能在同一连通分量中,反复迭代
//参数采用的是图的基类Graph<T,E>,在具体运行的
//时候可以实现基类动态向子类的类型转换
//////////////////////////////////////////////////
template<class T,class E>
void MinSpanTree<T,E>::Cruskal(Graph<T,E>& G)
{
/*首先把所有的边按照权值放入最小堆中*/
int numEdges=G.NumberOfEdges(); //得到图G的边的条数
MinHeap<int,MSTEdgeNode<T,E> >MH(numEdges);//依照图的边数定义最小堆
MSTEdgeNode<T,E> Edge; //边结点变量
for(int u=0;u<numEdges;u++) //无重复地遍历所有的边
{
for(int v=u+1;v<numEdges;v++) //把边压入最小堆
{
int cost=G.getWeight(u,v); //获取边(u,v)的权值
if(cost>0 && cost<maxWeight) //如果该边存在且有效
{
Edge.head=u; //初始化边结点内容
Edge.tail=v;
Edge.weight=cost;
MH.Insert(Edge); //把该边加入到最小堆中
};
};
};
/*从对中取出不在同一连通分量中的最小边插入堆中的迭代过程*/
int numVertices=G.NumberOfVertices(); //获得图中的当前顶点的个数
UFSet UF(numVertices); //用于判断是否在同一个连同分量的并查集
int count=1;
while(count<=numVertices-1) //从堆中逐个取出权值最小的边
{
MH.RemoveMin(Edge); //从最小堆中取出一条最小边
u=UF.findRoot(Edge.head); //找u所在集合的根结点
int v=UF.findRoot(Edge.tail); //找v所在集合的根结点
if(u!=v) //如果Edge的两个端点不在一个连通分量
{
Insert(Edge); //把该边插入到最小生成树中去
count++;
UF.Union(u,v); //把u,v两个集合合并,连接两个分裂的连通分量
};
};
};
/////////////////////////////Cruskal()公有函数结束
//////////////////////////////////////////////////
//Prim()公有成员函数
//通过Prim算法实现把图G得到相应的最小生成树
//每次从某个结点出发,把与最小生成树中结点相关联的
//权值最小的边找出来,并加入最小生成树,反复迭代
//其中start是起始结点
//////////////////////////////////////////////////
template<class T,class E>
void MinSpanTree<T,E>::Prim(Graph<T,E>& G,int start)
{
int numVertices=G.NumberOfVertices(); //得到图当前所有顶点数
bool* vmst=new bool[numVertices]; //用于标记已经加入生成树的结点
for(int i=0;i<numVertices;i++) //初始化为未加入
vmst[i]=false;
vmst[start]=true; //先把start加入最小生成树
MinHeap<int,MSTEdgeNode<T,E> >
MH(G.NumberOfEdges()); //迭代过程中用于求权值最小的边的堆栈
MSTEdgeNode<T,E> Edge; //一个最小生成树的结点变量
int p=start; //新加入最小生成树的那个顶点
int count=1; //迭代计数器,一共要迭代n-1次
do
{
/*把新结点加入生成树的顶点集合中*/
vmst[p]=true;
/*把与新结点相关的并且另一个顶点不
在生成树中的边加入最小堆*/
int n=G.getFirstNeighbor(p); //先获取结点p的第一个邻接
while(n!=-1) //遍历所有的邻接结点
{
if(vmst[n]!=true) //如果邻接点n不在生成树中
{ //把该边加入最小堆
Edge.head=p; //生成树内的结点
Edge.tail=n; //生成树外的结点
Edge.weight=G.getWeight(p,n);
MH.Insert(Edge); //把该边加入最小堆
};
n=G.getNextNeighbor(p,n); //获取下个邻接结点
};
/*从堆中取出权值最小的边加入到生成树中去*/
do
{
MH.RemoveMin(Edge); //取出最小边
if(vmst[Edge.tail]!=true) //如果另一个结点不在生成树中
{
Insert(Edge); //把该边插入生成树
count++; //加入边的条数的计数器
break;
};
}
while(!MH.IsEmpty());
p=Edge.tail;
}
while(count<=numVertices-1);
};
////////////////////////////Prim()公有成员函数结束
//////////////////////////////////////////////////
//友元重载<<输出运算符输出当前的最小生成树
//////////////////////////////////////////////////
template<class T,class E>
ostream& operator<<(ostream& os,MinSpanTree<T,E>& MST)
{
cout<<"当前的最小生成树的边集合是:"<<endl;
for(int i=0;i<MST.currentSize;i++)
{
cout<<"("<<MST.EdgeValue[i].head //输出边的一端
<<","<<MST.EdgeValue[i].tail //输出边的另一端
<<","<<MST.EdgeValue[i].weight
<<")"<<endl; //输出该边的权值
};
return os;
};
////////////////////////////////////<<友元重载结束