mirror of
https://github.com/duke-git/lancet.git
synced 2025-10-06 16:06:54 +08:00
204 lines
4.2 KiB
Go
204 lines
4.2 KiB
Go
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
|
// Use of this source code is governed by MIT license
|
|
|
|
// Package datastructure implements some data structure. MaxHeap is a binary max heap.
|
|
package datastructure
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/duke-git/lancet/v2/constraints"
|
|
)
|
|
|
|
// MaxHeap implements a binary max heap
|
|
// type T should implements Compare function in constraints.Comparator interface.
|
|
type MaxHeap[T any] struct {
|
|
data []T
|
|
comparator constraints.Comparator
|
|
}
|
|
|
|
// NewMaxHeap returns a MaxHeap instance with the given comparator.
|
|
func NewMaxHeap[T any](comparator constraints.Comparator) *MaxHeap[T] {
|
|
return &MaxHeap[T]{
|
|
data: make([]T, 0),
|
|
comparator: comparator,
|
|
}
|
|
}
|
|
|
|
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
|
|
func BuildMaxHeap[T any](data []T, comparator constraints.Comparator) *MaxHeap[T] {
|
|
heap := &MaxHeap[T]{
|
|
data: make([]T, 0, len(data)),
|
|
comparator: comparator,
|
|
}
|
|
|
|
for _, v := range data {
|
|
heap.Push(v)
|
|
}
|
|
|
|
return heap
|
|
}
|
|
|
|
// Push value into the heap
|
|
func (h *MaxHeap[T]) Push(value T) {
|
|
h.data = append(h.data, value)
|
|
h.heapifyUp(len(h.data) - 1)
|
|
}
|
|
|
|
// heapifyUp heapify the data from bottom to top
|
|
func (h *MaxHeap[T]) heapifyUp(i int) {
|
|
for h.comparator.Compare(h.data[parentIndex(i)], h.data[i]) < 0 {
|
|
h.swap(parentIndex(i), i)
|
|
i = parentIndex(i)
|
|
}
|
|
}
|
|
|
|
// Pop return the largest value, and remove it from the heap
|
|
// if heap is empty, return zero value and fasle
|
|
func (h *MaxHeap[T]) Pop() (T, bool) {
|
|
var val T
|
|
if h.Size() == 0 {
|
|
return val, false
|
|
}
|
|
|
|
val = h.data[0]
|
|
l := len(h.data) - 1
|
|
|
|
h.data[0] = h.data[l]
|
|
h.data = h.data[:l]
|
|
h.heapifyDown(0)
|
|
|
|
return val, true
|
|
}
|
|
|
|
// heapifyDown heapify the data from top to bottom
|
|
func (h *MaxHeap[T]) heapifyDown(i int) {
|
|
lastIndex := len(h.data) - 1
|
|
l, r := leftChildIndex(i), rightChildIndex(i)
|
|
childToCompare := 0
|
|
|
|
for l <= lastIndex {
|
|
if l == lastIndex {
|
|
childToCompare = l
|
|
} else if h.comparator.Compare(h.data[l], h.data[r]) > 0 {
|
|
childToCompare = l
|
|
} else {
|
|
childToCompare = r
|
|
}
|
|
|
|
if h.comparator.Compare(h.data[i], h.data[childToCompare]) < 0 {
|
|
h.swap(i, childToCompare)
|
|
i = childToCompare
|
|
l, r = leftChildIndex(i), rightChildIndex(i)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Peek returns the largest element from the heap without removing it.
|
|
// if heap is empty, it returns zero value and false.
|
|
func (h *MaxHeap[T]) Peek() (T, bool) {
|
|
if h.Size() == 0 {
|
|
var val T
|
|
return val, false
|
|
}
|
|
|
|
return h.data[0], true
|
|
}
|
|
|
|
// Size return the number of elements in the heap
|
|
func (h *MaxHeap[T]) Size() int {
|
|
return len(h.data)
|
|
}
|
|
|
|
// Data return data of the heap
|
|
func (h *MaxHeap[T]) Data() []T {
|
|
return h.data
|
|
}
|
|
|
|
// PrintStructure print the structure of the heap
|
|
func (h *MaxHeap[T]) PrintStructure() {
|
|
level := 1
|
|
data := h.data
|
|
length := len(h.data)
|
|
index := 0
|
|
|
|
list := [][]string{}
|
|
temp := []string{}
|
|
for index < length {
|
|
start := powerTwo(level-1) - 1
|
|
end := start + powerTwo(level-1) - 1
|
|
|
|
temp = append(temp, fmt.Sprintf("%v", data[index]))
|
|
index++
|
|
|
|
if index > end || index >= length {
|
|
list = append(list, temp)
|
|
temp = []string{}
|
|
|
|
if index < length {
|
|
level++
|
|
}
|
|
}
|
|
}
|
|
|
|
lastNum := powerTwo(level - 1)
|
|
lastLen := lastNum + (lastNum - 1)
|
|
|
|
heapTree := make([][]string, level)
|
|
for i := 0; i < level; i++ {
|
|
heapTree[i] = make([]string, lastLen)
|
|
for j := 0; j < lastLen; j++ {
|
|
heapTree[i][j] = ""
|
|
}
|
|
}
|
|
|
|
for k := 0; k < len(list); k++ {
|
|
vals := list[k]
|
|
tempLevel := level - k
|
|
st := powerTwo(tempLevel-1) - 1
|
|
for _, v := range vals {
|
|
heapTree[k][st] = v
|
|
gap := powerTwo(tempLevel)
|
|
st = st + gap
|
|
}
|
|
}
|
|
|
|
for m := 0; m < level; m++ {
|
|
for n := 0; n < lastLen; n++ {
|
|
val := heapTree[m][n]
|
|
if val == "" {
|
|
fmt.Print(" ")
|
|
} else {
|
|
fmt.Print(val)
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
|
|
// parentIndex get parent index of the given index
|
|
func parentIndex(i int) int {
|
|
return (i - 1) / 2
|
|
}
|
|
|
|
// leftChildIndex get left child index of the given index
|
|
func leftChildIndex(i int) int {
|
|
return 2*i + 1
|
|
}
|
|
|
|
// rightChildIndex get right child index of the given index
|
|
func rightChildIndex(i int) int {
|
|
return 2*i + 2
|
|
}
|
|
|
|
// swap two elements in the heap
|
|
func (h *MaxHeap[T]) swap(i, j int) {
|
|
h.data[i], h.data[j] = h.data[j], h.data[i]
|
|
}
|
|
|
|
func powerTwo(n int) int {
|
|
return 1 << n
|
|
}
|