数据结构:大顶堆

一、大顶堆的定义

大顶堆是 的一种具体实现,属于完全二叉树结构,同时满足大顶堆的核心性质 :每个父节点的值都大于或等于其左右子节点的值,堆顶(根节点)为整个堆的最大值。

大顶堆常被用于快速获取和维护数据集的最大值,是优先队列、Top-K 大问题等场景的常用底层结构。

资料:https://pan.quark.cn/s/43d906ddfa1bhttps://pan.quark.cn/s/90ad8fba8347https://pan.quark.cn/s/d9d72152d3cf

二、大顶堆的核心性质

1. 结构性质

  • 大顶堆是一棵完全二叉树,除最后一层外,其余层节点数均为最大值,且最后一层节点靠左排列。
  • 通常用数组存储,若数组索引从 0 开始,对于索引为 i 的节点:
    • 左子节点索引为 2i + 1
    • 右子节点索引为 2i + 2
    • 父节点索引为 (i - 1) // 2

2. 数值性质

  • 任意父节点的值 ≥ 其左右子节点的值,堆顶(数组索引 0 位置)始终是堆中最大值。
  • 叶子节点无需满足额外的数值约束(无后代节点)。

三、大顶堆的核心操作

大顶堆的操作围绕维持堆的数值性质 展开,核心为上浮下沉,具体操作如下:

1. 上浮(Up-Heapify)

当插入新元素时,新元素初始放在数组末尾,若其值大于父节点,需通过上浮调整位置。

  • 操作逻辑:比较当前节点与父节点的值,若当前节点值更大,则交换两者,重复此过程直到当前节点值 ≤ 父节点,或到达堆顶。

2. 下沉(Down-Heapify)

当堆顶元素被删除或堆中元素值被修改时,需通过下沉调整堆结构。

  • 操作逻辑:比较当前节点与左右子节点的值,选择值最大的子节点;若当前节点值小于该子节点,则交换两者,重复此过程直到当前节点值 ≥ 所有子节点,或成为叶子节点。

3. 插入元素

  1. 将新元素添加到数组末尾;
  2. 对新元素执行上浮操作,恢复大顶堆性质。

4. 删除堆顶元素

  1. 将堆顶元素与数组末尾元素交换;
  2. 删除数组末尾的原堆顶元素;
  3. 对新的堆顶元素执行下沉操作,恢复大顶堆性质。

5. 构建大顶堆

将无序数组转换为大顶堆,从最后一个非叶子节点 开始(索引为 (n//2)-1n 为数组长度),从下到上依次执行下沉操作。

四、大顶堆的时间复杂度

  • 插入操作:O(log n),上浮操作最多遍历堆的高度(log n 层)。
  • 删除堆顶操作:O(log n),下沉操作最多遍历堆的高度。
  • 构建堆:O(n),优于逐个插入的 O(n log n)
  • 获取堆顶最大值:O(1),直接访问数组索引 0 位置。

五、大顶堆的实现示例

python 复制代码
class MaxHeap:
    def __init__(self):
        self.heap = []
    
    def parent(self, idx):
        """获取父节点索引"""
        return (idx - 1) // 2
    
    def left_child(self, idx):
        """获取左子节点索引"""
        return 2 * idx + 1
    
    def right_child(self, idx):
        """获取右子节点索引"""
        return 2 * idx + 2
    
    def swap(self, i, j):
        """交换堆中两个位置的元素"""
        self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
    
    def up_heapify(self, idx):
        """上浮操作,维护大顶堆性质"""
        while idx > 0 and self.heap[idx] > self.heap[self.parent(idx)]:
            self.swap(idx, self.parent(idx))
            idx = self.parent(idx)
    
    def down_heapify(self, idx):
        """下沉操作,维护大顶堆性质"""
        n = len(self.heap)
        while True:
            largest = idx  # 初始假设当前节点最大
            left = self.left_child(idx)
            right = self.right_child(idx)
            
            # 比较左子节点
            if left < n and self.heap[left] > self.heap[largest]:
                largest = left
            # 比较右子节点
            if right < n and self.heap[right] > self.heap[largest]:
                largest = right
            
            # 若当前节点已是最大,停止下沉
            if largest == idx:
                break
            self.swap(idx, largest)
            idx = largest
    
    def insert(self, val):
        """插入元素"""
        self.heap.append(val)
        self.up_heapify(len(self.heap) - 1)
    
    def extract_max(self):
        """删除并返回堆顶最大值"""
        if not self.heap:
            return None
        if len(self.heap) == 1:
            return self.heap.pop()
        
        max_val = self.heap[0]
        # 堆顶与末尾元素交换,删除原堆顶
        self.heap[0] = self.heap.pop()
        # 新堆顶下沉
        self.down_heapify(0)
        return max_val
    
    def get_max(self):
        """获取堆顶最大值(不删除)"""
        return self.heap[0] if self.heap else None
    
    def build_heap(self, arr):
        """将无序数组构建为大顶堆"""
        self.heap = arr.copy()
        n = len(self.heap)
        # 从最后一个非叶子节点开始下沉
        for i in range((n // 2) - 1, -1, -1):
            self.down_heapify(i)

使用示例

python 复制代码
# 初始化大顶堆
max_heap = MaxHeap()

# 插入元素
max_heap.insert(5)
max_heap.insert(3)
max_heap.insert(8)
max_heap.insert(1)
print("堆顶最大值:", max_heap.get_max())  # 输出 8

# 提取堆顶
print("提取的最大值:", max_heap.extract_max())  # 输出 8
print("当前堆顶:", max_heap.get_max())  # 输出 5

# 用无序数组构建大顶堆
arr = [9, 4, 7, 1, 3, 6]
max_heap.build_heap(arr)
print("构建后的堆顶:", max_heap.get_max())  # 输出 9

六、大顶堆的典型应用

  1. 优先队列(最大值优先):用于任务调度系统,优先执行优先级高(数值大)的任务。
  2. Top-K 小问题:维护一个大小为 K 的大顶堆,遍历数据时,若新元素小于堆顶则替换堆顶并下沉,最终堆中元素即为前 K 小值。
  3. 堆排序:先构建大顶堆,再逐次提取堆顶最大值,将其放到数组末尾,最终得到升序数组。
  4. 数据流最大值维护:实时数据流中,可通过大顶堆快速获取当前所有数据的最大值。
相关推荐
SHOJYS11 小时前
学习离线处理 [CSP-J 2022 山东] 部署
数据结构·c++·学习·算法
ada7_12 小时前
LeetCode(python)108.将有序数组转换为二叉搜索树
数据结构·python·算法·leetcode
仰泳的熊猫12 小时前
1084 Broken Keyboard
数据结构·c++·算法·pat考试
_w_z_j_13 小时前
最小覆盖字串(滑动窗口)
数据结构·算法
湖北师范大学2403w14 小时前
根据前序和中序遍历构建二叉树
数据结构·算法
2401_8414956414 小时前
【LeetCode刷题】最大子数组和
数据结构·python·算法·leetcode·动态规划·最大值·最大子数组和
liu****14 小时前
8.栈和队列
c语言·开发语言·数据结构·c++·算法
仰泳的熊猫15 小时前
1088 Rational Arithmetic
数据结构·c++·算法·pat考试
2401_8414956415 小时前
【LeetCode刷题】最小覆盖字串
数据结构·python·算法·leetcode·字符串·双指针·滑动窗口算法
roman_日积跬步-终至千里15 小时前
【计算机算法与设计(4)】排序算法的原理和方法,以及寻找一个长序列中前k个最大数所运用的方法
数据结构·算法·排序算法