go语言实现最小堆并测试

作为go语言初学者,非常有必要多写写代码来熟悉go的语法和风格,本文是关于go语言实现最小堆,就不对最小堆进行赘述了,具体的构建原理可以参考我的这篇博客
下面直接上代码~

package main

import "fmt"

type Node struct {
	Value int
}

// 用于构建结构体切片为最小堆,需要调用down函数
func Init(nodes []Node) {
    for i := len(nodes)/2-1; i >=0; i-- {
        down(nodes,i,len(nodes)) 
    }
}

// 需要down(下沉)的元素在切片中的索引为i,n为heap的长度,将该元素下沉到该元素对应的子树合适的位置,从而满足该子树为最小堆的要求
func down(nodes []Node, i, n int) {
    parent := i
    child := 2*parent+1
    temp := nodes[parent].Value
    for{
        if child < n {
            if child + 1 < n && nodes[child].Value > nodes[child+1].Value {
                child++
            }
            if temp <= nodes[child].Value{
                break
            }
            nodes[parent].Value = nodes[child].Value
            parent = child
            child = child*2+1
        }else{
            break
        }
    }
    nodes[parent].Value = temp    
}

// 用于保证插入新元素(j为元素的索引,切片末尾插入,堆底插入)的结构体切片之后仍然是一个最小堆
func up(nodes []Node, j int) {
    child := j
    parent := (j-1) / 2
    for{
        if child == 0 {
            break
        }
        if nodes[parent].Value < nodes[child].Value {
            break
        }
        temp := nodes[child].Value
        nodes[child].Value = nodes[parent].Value
        nodes[parent].Value = temp
        child = parent
        parent = (parent-1)/2
    }
}

// 弹出最小元素,并保证弹出后的结构体切片仍然是一个最小堆,第一个返回值是弹出的节点的信息,第二个参数是Pop操作后得到的新的结构体切片
func Pop(nodes []Node) (Node, []Node) {
    min := nodes[0]
    nodes[0].Value = nodes[len(nodes)-1].Value
    nodes = nodes[:len(nodes)-1]
    down(nodes,0,len(nodes)-1)
    return min, nodes
}

// 保证插入新元素时,结构体切片仍然是一个最小堆,需要调用up函数
func Push(node Node, nodes []Node) []Node {
    nodes = append(nodes,node)
    up(nodes,len(nodes)-1)
    return nodes
}

// 移除切片中指定索引的元素,保证移除后结构体切片仍然是一个最小堆
func Remove(nodes []Node, node Node) []Node {
    for i := 0; i < len(nodes); i++ {
        if node.Value == nodes[i].Value {
            nodes[i].Value = nodes[len(nodes)-1].Value
            nodes = nodes[0:len(nodes)-1]
            down(nodes,0,len(nodes)-1)
            break
        }
    }
    return nodes
}

//我添加的函数,用于打印切片
func Display(nodes []Node) {
    for _, ele := range nodes {
        fmt.Printf("%d ", ele.Value)
    }
    fmt.Printf("\n")
}

func main() {
    nodes := []Node{
        Node{3},
        Node{6},
        Node{9},
        Node{1},
        Node{2},
        Node{5},
        Node{8},
        Node{4},
        Node{7},
    }
    fmt.Printf("Before test\n")
    Display(nodes)

    fmt.Printf("Testing Init() and down()\n")
    Init(nodes)
    Display(nodes)
    
    fmt.Printf("Testing up() with adding 0\n")
    node_add := Node{0}
    nodes = append(nodes,node_add)
    up(nodes,9)
    Display(nodes)

    fmt.Printf("Testing Pop() with popping 0\n")
    min, nodes := Pop(nodes)
    fmt.Printf("Minimum :%d\n",min)
    Display(nodes)

    fmt.Printf("Testing Remove() with removing 5\n")
    node_remove := Node{5}
    nodes = Remove(nodes,node_remove)
    Display(nodes)

    fmt.Printf("Testing Push()\n")
    array := []Node{
        Node{9},
        Node{7},
        Node{6},
    }
    node5 := Node{5}
    node4 := Node{4}
    node3 := Node{3}
    node2 := Node{2}
    node1 := Node{1}
    array = Push(node5,array)
    array = Push(node4,array)
    array = Push(node3,array)
    array = Push(node2,array)
    array = Push(node1,array)
    Display(array)
}

使用go test 命令和 testing 包进行测试

GoConvey是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多 Web 界面特性。使用go test指令就可以直接运行。
在测试之前,我们需要修改上面部分函数的返回值(这里就不放代码了),返回构造好的最小堆,以便使用GoConvey进行测试。
首先将miniHeap.go打包,go build之后应该会在pkg中生成.a文件
然后在同一目录下,增加miniHeap_test.go测试文件:

package miniHeap

import (
    "testing"
    ."github.com/smartystreets/goconvey/convey"
)

func TestInit(t *testing.T){
    Convey("testing Init()",t,func(){
        So(Init([]Node{
        Node{3},
        Node{6},
        Node{9},
        Node{1},
        Node{2},
        Node{5},
        Node{8},
        Node{4},
        Node{7},
    }),ShouldResemble,[]Node{
        Node{1},
        Node{2},
        Node{5},
        Node{4},
        Node{3},
        Node{9},
        Node{8},
        Node{6},
        Node{7},
    })
    })
}

func TestUp(t *testing.T){
    Convey("testing up()",t,func(){
        So(up([]Node{
            Node{1},
            Node{2},
            Node{5},
            Node{4},
            Node{3},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
            Node{0},
        },9),ShouldResemble,
        []Node{
            Node{0},
            Node{1},
            Node{5},
            Node{4},
            Node{2},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
            Node{3},
        })
    })
}

func TestPop(t *testing.T){
    Convey("testing Pop()",t,func(){
        So(Pop([]Node{
            Node{0},
            Node{1},
            Node{5},
            Node{4},
            Node{2},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
            Node{3},
        }),ShouldResemble,
        []Node{
            Node{1},
            Node{2},
            Node{5},
            Node{4},
            Node{3},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
        })
    })
}

func TestPush(t *testing.T){
    Convey("testing Push()",t,func(){
        So(Push(Node{0},[]Node{
            Node{1},
            Node{2},
            Node{5},
            Node{4},
            Node{3},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
        }),ShouldResemble,
        []Node{
            Node{0},
            Node{1},
            Node{5},
            Node{4},
            Node{2},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
            Node{3},
        })
    })
}

func TestRemove(t *testing.T){
    Convey("testing Remove()",t,func(){
        So(Remove([]Node{
            Node{1},
            Node{2},
            Node{5},
            Node{4},
            Node{3},
            Node{9},
            Node{8},
            Node{6},
            Node{7},
        },Node{1}),ShouldResemble,
        []Node{
            Node{2},
            Node{3},
            Node{5},
            Node{4},
            Node{7},
            Node{9},
            Node{8},
            Node{6},
        })
    })
}

下面是运行结果

由于我也是初学者,有的地方还不甚明白(比如原Pop函数,返回一个切片和一个结构体,我不知道怎么写断言,只好去掉返回值中的结构体),写法也比较笨重,希望大佬们可以指点指点~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值