这篇文章的内容,是看了一篇讲最小生成树两种经典算法的文章后,我自己敲的代码和感想。主要的内容在注释上,写成博客方便之后查看,或者是利用。
参考文章:http://blog.csdn.net/qjzl2008/article/details/8008077
代码:
#include "stdafx.h"
#include <iostream>
using namespace std;
struct Edge
{
int begin;
int end;
int weight;
};
struct Matrix
{
int iVexNum;
int iEdgeNum;
int** iArcs;
};
void SortEdges(Edge &low, Edge &high) //用于调换位置实现排序
{
Edge eTemp;
eTemp.begin = low.begin;
eTemp.end = low.end;
eTemp.weight = low.weight;
low.begin = high.begin;
low.end = high.end;
low.weight = high.weight;
high.begin = eTemp.begin;
high.end = eTemp.end;
high.weight = eTemp.weight;
}
void CreatEdges(Matrix & g,Edge *edges)
{
int i ;
int j ;
int k = 0;
for (i = 0; i < g.iVexNum; i++)
{
for (j = i + 1; j < g.iVexNum; j++) //将邻接矩阵转换为边集数组
{
if (g.iArcs[i][j] > 0)
{
edges[k].begin = i;
edges[k].end = j;
edges[k].weight = g.iArcs[i][j];
}
}
}
for (i = 0; i < g.iEdgeNum-1; i++) //一个简单的选择排序
{
for (j = i + 1; j < g.iEdgeNum; j++)
{
if (edges[j].weight < edges[i].weight)
{
SortEdges(edges[j], edges[i]);
}
}
}
}
//这个函数是最大的亮点,通过检查尾部标记进行是否有环路的判断
//尾部标记就是,将最后加进来的边的End点赋值给之前的end点,从而实现通路上的点循环之后
//都会有相同的尾部标记,如果新加进来的边的end点和begin点有相同的尾部标记,就证明在这条边
//加进最小生成树中之前,这两个点就已经在某一条通路当中了,也就是会形成环
//实际上这里的实现思路有点像并查集的方法,为通路中的每个点添加统一的标记,就可以很容易知道两个点是否联通
int Find(int * iEndMark, int iMark)
{
while (iEndMark[iMark])
{
iMark = iEndMark[iMark];
}
return iMark;
}
void TestKruskal(Matrix & g)
{
int i;
int j;
int * iEndMark = new int[g.iVexNum];
Edge * edges = new Edge[g.iEdgeNum];
CreatEdges(g, edges);
for (i = 0; i < g.iVexNum; i++) //初始化所有的尾部标记都为0
{
iEndMark[i] = 0;
}
for (j = 0; j < g.iEdgeNum; j++)
{
int iTemp1 = Find(iEndMark, edges[j].begin);
int iTemp2 = Find(iEndMark, edges[j].end);
if (iTemp1 != iTemp2) //如果相同就是会形成环,不同则加入
{
//加入最小生成树中
iEndMark[iTemp1] = iTemp2;
cout << edges[j].begin << " " << edges[j].end << " "<<edges[j].weight << endl;
}
}
}
int main()
{
return 0;
}
经典的算法的确有很多值得借鉴的地方,好的算法和好的数据结构也是密不可分的,个人感觉算法的思想往往不难理解,比较难的是用好的合适的数据结构来实现算法。