无向图的最小支撑树Kruskal算法的实现

//                                 无向图的最小支撑树Kruskal算法的实现
//主题: 用邻接表的方式实现最小支撑树Kruskal算法

//作者:Andyhou

//时间:2008年4月28日

//具体算法实现:
//            采用的是最小堆的方式找最小边,用等价类的方式步步合并最小的边。
//            程序中还声明了一个等价类。
#include <iostream>
using namespace std;

const int MaxNode=100;
const int VISITED=1;
const int UNVISITED=0;
const int ROOT=-1;
const int INFINITY=9999;

struct Node
{
 int adjvex;           //终点顶点
 int weight;           //权
 struct Node *next;    //指向下个顶点的指针
};
class VNode
{
public:
 int data;
 struct Node* first;    //指向第一个邻接顶点
 VNode(){}
 VNode(int Data,struct Node* firstVal)
 {
  data=Data;
  first=firstVal;
 }
 VNode(struct Node* firstVal)
 {
  first=firstVal;
 }
 
};
//用于最小支撑树的边类
class Edge
{
public:
 int from,to,weight;
 Edge()
 {
  from=-1;
  to=-1;
  weight=0;
 }
 Edge(int f,int t,int w)
 {
  from=f;
  to=t;
  weight=w;
 }
 bool operator>(Edge oneEdge)
 {
  return weight>oneEdge.weight;
 }
 bool operator<(Edge oneEdge)
 {
  return weight<oneEdge.weight;
 }
 bool operator==(Edge oneEdge)
 {
  return weight==oneEdge.weight;
 }
};

//用于”父指针"发表示等价类的类
class Gentree
{
private:
 int *Array;
 int size;
public:
 Gentree(int sz)
 {
  size=sz;
  Array=new int[sz+1];
  for(int i=1;i<=sz;i++)
   Array[i]=ROOT;       //整个数的根节点
 }
 ~Gentree()
 {
  delete[] Array;
 }
 int FIND(int curr)       //寻找根的函数
 {
  while(Array[curr]!=ROOT)
   curr=Array[curr];
  return curr;
 }
 void UNION(int a,int b)  //将a和b合并到一个等价类中,a和b在一个等价类中就他们相同的根。
 {
  int root1=FIND(a);
  int root2=FIND(b);
  if(root1!=root2)
   Array[root2]=root1;
 }
 bool differ(int a,int b)  //判断a和b是否等价。
 {
  int root1=FIND(a);
  int root2=FIND(b);
  return root1!=root2;
 }
};


//最小值堆的建立
template <class T>
class MinHeap 
{
private:
 T* heapArray;
 int CurrentSize;
 int MaxSize;
 
public:
 MinHeap(const int n);
 virtual ~MinHeap()
 {delete []heapArray;};
 void BuildHeap();
 bool isLeaf(int pos) const;
 int leftchild(int pos) const;
 int rightchild(int pos) const;
 // Return parent position
 int parent(int pos) const;
 // 删除给定下标的元素
 bool Remove(int pos, T& node);
 void SiftDown(int left);
 //从position向上开始调整,使序列成为堆
 void SiftUp(int position);
 bool Insert(const T& newNode);
 T& RemoveMin();
 bool empty()
 {
  if(CurrentSize>0)
   return false;
  else
   return true;
 }
};

template<class T>
MinHeap<T>::MinHeap(const int n)
{
 if(n<=0)
  return;
 CurrentSize=0;
 MaxSize=n;
 heapArray=new T[MaxSize];
 BuildHeap();
}

template<class T>
void MinHeap<T>::BuildHeap()
{
 for (int i=CurrentSize/2-1; i>=0; i--)
  SiftDown(i);
}

template<class T>
bool MinHeap<T>::isLeaf(int pos) const
{
  return (pos>=CurrentSize/2)&&(pos<CurrentSize);
}

template<class T>
int MinHeap<T>::leftchild(int pos) const
{
 return 2*pos+1;      //返回左孩子位置
}

template<class T>
int MinHeap<T>::rightchild(int pos) const
{
 return 2*pos+2;      //返回右孩子位置
}

template<class T>
int MinHeap<T>::parent(int pos) const // 返回父节点位置
{
 return (pos-1)/2;
}

template<class T>
void MinHeap<T>::SiftDown(int left)
{
 //准备
 int i=left;       //标识父结点
 int j=2*i+1;      //标识关键值较小的子结点  
 T temp=heapArray[i];    //保存父结点
 //过筛
 while(j<CurrentSize)
 {
  if((j<CurrentSize-1)&&(heapArray[j]>heapArray[j+1]))
   j++;      //j指向右子结点
  if(temp>heapArray[j])
  {
   heapArray[i]=heapArray[j];
   i=j;
   j=2*j+1;
  }
  else break;
 }
 heapArray[i]=temp;
}

template<class T>
void MinHeap<T>::SiftUp(int position)
{//从position向上开始调整,使序列成为堆
 int temppos=position;
 T temp=heapArray[temppos];
 while((temppos>0)&&(heapArray[parent(temppos)]>temp))
 {
  heapArray[temppos]=heapArray[parent(temppos)];
  temppos=parent(temppos);
 }
 heapArray[temppos]=temp;
}

template<class T>
bool MinHeap<T>::Insert(const T& newNode)
{//向堆中插入一个结点
 if(CurrentSize==MaxSize)
  return false;
 heapArray[CurrentSize]=newNode;
 SiftUp(CurrentSize);
 CurrentSize++;
 return true;
}

template<class T>
T& MinHeap<T>::RemoveMin()
{
 if(CurrentSize==0)
 {
  cout<<"Can't Delete";

 }
 else
 {
  T temp=heapArray[0];     //取堆顶元素
  heapArray[0]=heapArray[CurrentSize-1]; //堆末元素上升至堆顶
  CurrentSize--;
  if(CurrentSize>1)
   SiftDown(0);      //从堆顶开始筛选
  return temp;
 }
}

template<class T>
bool MinHeap<T>::Remove(int pos, T& node)
{// 删除给定下标的元素
 if((pos<0)||(pos>=CurrentSize))
  return false;
 T temp=heapArray[pos];
 heapArray[pos]=heapArray[--CurrentSize]; //指定元素置于最后
 SiftUp(pos);        //上升筛
 SiftDown(pos);        //向下筛 
 node=temp;
 return true;
}

class ADJ
{
private:
 int e;                             //边数
 VNode *AdjList;                    //邻接表
 int NNode;                         //顶点数
 int MARK[MaxNode];                //访问标记数组
public:
 ADJ(int itE,int itMaxNode)
 {
  e=itE;
  NNode=itMaxNode;
  AdjList=new VNode[NNode+1];
  for(int i=0;i<NNode;i++)
  {
   AdjList[i].data=0;
   AdjList[i].first=NULL;
  }
 }
 ~ADJ()
 {
  delete[] AdjList;
 }
 void CreateAdj()
 {
  int i,j;
        int item;
  struct Node* S;
  for(int a=1;a<=NNode;a++)
  {
   cout<<"输入第"<<a<<"个顶点数据";
   cin>>AdjList[a].data;
   AdjList[a].first=NULL;
  }
  for(int k=0;k<e;k++)
  {
   cout<<"输入边<Vi,Vj>的顶点对序列号:";
   cin>>i;
   cin>>j;
   cout<<"输入边的权:";
   cin>>item;
            S=new struct Node();
   S->adjvex=j;
   S->weight=item;
   S->next=AdjList[i].first;   
   AdjList[i].first=S;          //连接两个顶点
   S=new struct Node();
   S->adjvex=i;
   S->weight=item;
   S->next=AdjList[j].first;
   AdjList[j].first=S;
  }
 }
 
 void printAll()
 {
  cout<<"打印所有顶点的连接情况;"<<endl;
  for(int i=1;i<=NNode;i++)
  {
   struct Node* temp=AdjList[i].first;
   cout<<i;
   cout<<"("<<AdjList[i].data<<")";
   if(temp!=NULL)
    cout<<"---"<<temp->weight<<"-->";
   while(temp!=NULL)
   {
    cout<<temp->adjvex;
    cout<<"("<<AdjList[temp->adjvex].data<<")"<<"--"<<temp->weight<<"-->";
    temp=temp->next;
   }
   cout<<"---->NULL";
   cout<<endl;
  }
  cout<<"输出了所有数据!"<<endl;
 }
 void AddEdgetoMST(Edge &E,Edge *MST,int tag)
 {
  MST[tag].from=E.from;
  MST[tag].to=E.to;
  MST[tag].weight=E.weight;
 }
 void Krushal();
 
};
void ADJ::Krushal()
{
 Gentree A(NNode);               //等价类
 MinHeap<Edge> H(e);             //最小值堆
 struct Node *temp;
 Edge * MST=new Edge[NNode-1];   //最小支撑树
 int MSTtag=1;                   //最小支撑树的边的标记 
 Edge Ne;
 for(int i=1;i<=NNode;i++)        //将图的所有边插入最小值堆H中
 {
  temp=AdjList[i].first;
  while(temp!=NULL)
  {
   if(i<temp->adjvex)      //因为是无向图,所有应防止重复插入
   {
    Ne.from=i;
    Ne.to=temp->adjvex;
    Ne.weight=temp->weight;
    H.Insert(Ne);
   }
   temp=temp->next;
  }
 }
 int EquNum=NNode;     //开始有|V|个等价类
 while(EquNum>1)          //合并等价类
 {
   Ne=H.RemoveMin();    //获得下一条权最小的边
   if(Ne.weight==INFINITY)
   {
    cout<<"不存在最小支撑树:";
    delete[] MST;
    MST=NULL;
    return ;
   }
   int from=Ne.from;           //纪录该条边的信息
   int to=Ne.to;
   if(A.differ(from,to))       //如果边Ne的两个顶点不在一个等价类
   {
    A.UNION(from,to);        //将边Ne的连个顶点在的两个等价类合并为一个
    AddEdgetoMST(Ne,MST,MSTtag++);  //将边e加到MST
    EquNum--;                       //将等价类的个数减1
   }
 }
 cout<<"输出无向图的最小支撑树的边和权:";
 for(int i=1;i<NNode;i++)
  cout<<MST[i].from<<"--"<<MST[i].to<<"("<<MST[i].weight<<")/t";
 cout<<endl;
}


int main()
{
 int E,MaxNode;
 cout<<"输入无向图的顶点数和边数::";
 cin>>MaxNode>>E;
 ADJ T(E,MaxNode);
 T.CreateAdj();
 T.printAll();
 cout<<endl;
 cout<<"Kruskal算法的执行:"<<endl;
 T.Krushal();
 return 0;
}

注:本程序在VC2005中编译成功的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值