数据结构_堆

Created: 2023-11-28T16:46+08:00

  • 定义
    • 堆是一棵完全二叉树
    • 每个父节点大于子节点就是大顶堆,反之就是小顶堆
    • 优先队列可以用堆实现
  • 建堆:自底向上
  • 新增元素:上浮
  • 弹出元素:下沉
  • 例题
    • topK

参考:数据结构 - 堆和堆的 Java 实现

堆的建立

Binary Heap - Insert, Sift Up, Delete, Sift Down, Heapify(BuildHeap) - YouTube

堆的建立使用的是 sift down + bottom top 的方法,从最后一个非叶子节点开始 sift down,逐步调整到 root。
每一次对非叶子节点 sift down,就会导致该节点开始以下的部分变成一个堆。
复杂度是 \(O(n)\)

在我看来,堆的建立使用了分治法中“合并”的思想:给定两个堆和一个数,合并成一个新的堆。

给定一个数组,那么堆的建立就是自底向上的,整个大堆任意取一个点,该点以下部分构成一个「子堆」,两个子堆加上一个 root,对 root sift down 就完成新堆的构建。

可以利用 Java 中的 ArrayList 结构实现堆

import java.util.ArrayList;

public class test {
    public static void main(String[] args) {
        ArrayList<Integer> nums = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            nums.add(i);
        }

        printOnedArray(nums);

        for (int i = nums.size() / 2; i >= 0; i--) {
            keepHeapAttrib(nums, i);
        }

        printOnedArray(nums);

    }

    // 保证堆的性质
    public static void keepHeapAttrib(ArrayList<Integer> heap, int index) {
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int max = index;
        if (left < heap.size() && heap.get(left) > heap.get(max)) max = left;
        if (right < heap.size() && heap.get(right) > heap.get(max)) max = right;
        if (max != index) {
            int temp = heap.get(index);
            heap.set(index, heap.get(max));
            heap.set(max, temp);
            keepHeapAttrib(heap, max);  // 递归解决
        }
    }

    public static void printOnedArray(ArrayList<Integer> array) {
        for (int i = 0; i < array.size(); i++) {
            System.out.print(array.get(i) + " ");
        }
        System.out.println();
    }
}

add 和 delete

对于大根堆来说,新增元素,就是在堆最后新增一个叶子,然后一直上浮,直到该新增的数为根节点或比父节点小

对于大根堆来说,弹出元素,就是删除根节点,然后把最后一个叶子取出来,做一次 sift down 就变成了堆的构建算法。

例题

NC119 最小的 K 个数

posted @ 2022-02-21 12:10  dutrmp19  阅读(43)  评论(0)    收藏  举报