优先级队列(堆)

优先级队列(堆)

1. 堆的顺序存储

1.1 堆的概念
  1. 堆逻辑上是一棵完全二叉树

  2. 堆物理上是保存在数组中比特科技

  3. 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆

  4. 反之,则是小堆,或者小根堆,或者最小堆

  5. 堆的基本作用是,快速找集合中的最值

1.2 存储方式

使用数组保存二叉树结构,方式是将二叉树用层序遍历方式放入数组中。

一般只适合表示完全二叉树,因为非完全二叉树会有空间的浪费。

这种方式的主要用法就是堆的表示。

1.3 下标关系

已知双亲**(parent)**的下标,则:

左孩子(left)下标 = 2 * parent + 1;

右孩子(right)下标 = 2 * parent + 2;

**已知孩子(不区分左右)****(child)**下标,则:

双亲(parent)下标 = (child - 1) / 2;

2. 堆的相关操作

2.1 向下调整
  1. index 如果已经是叶子结点,则整个调整过程结束

    1. 判断 index 位置有没有孩子
    2. 因为堆是完全二叉树,没有左孩子就一定没有右孩子,所以判断是否有左孩子
    3. 因为堆的存储结构是数组,所以判断是否有左孩子即判断左孩子下标是否越界,即 left >= size 越界
  2. 确定 left 或 right,谁是 index 的最小孩子 min

    1. 如果右孩子不存在,则 min = left
    2. 否则,比较 array[left] 和 array[right] 值得大小,选择小的为 min
  3. 比较 array[index] 的值 和 array[min] 的值,如果 array[index] <= array[min],则满足堆的性质,调整结束

  4. 否则,交换 array[index] 和 array[min] 的值

  5. 然后因为 min 位置的堆的性质可能被破坏,所以把 min 视作 index,向下重复以上过程

时间复杂度分析:

最坏的情况即图示的情况,从根一路比较到叶子,比较的次数为完全二叉树的高度

即时间复杂度为 O(log(n))

代码:
public void adjustDown(int arr[], int index, int size) {
    while (index * 2 + 1 < size) {
        //当需要调整的元素不存在或者它没有孩子时,直接返回
            //找到孩子中较小的
            int min;
            if (index * 2 + 2 >= size || arr[index * 2 + 1] > arr[index * 2 + 2]) {
                min = index * 2 + 1;
            } else {
                min = index * 2 + 2;
            }
            //将min和arr[index]比较
            if (arr[index] > arr[min]) { //如果当前元素更大, 就向下置换
                {int temp = arr[index]; arr[index] = arr[min]; arr[min] = temp;}
            }
            index = min;
        }
}
2.2 建堆

思路:从倒数的第一个非叶子节点的子树开始调整,一直 调整到根节点的树,就可以调整成堆。

public void createHeap(int arr[]) {
    //思路: 將每个非叶子结点都向下调整
    // 最后一个结点的父结点下标设为par   需要调整的区间就是[0,par]
    int par = (arr.length - 2) / 2;
    for (int i = par; i >= 0; i--) {
        adjustDown(arr, i, arr.length);
    }
}
2.3 向上调整

相对简单,不多做赘述

public void adjustUp(int arr[], int index, int size) {
    //将该元素与他的父结点比较, 如果小于父结点 就向上置换
    while (true) {
        int par = (index - 1) / 2; // 父结点的下标
        if (par <= 0 || arr[par] < arr[index]) {
            return;
        }
        int temp = arr[index]; arr[index] = arr[par]; arr[par] = temp;

        index = par;
    }
}

3. 堆的相关应用

  • 优先级队列 (java.util.PriorityQueue)

  • 排序 (堆排序)

  • TopK(经典面试题)

    问题:选出最大或最优秀的k个元素

    思路:建立K个元素的小根堆,然后依次向后遍历,每个元素和堆顶元素比较(挑战) 如果大于就替换,然后向下调整

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值