Java优先级队列(堆)
迪丽瓦拉
2024-03-31 22:17:33
0

目录

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.堆的创建

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

public class TestHeap {public int[] elem;public int usedSize;//数组元素个数public static final int DEFAULT_SIZE = 10;//数组的初始容量public TestHeap() {elem = new int[DEFAULT_SIZE];}
}

我们以大根堆为例

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

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

    public void createHeap(int[] array) {for (int i = 0; i < array.length; i++) {elem[i] = array[i];usedSize++;}for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(parent, usedSize);//向下调整}}public void shiftDown(int parent, int len) {int child = parent * 2 + 1;while (child < len) {if (child + 1 < len && elem[child] < elem[child + 1]) {child++;}if (elem[parent] < elem[child]) {int tmp = elem[parent];elem[parent] = elem[child];elem[child] = tmp;parent = child;child = parent * 2 + 1;} else {break;}}}

4.堆的增删查改

4.1 offer() 增添元素

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

    public void offer(int val) {if (isFull()) {//扩容this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);}this.elem[this.usedSize] = val;this.usedSize++;//向上调整shiftUp(usedSize - 1);}private boolean isFull() {return this.usedSize == this.elem.length;}public void shiftUp(int child) {int parent = (child - 1) / 2;while (parent >= 0) {if (elem[parent] < elem[child]) {int tmp = elem[parent];elem[parent] = elem[child];elem[child] = tmp;child = parent;parent = (parent - 1) / 2;} else {break;}}}

4.2 peek() 获取堆顶元素

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

    //判断堆是否为空private boolean isEmpty() {return this.usedSize == 0;}public int peek() {if (isEmpty()) {return -1;}return this.elem[0];}

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

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

    public int pop() {if (isEmpty()) {return -1;}int tmp = elem[0];elem[0] = elem[this.usedSize - 1];elem[this.usedSize - 1] = tmp;//删除最后一个元素this.usedSize--;//向下调整shiftDown(0, usedSize);return tmp;}

5.堆排序

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

    public void heapSort() {int end = usedSize - 1;while (end > 0) {//将堆顶元素与其相对的位置交换int tmp = elem[end];elem[end] = elem[0];elem[0] = tmp;//向下调整,将最大值放到堆顶shiftDown(0, end);end--;}}

相关内容