数据结构之图的最小生成树【2】

这篇文章接上一篇最小生成树的文章,上一篇的代码是Kruskal算法,这一篇是Prim算法,顺便复习了一下优先级队列。只要记住树是一种1对多的结构,储存的最好方法是储存每个节点的父节点(用数组的储存的话)就行。

参考文章:http://blog.csdn.net/tham_/article/details/46048907

代码:

struct Matrix
{
	int iVexNum;
	int iEdgeNum;
	int** iArcs;
};

struct Node
{
	int weight;     //表示对应边的权值
	int dot;        //节点的编号
	int parent;     //父节点的编号
	friend bool operator < (Node a, Node b)  //优先级排序,权值小的排前面
	{
		return a.weight > b.weight;
	}
};

//用到的主要数据结构是一个优先级队列、一个结构体数组(用来储存最小生成树)、一个标记数组(用来表示节点是否已加入树)

//这里比较需要注意的地方是,最小生成树的储存方式是储存每个节点在树当中的父节点
void Prim(Matrix & g)
{
	priority_queue<Node> q;
	Node* nTree = new Node[g.iVexNum];
	bool* bVisited = new bool[g.iVexNum];
	int i;
	int j;
	for (i = 0; i < g.iVexNum; i++)  //初始化 
	{
		bVisited[i] = false;    //设置为都没有加进树中
		nTree[i].dot = i;       //节点的编号就是它在数组中的编号
		nTree[i].weight = INF;  //权值设置为最大值
		nTree[i].parent = -1;   //最开始时都没有加进树中,全部节点都没有父节点
	}
	nTree[0].weight = 0;
	q.push(nTree[0]);       //将头结点加入队列
	while (!q.empty())
	{
		Node nTemp = q.top();  //获得权值最小的节点(优先级队列所以权值小的排在队首)
		q.pop();

		if (bVisited[nTemp.dot]) //如果已经加入树中了,那么就跳过
			continue;

		int iTemp = nTemp.dot;
		bVisited[nTemp.dot] = true;  //标记

		for (i = 0; i < g.iVexNum; i++)
		{
			if (i != iTemp && !bVisited[i] && g.iArcs[iTemp][i] < nTree[i].weight)
			{      
				//不能是矩阵对角线上的边(自己到自己)、不能已经加入树中、权值小于当前权值

				nTree[i].parent = i;    //设置为父节点
				nTree[i].weight = g.iArcs[iTemp][i];   //设置新的权值
				q.push(nTree[i]);   //加入队列当中 
			}
			//可以看出这种方法会将全部比之前小的边都加入到队列当中(相同的未加入树的点),但是由于队列是优先级队列,所以用的时候只取最小权值的
			//队列就是保存了相同节点的不同权值结果,很方便的实现了动态更新未加入树的节点情况
		}
	}
	
}

注释比较详细,这段代码的重点在于对优先级队列的应用,就和之前的理解一样,队列和栈往往都是用来保存某种状态(情况?)的。但是这里和之前对队列和栈的应用不同的是,并不是所有保存到队列中的都有用到,最小生成树嘛,只用了最小权值的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值