Prime算法求最小生成树 (最小堆优化)

/*
  Name: Prime算法求最小生成树 (最小堆优化)
  Copyright: 
  Author: 巧若拙 
  Date: 28-02-17 08:43
  Description: 实现了 Prime算法求最小生成树 (邻接矩阵)的最小堆优化算法。 
*/
#include<iostream>

using namespace std;

const int MAX=2000;   //最大顶点数量 
const int INFINITY=999999;   //无穷大 
int map[MAX][MAX] = {0};//邻接矩阵存储图信息 

class Vertex //图的结点类  
{
    public:
	    //void PrintVertex() {printf("(%d, %d) = %d", from, pos, dis);}
        void SetVertex(int p, int d, int f) {pos = p; dis = d; from = f;}
    	void SetDis(int d) {dis = d;}
	    void SetFrom(int f) {from = f;}
	    int GetPos() {return pos;}
	    int GetDis() {return dis;}
	    int GetFrom() {return from;}
	    friend bool operator >(const Vertex &op1, const Vertex &op2) {return op1.dis > op2.dis;}
	    friend bool operator <(const Vertex &op1, const Vertex &op2) {return op1.dis < op2.dis;}
	    Vertex operator =(const Vertex &op) {pos = op.pos; dis = op.dis; from = op.from; return *this;}
    private:
        int pos;//存储顶点序号 
	    int dis;  //存储顶点到最小生成树的距离
	    int from; //入树介绍人       
};

template <typename type> class MinHeap //一个简化的最小堆类  
{
	public:
		   MinHeap(int maxSize); //创建一个容量为maxSize的空堆
		   bool IsEmpty() const {return size == 0;}
		   bool IsFull() const {return size == capacity;}
		   type GetMin() const {return heap[0];} //返回堆顶的最小元素 
		   bool Insert(const type &x); //将x插入到最小堆
		   bool DeleteMin(); //删除堆顶的最小元素
		   bool Change(const type &x, int i); //修改下标为i处元素的值,并调整堆  
		   int Length() const {return size;} //返回堆的大小 
		   type GetNode(int i) const {return heap[i];} 
		      
	private:
			type *heap;   //存放堆的元素的数组 
			int capacity; //堆的容量 
			int size;     //堆的长度,即当前元素个数 
			
			void FilterDown(int i); //从下标i到m自顶向下进行调整成为最小堆
			void FilterUp(int i); //从下标i到0自底向上进行调整成为最小堆	
};

template <typename type> MinHeap<type>::MinHeap(int maxSize)
{
    capacity = maxSize;
    heap = new type[capacity];
    size = 0;
}

template <typename type> void MinHeap<type>::FilterDown(int i) //从下标i到堆的尾部自顶向下进行调整成为最小堆
{
    type t = heap[i];   //保存heap[i]的值以备放到适合的位置 
    int child = i * 2 + 1; //指向左孩子   
    
    while (child < size) //有左孩子 
    {
 	    if (child+1 < size && heap[child+1] < heap[child]) //有右孩子,且右孩子更小些,定位其右孩子   
            child += 1;  
          
        if (heap[child] < t)//用最小值覆盖其父亲结点的值,即将空位下滤到新的位置 
        {  
      	    heap[i] = heap[child];      
  		    i = child; 
  		    child = i * 2 + 1;
        }  
        else  
            break;  
	}
    
    heap[i] = t;
}

template <typename type> void MinHeap<type>::FilterUp(int i) //从下标i到0自底向上进行调整成为最小堆
{
    type t = heap[i];
    
    while (i > 0 && heap[i/2] > t) //若比父亲结点小,则用父亲结点的值覆盖该结点,即将空位上滤到新的位置 
    {
        heap[i] = heap[i/2];	   
        i /= 2;
	}
    
    heap[i] = t;
}

template <typename type> bool MinHeap<type>::Insert(const type &x) //将x插入到最小堆
{
    if (IsFull())
    {
        cerr << "heap is full" << endl;
        return false;
    }
    //从尾部插入并向上调整成最小堆,然后长度增1 
    heap[size++] = x;
    FilterUp(size-1); 
    return true;
}

template <typename type> bool MinHeap<type>::Change(const type &x, int i) //修改下标为i处元素的值,并调整堆 
{
    if (i < 0 || i >= size)
    {
        cerr << "wrong pos" << endl;
        return false;
    }
  
    if (heap[i] < x) //键值变大,向下调整 
    {
		heap[i] = x;
	    FilterDown(i); 
    }
    else if (heap[i] > x) //键值变小,向上调整 
    {
		heap[i] = x;
	    FilterUp(i); 
    }
    
    return true;
}

template <typename type> bool MinHeap<type>::DeleteMin() //删除堆顶的最小元素
{
    if (IsEmpty())
    {
        cerr << "heap is empty" << endl;
        return false;
    }
    
    heap[0] = heap[--size];//用尾部元素覆盖顶部元素,然后长度减1
    FilterDown(0); //顶部元素向下调整成最小堆
    return true;
}

void CreatGraph(int m, int n);//创建邻接矩阵图 
void PrintGraph(int n);//输出图
void Prime_MinHeap(int n, int v0);//Prime算法求最小生成树(优先队列版本) 

int main()
{
 	int i, j, m, n, v0 = 0;

	printf("请输入顶点数量:"); 
	scanf("%d", &n);
	printf("\n请输入边数量:"); 
	scanf("%d", &m);
	
	CreatGraph(m, n);//创建邻接矩阵图 
 	PrintGraph(n);//输出图
    Prime_MinHeap(n, v0);//Prime算法求最小生成树(优先队列版本) 
	
    system("pause");				   
	return 0;
}

void CreatGraph(int m, int n)//创建邻接矩阵图 
{
	int i, j, a, b, c;
	
	for (i=0; i<n; i++) //初始化顶点数据 
	{
		for (j=0; j<n; j++)
		{
			map[i][j] = (i == j) ? 0 : INFINITY;
		}
	}
    printf("\n请按照a b c格式输入边信息:\n"); 
    for (i=0; i<m; i++)
    {
	    scanf("%d%d%d", &a,&b,&c);
	    map[a][b] = map[b][a] = c;
    }
} 

void PrintGraph(int n)//输出图
{
    int i, j;
    
    for (i=0; i<n; i++)
    {
        printf("G[%d] = %d: ", i, i);
        for (j=0; j<n; j++)
        {
        if (map[i][j] != 0 && map[i][j] != INFINITY)
            printf("<%d, %d> = %d", i, j, map[i][j]);
        }
        printf("\n");
    }
    printf("\n");
} 

void Prime_MinHeap(int n, int v0)//Prime算法求最小生成树(优先队列版本) 
{
    Vertex vex;
	MinHeap<Vertex> h(n);
	int pos, dis, from;
	
	for (int i=0; i<n; i++) //初始化工作,创建一个最小堆 
	{
	 	vex.SetVertex(i, map[v0][i], v0); 
		h.Insert(vex);  
	}
	h.DeleteMin(); //删除顶点v0 
	
	int minDis = 0;
	for (int i=1; i<n; i++) //每趟确定一个新顶点,共n-1趟 
	{
	 	//获取最小元素信息 
	 	vex = h.GetMin();
	 	pos = vex.GetPos();
	 	dis = vex.GetDis();
	 	from = vex.GetFrom();
	 	minDis += dis;
	 	printf("<%d, %d> = %d   ", from, pos, dis);
	 	
		h.DeleteMin(); //删除最小元素
		
		for (int j=0; j<h.Length(); j++)//更新顶点pos的邻接点的dis值,同时更新最小堆 
		{
		 	vex = h.GetNode(j);
		 	if (vex.GetDis() > map[pos][vex.GetPos()])
		 	{
			    vex.SetFrom(pos);
	            vex.SetDis(map[pos][vex.GetPos()]);
				h.Change(vex, j);  
			}
		}
	}

	printf("最小生成树总长度(权值)为 %d\n", minDis); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值