在网上找到很多Prim算法的相关博客,虽然很正确,但是感觉看不懂,代码也不能完成自己需要去做的作业。之前跟着一篇博客打过一次代码,但是我看不懂了(所以痛定思痛,以后一定写注释@_@),而且测试我之后写的代码,出现了内存错误。没办法。这里记下我写代码的过程。
找不到想要博客之后,决定自己想办法,把老师的ppt看了很多遍,但是ppt上的伪代码含糊不清,有用的只有Prim的手动计算过程(这个百度上搜的到,很容易看懂,但是换成程序对于我这种不听课的人就麻烦了)。因为伪代码对自己写程序有帮助,所以我决定先弄伪代码(伪代码比较水可以不看,不过我还是放在这里)。
1.初始化visit,再加一个cont变量,记录已经访问的点的数目
2.把开始的顶点在visit里标记为已读
3.把开始的点存入V中
4.初始化lowcost和adjvex(如下标k代表这个顶点k与adjvex[k]=j,意思是在lowcost集合中lowcost[k]代表的是k到j的权值)
(lowcost第一次初始化比较简单,直接把开始顶点那一行的值全部放进去就行了)
5.从lowcost里选一个最小的权值,然后用lowcostpoint记下来,这个点需要是没被访问的点
6.把lowcostpoint放进V中,visit标记一下
7.之后对lowcost再次进行操作,对于未访问的点,与访问过的点直接的权值进行比较,把每个未访问的点的最小权值用lowcost记下,顺便更换一下adjvex,把adjvex的值变为对应的点
8.继续操作5、6、7,直到所有点被访问
9.打印V(如果这里V不是数组,是树的话返回树)
第一步,根据Prim的计算过程,需要选取一个点作为开始访问的节点(网上很多直接从0开始,这样会省去很多步骤)
void GraphMatrix::Prim(int start_index)//在GraphMatrix类中的Prim函数
第二步,在函数中,需要一个判断节点是否被访问过的数组,数组下标对应的是顶点,推荐bool值,整型的话用0或1(废话 )。这些还不够,还需要一个储存访问的节点索引的数组(这个是为了打印结果到控制台用的),一个记录权值的数组lowcost和记录最小权值对应点lowcostpoint,附带一个min,好判断最小值。如果要返回的是一个树的话,还需要一个adjvex数组。剩下的其他变量带有注释,就不一一解释了。(m_size是这个图用二维数组储存,二维数组的大小)
int lowcost[m_size]; //储存相关顶点的最小路径
int lowcostpoint;//记录最小权值对应顶点
int min;//方便之后选择最小权值
bool visit[m_size];//判断节点有没有被访问
for(int i = 0;i < m_size;i ++)//初始化访问数组
visit[i] = false;
int cont = 0;//计数
int adjvex[m_size];//储存相关顶点
int V[m_size];//储存访问顺序
V[cont] = start_index;//添加开始节点
visit[start_index-1] = true;
cont++;
int sum = 0;//总权值
注:visit这里的下标之所以减1,是因为在节点上,我是用1开始计数,而数组是从0开始的。所以需要减小1。之后的情况也一样。
第三步初始化lowcost和adjvex,因为刚开始只有一个节点被访问,所以直接把这个点所有的分量赋值给lowcost就行。
for(int i = 0;i < m_size;i ++)
{
lowcost[i] = matrix[start_index-1][i];
adjvex[i] = start_index - 1;
}
第四步,循环m_size-1次重复的操作,每一次都需要保证有一个节点,所以可能不适用于一些特殊情况。例如
代码片段:
for(int i = 1;i < m_size;i ++)//因为第一个点已经访问,为了防止用cont访问V越界,所以把i=0改成了i=1
{
min = INF;
注:这里的INF定义如下
#define INF 65535
第六步,找到了最小的点,用之前申请的变量进行记录,把visit中对应的未访问(false)改为已访问(true),把这个节点记录在V中(所以cont的计数是在这用的)。另外,如果需要最小生成树的总权值,还需要把这个最小点的对应权值加上去。
sum += lowcost[lowcostpoint];
visit[lowcostpoint] = true;
V[cont] = lowcostpoint + 1;
cont++;
第七步,这里需要的东西有点多。主要是对lowcost的操作。在Prim算法中,很容易知道事把已经访问的节点看作一个集合(或者是点),然后再看和其他未访问顶点的连通分量。
两个集合都有未知个数的点,这里用了傻瓜方法,便于理解也便于操作。就是把visit遍历,对没有访问过的节点,把它与已经访问的节点的连通分量遍历,找到最小的,然后塞进lowcost里,已经访问过了其实操不操作已经无所谓了,但是这里还是把对应的值改为了INF。
for(int j = 0;j < m_size;j ++)
{
if(!visit[j])
{
min = INF;
for(int k = 0;k < m_size;k ++)//对于未访问的单个节点,寻找与被访问的节点权值最小的节点
{
if(min > matrix[j][k] && visit[k])//需要的是已经访问的节点
{
min = matrix[j][k