您的位置:首页 > 理论基础 > 数据结构算法

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

2018-03-01 11:29 239 查看
这篇文章接上一篇最小生成树的文章,上一篇的代码是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]); //加入队列当中
}
//可以看出这种方法会将全部比之前小的边都加入到队列当中(相同的未加入树的点),但是由于队列是优先级队列,所以用的时候只取最小权值的
//队列就是保存了相同节点的不同权值结果,很方便的实现了动态更新未加入树的节点情况
}
}

}注释比较详细,这段代码的重点在于对优先级队列的应用,就和之前的理解一样,队列和栈往往都是用来保存某种状态(情况?)的。但是这里和之前对队列和栈的应用不同的是,并不是所有保存到队列中的都有用到,最小生成树嘛,只用了最小权值的情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息