golang 使用双向链表作为container/heap的载体

MyHeap:container/heap的数据载体,需要实现以下方法:

Len:堆中数据个数

Less:第i个元素 是否必 第j个元素 值小

Swap:交换第i个元素和 第j个元素

Push:向堆中追加元素

Pop:从堆中取出元素

下面是使用双向链路作为数据载体的最小堆实现方式:

Go 复制代码
package main

import (
	"container/heap"
	"fmt"
)

type HeapItem struct {
	Value int
	Prev  *HeapItem
	Next  *HeapItem
}

type MyHeap struct {
	Head   *HeapItem
	Tail   *HeapItem
	Length int
}

func (h *MyHeap) Len() int {
	return h.Length
}

func (h *MyHeap) Less(i, j int) bool {
	return h.Find(i).Value < h.Find(j).Value
}

func (h *MyHeap) Swap(i, j int) {
	nodeI, nodeJ := h.Find(i), h.Find(j)
	isNear := h.IsNear(nodeI, nodeJ)

	// 记录I的前和后
	nodeIPrev, nodeINext := nodeI.Prev, nodeI.Next

	// 记录J的前和后
	nodeJPrev, nodeJNext := nodeJ.Prev, nodeJ.Next

	// 把J放到I的位置
	nodeIPrev.Next = nodeJ
	nodeJ.Prev = nodeIPrev
	nodeJ.Next = nodeINext // near, 对于相邻元素, 这样操作有问题, 下面会重新赋值
	nodeINext.Prev = nodeJ // near, 对于相邻元素, 这样操作有问题, 下面会重新赋值

	// 把I放到J的位置
	nodeJPrev.Next = nodeI // near, 对于相邻元素, 这样操作有问题, 下面会重新赋值
	nodeI.Prev = nodeJPrev // near, 对于相邻元素, 这样操作有问题, 下面会重新赋值
	nodeI.Next = nodeJNext
	nodeJNext.Prev = nodeI

	// 对于相邻元素,重新赋值
	if isNear {
		nodeJ.Next = nodeI
		nodeINext.Prev = nodeIPrev

		nodeJPrev.Next = nodeJNext
		nodeI.Prev = nodeJ
	}
}

func (h *MyHeap) Push(v interface{}) {
	newItem := v.(*HeapItem)

	temp := h.Tail.Prev
	temp.Next = newItem
	newItem.Prev = temp
	newItem.Next = h.Tail
	h.Tail.Prev = newItem

	h.Length++
	return
}

func (h *MyHeap) Pop() interface{} {
	realTailNode := h.Tail.Prev

	realTailNode.Prev.Next = realTailNode.Next
	realTailNode.Next.Prev = realTailNode.Prev

	h.Length--

	return realTailNode
}

func (h *MyHeap) IsNear(nodeI, nodeJ *HeapItem) bool {
	if nodeI.Next == nodeJ {
		return true
	}
	return false
}

func (h *MyHeap) Find(i int) *HeapItem {
	nodeI := h.Head
	for k := 0; k <= i; k++ {
		nodeI = nodeI.Next
	}
	return nodeI
}

func (h *MyHeap) Show() {
	forward := ""
	backward := ""
	i := 0
	for curr := h.Head; curr != nil && i < 10; curr = curr.Next {
		forward += fmt.Sprintf("'%d'->", curr.Value)
		i++
	}
	j := 0
	for curr := h.Tail; curr != nil && j < 10; curr = curr.Prev {
		backward = fmt.Sprintf("'%d'<-", curr.Value) + backward
		j++
	}
	fmt.Printf("forward=%s, backward=%s\n", forward, backward)
}

func InitHeap() *MyHeap {
	head := &HeapItem{Value: -1}
	tail := &HeapItem{Value: -2}
	head.Next = tail
	tail.Prev = head
	return &MyHeap{
		Head:   head,
		Tail:   tail,
		Length: 0,
	}
}

func main() {
	myHeap := InitHeap()
	heap.Init(myHeap)
	heap.Push(myHeap, &HeapItem{Value: 10})
	heap.Push(myHeap, &HeapItem{Value: 1000})
	heap.Push(myHeap, &HeapItem{Value: 5})
	heap.Push(myHeap, &HeapItem{Value: 1})
	heap.Push(myHeap, &HeapItem{Value: 7})

	myHeap.Show()

	for myHeap.Len() > 0 {
		item := heap.Pop(myHeap).(*HeapItem)
		fmt.Printf("%d ", item.Value)
	}
	fmt.Println()
}
相关推荐
半桔5 小时前
二叉树(C语言)
c语言·开发语言·数据结构·算法·链表·github
加油,旭杏6 小时前
【go语言】map 和 list
开发语言·golang·list
Joyner20187 小时前
python-leetcode-删除排序链表中的重复元素 II
算法·leetcode·链表
薛语澄18 小时前
CSS语言的网络编程
开发语言·后端·golang
川Princess19 小时前
【后端开发】字节跳动青训营之Go语言进阶与依赖管理
开发语言·后端·golang
薛语澄20 小时前
Scala语言的移动应用开发
开发语言·后端·golang
SyntaxSage20 小时前
Elixir语言的数据结构
开发语言·后端·golang
萧澄华21 小时前
Powershell语言的云计算
开发语言·后端·golang
梦想画家21 小时前
Golang Gin系列-5:数据模型和数据库
数据库·golang·gin
L_09071 天前
【C】链表算法题4 -- 合并两个有序链表
c语言·算法·链表