堆及其java手写实现

堆(Heap)是计算机科学中一种常用且高效的数据结构,通常被实现为一个完全二叉树。这个树形结构中的每个节点都有一个关联的值,并且这个值遵循一定的规则,从而使得堆具备特殊的性质,主要分为两种类型:大顶堆和小顶堆。

基本概念:

  • 完全二叉树:这是一种特殊的二叉树,除了最后一层外,每一层都被完全填满,最后一层的节点都尽可能地靠左排列。

  • 数组表示:由于完全二叉树的特性,堆常通过数组来紧凑存储,其中数组的索引关系反映了节点间的父子关系。例如,在数组中,索引i的节点的父节点是索引i/2(向下取整),而其左、右孩子分别是索引2i和2i+1。

堆的性质:

  • 大顶堆:在每个节点上,父节点的值总是大于或等于其孩子的值。因此,堆的根节点是整个堆中的最大值。

  • 小顶堆:与大顶堆相反,每个节点的值总是小于或等于其孩子的值,使得堆的根节点是整个堆中的最小值。

1 代码实现

package org.example.code;

/**
 * @author Mazai-Liu
 * @time 2024/6/22
 */
public class MyHeap {
    private int[] heapArray;
    private int heapSize;

    public MyHeap(int maxHeapSize) {
        heapArray = new int[maxHeapSize + 1];
        heapSize = 0;
        heapArray[0] = Integer.MIN_VALUE; // 使用哨兵元素,简化索引计算
    }

    public MyHeap(int[] nums) {
        heapArray = new int[nums.length + 1];
        System.arraycopy(nums, 0 , heapArray, 1, nums.length);

        heapSize = nums.length;
        heapArray[0] = Integer.MIN_VALUE; // 使用哨兵元素,简化索引计算

        for(int i = heapSize / 2; i >= 1; i --) {
            minHeapify(i);
        }
    }

    // 向堆中插入一个元素
    public void insert(int value) {
        if (heapSize == heapArray.length - 1) {
            throw new IllegalStateException("Heap is full.");
        }
        heapSize++;
        heapArray[heapSize] = value;
        int current = heapSize;
        while (heapArray[current] < heapArray[current / 2]) {
            swap(current, current / 2);
            current = current / 2;
        }
    }

    // 删除并返回堆中的最小元素
    public int top() {
        if (isEmpty()) {
            throw new IllegalStateException("Heap is empty.");
        }
        int root = heapArray[1];
        heapArray[1] = heapArray[heapSize];
        heapSize--;
        minHeapify(1);
        return root;
    }

    // 查看堆顶元素
    public int peek() {
        if (isEmpty()) {
            throw new IllegalStateException("Heap is empty.");
        }
        return heapArray[1];
    }

    // 检查堆是否为空
    public boolean isEmpty() {
        return heapSize == 0;
    }

    // 调整堆,使其满足小根堆性质
    private void minHeapify(int index) {
        int left = 2 * index;
        int right = 2 * index + 1;
        int smallest = index;

        if (left <= heapSize && heapArray[left] < heapArray[index]) {
            smallest = left;
        }
        if (right <= heapSize && heapArray[right] < heapArray[smallest]) {
            smallest = right;
        }
        if (smallest != index) {
            swap(index, smallest);
            minHeapify(smallest);
        }
    }

    // 交换两个元素的位置
    private void swap(int i, int j) {
        int temp = heapArray[i];
        heapArray[i] = heapArray[j];
        heapArray[j] = temp;
    }

    // 主函数用于测试
    public static void main(String[] args) {
        int[] nums = new int[]{3,1,9,5,4,6,7,2,0,8};
        MyHeap minHeap = new MyHeap(nums);

        while(!minHeap.isEmpty()) {
            System.out.println(minHeap.top());
        }
    }
}

2 用途

  1. 优先级队列:堆是实现优先级队列的常见方式,可以快速插入元素和删除(提取)最高优先级的元素(即堆顶元素)。

  2. 堆排序:利用堆的性质可以进行高效的排序,特别是对于大量数据的排序非常有效。

  3. 任务调度:在操作系统中用于决定哪些进程或任务优先执行。

  4. Top k、数据流中位数问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值