• Java优先级队列(堆)


    目录

    1.堆的性质

    2.堆的存储方式

    3.堆的创建

    4.堆的增删查改

    4.1 offer() 增添元素

    4.2 peek() 获取堆顶元素

    4.3 pop() 弹出堆顶第一个元素并返回

    5.堆排序


    1.堆的性质

    大根堆:根节点为最大的堆。

    小根堆:根节点为最小的堆。

    堆总是一颗完全二叉树。

    2.堆的存储方式

    堆的底层是一个数组,但是在应用的时候会将其看成一颗完全二叉树,所以他也有一些二叉树的性质:

    假设i为元素的下标

    (1)i不为0的节点的双亲节点的下标为:(i-1)/ 2;如果i为0,那i就是根节点。

    (2)下标为i的节点的左孩子下标:i*2+1,否则没有左孩子

    (3)下标为i的节点的右孩子下标:i*2+2,否则没有右孩子

    3.堆的创建

    堆的底层是一个数组,所以在创建堆之前要先建立一个数组

    1. public class TestHeap {
    2. public int[] elem;
    3. public int usedSize;//数组元素个数
    4. public static final int DEFAULT_SIZE = 10;//数组的初始容量
    5. public TestHeap() {
    6. elem = new int[DEFAULT_SIZE];
    7. }
    8. }

    我们以大根堆为例

    既然是创建大根堆,那么它的每颗子树都需要保证根节点是该树的最大值,所以我们从最后一个有孩子的子树开始对堆依此进行向下调整:

    首先找到该子树的左孩子节点,然后进入循环,每次找到左右孩子的最大值,让其与双亲节点相比较,大的放到双亲节点,然后让双亲节点指向孩子节点,进行循环操作,直到双亲节点的下标超过节点总数(等于也不行)

    1. public void createHeap(int[] array) {
    2. for (int i = 0; i < array.length; i++) {
    3. elem[i] = array[i];
    4. usedSize++;
    5. }
    6. for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {
    7. shiftDown(parent, usedSize);//向下调整
    8. }
    9. }
    10. public void shiftDown(int parent, int len) {
    11. int child = parent * 2 + 1;
    12. while (child < len) {
    13. if (child + 1 < len && elem[child] < elem[child + 1]) {
    14. child++;
    15. }
    16. if (elem[parent] < elem[child]) {
    17. int tmp = elem[parent];
    18. elem[parent] = elem[child];
    19. elem[child] = tmp;
    20. parent = child;
    21. child = parent * 2 + 1;
    22. } else {
    23. break;
    24. }
    25. }
    26. }

    4.堆的增删查改

    4.1 offer() 增添元素

    将新增的元素放到队尾,然后对其进行向上调整,和向下调整类似,只不过顺序由下向上,并且新增的元素一次只有一个,所以只需要进行一次即可

    1. public void offer(int val) {
    2. if (isFull()) {
    3. //扩容
    4. this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
    5. }
    6. this.elem[this.usedSize] = val;
    7. this.usedSize++;
    8. //向上调整
    9. shiftUp(usedSize - 1);
    10. }
    11. private boolean isFull() {
    12. return this.usedSize == this.elem.length;
    13. }
    14. public void shiftUp(int child) {
    15. int parent = (child - 1) / 2;
    16. while (parent >= 0) {
    17. if (elem[parent] < elem[child]) {
    18. int tmp = elem[parent];
    19. elem[parent] = elem[child];
    20. elem[child] = tmp;
    21. child = parent;
    22. parent = (parent - 1) / 2;
    23. } else {
    24. break;
    25. }
    26. }
    27. }

    4.2 peek() 获取堆顶元素

    直接返回数组的第一个元素

    1. //判断堆是否为空
    2. private boolean isEmpty() {
    3. return this.usedSize == 0;
    4. }
    5. public int peek() {
    6. if (isEmpty()) {
    7. return -1;
    8. }
    9. return this.elem[0];
    10. }

    4.3 pop() 弹出堆顶第一个元素并返回

    弹出元素相当于删除元素,将首元素和尾元素交换将其删除,然后进行向下调整

    1. public int pop() {
    2. if (isEmpty()) {
    3. return -1;
    4. }
    5. int tmp = elem[0];
    6. elem[0] = elem[this.usedSize - 1];
    7. elem[this.usedSize - 1] = tmp;
    8. //删除最后一个元素
    9. this.usedSize--;
    10. //向下调整
    11. shiftDown(0, usedSize);
    12. return tmp;
    13. }

    5.堆排序

    对堆进行升序排序,需要建立大根堆,每次将堆顶元素放到相对应的尾部,然后再进行像下调整,比如:第一次放到到i位置,下一次放到i-1位置,以此类推……

    1. public void heapSort() {
    2. int end = usedSize - 1;
    3. while (end > 0) {
    4. //将堆顶元素与其相对的位置交换
    5. int tmp = elem[end];
    6. elem[end] = elem[0];
    7. elem[0] = tmp;
    8. //向下调整,将最大值放到堆顶
    9. shiftDown(0, end);
    10. end--;
    11. }
    12. }

  • 相关阅读:
    自媒体时代,短视频创业是最赚钱的项目
    javafx-如何在项目中使用多个main函数
    作业 5.1——运输层
    接口压力测试 jmeter--进阶篇(三)
    Spring boot(2)
    C#操作MySQL从入门到精通(22)——创建表与操纵表
    Zookeeper leader选举源码分析(超详细)
    剑指 Offer 2022/6/29
    C#如何批量创建类
    加工制造业的升级突破必备系统
  • 原文地址:https://blog.csdn.net/m0_64318128/article/details/127547479