优先级队列(堆)的详解

      优先级队列提供了两个最基本的操作:一个是返回最高优先级对象,一个是添加新的对象,优先级队列底层实现用到的数据结构就是堆

一、堆 

1、堆的概念

        如果有一个关键码的集合的所有元素按照完全二叉树的顺序存储方式存储在一个一维数组中,并满足ki <= k2i + 1且ki <= k2i + 2  (ki >= k2i + 1且ki >= k2i + 2  ),则称为小堆(或大堆)。根节点最大的堆为大根堆或者最大堆,根节点最小的堆为小根堆或最小堆

2、堆的存储方式

        堆是一颗完全二叉树,因此可以层序的规则采用顺序的方式来高效存储

3、堆的创建

         由于根节点的左右子树已经完全满足堆的性质,因此只需要将根节点向下调整好即可

private void createSort(int[] arr) {
        for (int parent = (arr.length - 2) / 2;parent >= 0;parent--) {
            shiftDowm(arr,parent,arr.length);
        }
    }

    private void shiftDowm(int[] arr, int parent, int length) {
        int child = parent * 2 + 1;
        while (child < length) {
            if ((child + 1) < length) {
                if (arr[child] < arr[child + 1]) {
                    child++;
                }
            }
            if (arr[parent] >= arr[child]) {
                break;
            }
            int tmp = arr[parent];
            arr[parent] = arr[child];
            arr[child] = tmp;
            parent = child;
            child = parent * 2 + 1;
        }
    }

 注:建堆的复杂度为O(N)

4、堆的插入

       总共需要两个步骤:

            (1)先将元素放入底层空间中(空间不够时需要扩容)

            (2)将最后新插入的节点向上调整,直到满足堆的性质

private void shiftUp(int child) {
        if (child >= size) {
            return;
        }
        int parent = (child - 1) / 2;
        while (child > 0 && parent > 0) {
            if (elementData[child] <= elementData[parent]) {
                break;
            }
            swap(elementData,parent,child);
            child = parent;
            parent = (child - 1) * 2;
        }
    }
private void swap(int[] elementData, int parent, int child) {
        int tmp = elementData[parent];
        elementData[parent] = elementData[child];
        elementData[child] = tmp;
    }

 5、堆的删除

         删除的一定是堆顶元素

         步骤如下:

            (1)将堆顶元素与堆中最后一个元素进行交换

            (2)将堆中有效数据个数减少一个

            (3)对堆顶元素进行向下调整

private int poll() {
        if (isEmpty()) {
            throw new RuntimeException("数组为空");
        }
        int value = elementData[0];
        swap(elementData,0,size - 1);
        size--;
        shiftDown(0);
        return value;
    }

6、用堆模拟实现优先级队列

import java.util.Arrays;

public class Heap {
    private int[] elementData;
    private int size;
    private int DEFAULT_CAPACITY = 10;

    public Heap() {
        this.elementData = new int[DEFAULT_CAPACITY];
        this.size = 0;
    }
    public Heap(int[] array) {
        this.elementData = Arrays.copyOf(array, array.length);
        this.size = array.length;
        int parent = (size - 1 - 1) / 2;
        for (int i = parent;i >= 0;i--) {
            shiftDown(i);
        }
    }
    private void shiftDown(int parent) {
        if (parent < 0) {
            return;
        }
        int child = parent * 2 + 1;
        while (child < size) {
            if (child + 1 < size) {
                if (elementData[child] < elementData[child + 1]) {
                    child++;
                }
            }
            if (elementData[parent]  > elementData[child]) {
                break;
            }
            swap(elementData,parent,child);
            parent = child;
            child = parent * 2 + 1;
        }

    }
    private void offer(int value) {
        if (isFull()) {
            elementData = Arrays.copyOf(elementData,elementData.length * 2);
        }
        elementData[size] = value;
        size++;
        shiftUp(size - 1);
    }
    private void shiftUp(int child) {
        if (child >= size) {
            return;
        }
        int parent = (child - 1) / 2;
        while (child > 0 && parent > 0) {
            if (elementData[child] <= elementData[parent]) {
                break;
            }
            swap(elementData,parent,child);
            child = parent;
            parent = (child - 1) * 2;
        }
    }
    private boolean isFull() {
        return size == elementData.length;
    }
    private int poll() {
        if (isEmpty()) {
            throw new RuntimeException("数组为空");
        }
        int value = elementData[0];
        swap(elementData,0,size - 1);
        size--;
        shiftDown(0);
        return value;
    }
    private int peek() {
        return elementData[0];
    }
    private boolean isEmpty() {
        return size == 0;
    }
    private void swap(int[] elementData, int parent, int child) {
        int tmp = elementData[parent];
        elementData[parent] = elementData[child];
        elementData[child] = tmp;
    }

    public static void main(String[] args) {
        int[] array = {27,15,19,18,28,34,65,49,25,37};
    }
}

二、 优先级队列

1、优先级队列的特性

 注:

        (1)PriorityQueue中放置的元素必须要能够比较大小,否则会抛出ClassCastException异常

         (2)不能插入null对象,否则会抛出NullPointerException

         (3)没有容量限制,可以插入任意多个元素,内部可以自动扩容

         (4)PriorityQueue底层使用了堆数据结构

         (5)PriorityQueue默认情况下是小堆

2、常用的函数

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薰衣草2333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值