【数据结构】堆结构以及功能粗略笔记
目录
- 定义
- 基本操作
- 建堆
- 堆排序
- 优先队列
定义
堆必须是一个完全二叉树
完全二叉树:
- 只允许最后一层不满
- 最后一层只能从左往右排
- 最后一层元素间不能有间隔
堆序性
-
小根堆:小元素排在上层的堆
-
大根堆:大元素排在上层的堆
用数组储存堆
方法:从上层到下层,从左到右的顺序储存在一个一位向量中
节点下标为i
时,左子节点下标为2i+1
,右子节点下标为2i+2
,父节点为floor((i-1)/2)
基本操作
下滤
将破坏堆序性的元素跟最大的子节点比较,如果小于最大子节点,则与之交换。
持续比较交换直到该元素大于它的子节点为止,此时该树就被调整成一个大根堆,
反之就被调整成小根堆。
复杂度:
上滤
比如树的最后一个元素破坏了堆序性,那么让它和父节点比较,若大于则交换,重复直到无法上移为止。
该操作主要用于插入新元素进堆。
复杂度:
建堆
自上而下
已知数组,将元素挨个放到堆的最后一位,然后对其进行上滤,直到全部插入。
复杂度:
自下而上
先把数组元素调整成堆,然后再按从下而上的顺序对每个父节点进行下滤操作
复杂度:
堆排序
用一个大根堆做排序:
按从下到上从右到左的顺序把最右下角的点和第一个节点交换,并进行下滤操作,重复所有操作直到树成为一个小根堆,此时所有节点都按从小到大,从上到下,从左到右的顺序排列,也就是此时表示堆的数组已经按从小到大的顺序排列好了。
复杂度:
实现代码
package main
import (
"fmt"
"math"
)
// func main() {
// var (
// nums int
// list []int
// )
// fmt.Scan(&nums)
// list = make([]int, nums)
// for i := 0; i < nums; i++ {
// var a int
// fmt.Scan(a)
// list = append(list, a)
// }
// hp := newHeap(list)
// hp.sort()
// fmt.Println(hp.list)
// fmt.Scan()
// }
type MaxHeap struct {
list []int
}
func (h *MaxHeap) shiftUp(index int) {
for h.list[index] > h.list[parent(index)] {
h.swap(index, parent(index))
index = parent(index)
}
}
func (h *MaxHeap) shiftDown(index int) {
lastIndex := len(h.list) - 1
l := left(index)
childToCompare := 0
for l <= lastIndex {
if l == lastIndex {
childToCompare = l
} else {
childToCompare = h.maxChild(index)
}
if h.list[index] < h.list[childToCompare] {
h.swap(index, childToCompare)
index = childToCompare
l = left(index)
} else {
return
}
}
}
func newHeap(i []int) *MaxHeap {
list := &MaxHeap{[]int{}}
for _, v := range i {
list.list = append(list.list, v)
list.shiftUp(len(list.list) - 1)
}
return list
}
func (h *MaxHeap) Add(i int) {
h.list = append(h.list, i)
h.shiftUp(len(h.list) - 1)
}
func parent(i int) int {
return (i - 1) / 2
}
func left(i int) int {
return 2*i + 1
}
func right(i int) int {
return 2*i + 2
}
func (h *MaxHeap) swap(index1, index2 int) {
h.list[index1], h.list[index2] = h.list[index2], h.list[index1]
}
func (h *MaxHeap) maxChild(index int) int {
if left(index) < len(h.list) && right(index) < len(h.list) {
a, b := h.list[left(index)], h.list[right(index)]
if a > b {
return left(index)
} else {
return right(index)
}
} else {
return -1
}
}
func (h *MaxHeap) removeTop() {
h.swap(0, len(h.list)-1)
h.list = h.list[0 : len(h.list)-1]
h.shiftDown(0)
}
func (h *MaxHeap) extract() int {
a := h.list[0]
h.removeTop()
return a
}
func (h *MaxHeap) printHeap() {
level := 0.00
temp := 0
for temp < len(h.list) {
for i := 0.0; i < math.Pow(2, level); i++ {
if temp == len(h.list) {
return
}
fmt.Printf("%d ", h.list[temp])
temp++
}
fmt.Println()
level++
}
}
func (h *MaxHeap) sort() {
length := len(h.list)
returning := []int{}
for length >= 1 {
returning = append(returning, h.extract())
length--
}
h.list = returning
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)