【数据结构】堆结构以及功能粗略笔记

目录

  • 定义
  • 基本操作
  • 建堆
  • 堆排序
  • 优先队列

定义

堆必须是一个完全二叉树

完全二叉树

  • 只允许最后一层不满
  • 最后一层只能从左往右排
  • 最后一层元素间不能有间隔

堆序性

  • 小根堆:小元素排在上层的堆

  • 大根堆:大元素排在上层的堆

用数组储存堆

方法:从上层到下层,从左到右的顺序储存在一个一位向量中

节点下标为i时,左子节点下标为2i+1,右子节点下标为2i+2,父节点为floor((i-1)/2)

基本操作

下滤

将破坏堆序性的元素跟最大的子节点比较,如果小于最大子节点,则与之交换。

持续比较交换直到该元素大于它的子节点为止,此时该树就被调整成一个大根堆,

反之就被调整成小根堆。

复杂度:O(logN)

上滤

比如树的最后一个元素破坏了堆序性,那么让它和父节点比较,若大于则交换,重复直到无法上移为止。

该操作主要用于插入新元素进堆。

复杂度:O(logN)

建堆

自上而下

已知数组,将元素挨个放到堆的最后一位,然后对其进行上滤,直到全部插入。

复杂度:O(NlogN)

自下而上

先把数组元素调整成堆,然后再按从下而上的顺序对每个父节点进行下滤操作

复杂度:O(NlogN)

堆排序

用一个大根堆做排序:

按从下到上从右到左的顺序把最右下角的点和第一个节点交换,并进行下滤操作,重复所有操作直到树成为一个小根堆,此时所有节点都按从小到大,从上到下,从左到右的顺序排列,也就是此时表示堆的数组已经按从小到大的顺序排列好了。

复杂度:O(NlogN)

实现代码

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
}

posted on   安逐悲  阅读(52)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示