最小生成树之prim算法(go语言实现)

定义

在一个无向有权图中,能遍历完所有的节点并且花费的代价最小,这样就构成了一颗最小生成树

prim算法

简介:通过贪心算法,整个图中只存在一颗最小生成树,每次遍历的时候,将树外面的代价最小的一个节点添加进来

借鉴了景明先生的图:它的描述更详细些链接:图解:什么是最小生成树
在这里插入图片描述

伪代码(待完善)
for v := range G{
	v.Father = None
	v.Val = 无穷大
}
root = v
root.Val = 0	// 设置权重最小,选他来做为第一个节点
Queue = MinFirstQueue(G) //最小优先队列,  里面存放的值是当前“prim树”能够到达该节点的代价
for ;;{
	if(Queue.IsEmpty()){
		break
	}
	u = Queue.Pop()		// 弹出val最小的节点,所以第一个被弹出的肯定是root
	for v:=u.neighbor(){
	
		if v 属于 Queue and W(u, v) < v.Val{// 节点v没有在prim树中,并且节点u到v的权重小于v到father节点的权重
			// 发现更优路径,替换v的父节点
			v.Father = u
			v.val = w(u, v)	
			Queue.Update()		//替换了最小值,也要更新最小队列
		}
	}
}

这样,从root节点开始往下走,就能找到一颗prim树了

go语言代码:统计最小生成树的和

最好以后再来完善,使用对象生成一颗真正的生成树

package main

import "fmt"

// 图:
// 解释:(0, 1)	位置上的3 表示从v0到v3的权重为3
var lstGrap [9][9]int

// 0, 3, 0, 0, 0, 4, 0, 0, 0
// 3, 0, 8, 0, 0, 0, 6, 0, 5
// 0, 8, 0, 12,0, 0, 0, 0, 0
// 0, 0, 12,0, 10,0, 14,6, 0
// 0, 0, 0, 10,0, 18,0, 1, 0
// 4, 0, 0, 0, 18,0, 7, 0, 0
// 0, 6, 0, 14,0, 7, 0, 9, 0
// 0, 0, 0, 6, 1, 0, 9, 0, 0
// 0, 5, 2, 11,0, 0, 0, 0, 0
// 要求:统计最小生成树的和

func Prim() int {
	lstTree := make([]int, 9) //已经加入最小生成树的节点
	fmt.Printf("lstTree容量:%v, len: %v\n", len(lstTree), cap(lstTree))

	iNode := 0
	iSum := 0
	lstTree = append(lstTree, iNode) //选定v0作为root节点,开始生成最小生成树
	for {                            //循环直到遍历完所有节点
		if len(lstTree) == 9 { //做个保底,这里应该是不会被执行到的
			print("break")
			break
		}
		lstNextNodeInfo := FindMinNeibor(lstTree)
		iNextNode := lstNextNodeInfo[0]
		iWeight := lstNextNodeInfo[1]
		if iNextNode == -1 { // 没找到下一个节点就代表遍历结束,直接返回
			return iSum
		} else {
			fmt.Printf("选择路径:V%v --> V%v  权重:%v\n", iNode, iNextNode, iWeight)
			iSum += iWeight
			iNode = iNextNode
			lstTree = append(lstTree, iNode)
		}
	}
	return iSum
}

func FindMinNeibor(lstTree []int) []int {
	//找到下一个要加到生成树种的节点
	//参数:lstTree生成树种的节点
	//返回值:lstResult[0] 下一个要加到生成树种的节点, lstResult[1] 代价
	iMin := 0
	iNextNode := -1

	for _, iNode := range lstTree {
		for iNeiborNode, iWeight := range lstGrap[iNode] {
			if (iMin == 0 || iWeight < iMin) && !IsContain(lstTree, iNeiborNode) && iWeight != 0 {
				iMin = iWeight
				iNextNode = iNeiborNode
			}
		}
	}
	fmt.Printf("return:%v\n", iNextNode)
	lstResult := []int{iNextNode, iMin}
	return lstResult
}

func IsContain(lstData []int, value int) bool {
	// 判断元素是否在列表中
	for _, val := range lstData {
		if val == value {
			return true
		}
	}
	return false
}

func InitGrap() {
	// 初始化图
	lstGrap = [9][9]int{
		[9]int{0, 3, 0, 0, 0, 4, 0, 0, 0},
		[9]int{3, 0, 8, 0, 0, 0, 6, 0, 5},
		[9]int{0, 8, 0, 12, 0, 0, 0, 0, 0},
		[9]int{0, 0, 12, 0, 10, 0, 14, 6, 0},
		[9]int{0, 0, 0, 10, 0, 18, 0, 1, 0},
		[9]int{4, 0, 0, 0, 18, 0, 7, 0, 0},
		[9]int{0, 6, 0, 14, 0, 7, 0, 9, 0},
		[9]int{0, 0, 0, 6, 1, 0, 9, 0, 0},
		[9]int{0, 5, 2, 11, 0, 0, 0, 0, 0}}
}

func main() {
	InitGrap()
	iSum := Prim()
	fmt.Printf("\n最小生成树路径和:%v", iSum)
}

存在的问题

如果有知道的可以在评论区留言

  1. go语言我不知道该如何判断元素是否在列表中,只好遍历来判断,不知道是否有内置的方法判断

  2. 无穷大如何定义?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值