利用Go语言维护并测试最小堆
实验目的
- 熟悉 Go 语⾔对结构体数组的操作
- 熟悉 Go 语⾔中的函数不同类型的参数传递
最小堆
最小堆就是在二叉堆的基础上,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值
在B站上看到一个演示视频(最大堆),可以参考一下:HERE
最小堆中最重要的实现的两种情况:
- down:当某个节点的优先级下降的时候,从上至下恢复堆的顺序
- up:在当某个节点的优先级上升的时候,从下至上恢复堆的顺序
-
down
父节点与左右子节点比较,与最小的进行交换,如果最小的就是父节点本身则返回,否则交换后的父节点(当前的子节点)再作为父节点重新down
// 需要down(下沉)的元素在切片中的索引为i,n为heap的长度,将该元素下沉到该元素对应的子树合适的位置,从而满足该子树为最小堆的要求 func down(nodes []Node, i, n int) { parent := i for leftSon, rightSon := 2*parent+1, 2*parent+2; leftSon < n || rightSon < n; leftSon, rightSon = 2*parent+1, 2*parent+2 { next := parent if leftSon < n && nodes[parent].Value > nodes[leftSon].Value { next = leftSon } if rightSon < n && nodes[parent].Value > nodes[rightSon].Value { if nodes[rightSon].Value < nodes[next].Value { next = rightSon } } if next == parent { break } nodes[parent].Value, nodes[next].Value = nodes[next].Value, nodes[parent].Value parent = next } }
-
up
子节点与父节点比较,如果子结点小的话,则需要进行相互交换,直到循环到下标到达结尾,反之不用交换,直接返回
func up(nodes []Node, j int) { son := j for parent := (son - 1) / 2; parent >= 0; { if nodes[parent].Value <= nodes[son].Value { break } else { nodes[parent].Value, nodes[son].Value = nodes[son].Value, nodes[parent].Value son = parent parent = (son - 1) / 2 } } }
-
Push,用到了上述的Up函数
-
Pop,用到了上述的Down函数
测试(gocheck)
Golang官方的testing package是不支持assert的。
Gocheck
在testing库之上,丰富了很多功能,带我们脱离Golang官方测试框架下无尽的“if…else…"苦海
实用特性:
- assert断言 + 丰富的判断动词: deep multi-type 对比, 字符串比较(正则匹配)
- 按suite组织测试用例,支持suite级别的setup()和teardown()
- 创建、删除临时文件/目录
使用方法
-
安装包
go get -u gopkg.in/check.v1
-
基本用法(引用官方文档)
package hello_test import ( "testing" "io" . "gopkg.in/check.v1" ) // Hook up gocheck into the "go test" runner. func Test(t *testing.T) { TestingT(t) } //先声明该结构并创建将运行测试的函数 type MySuite struct{} //套件将给定值注册为要运行的测试套件。给定值中以Test前缀开头的任何方法都将被视为测试方法。 var _ = Suite(&MySuite{}) func (s *MySuite) TestHelloWorld(c *C) { c.Assert(42, Equals, "42") c.Assert(io.ErrClosedPipe, ErrorMatches, "io: .*on closed pipe") c.Check(42, Equals, 42) }