1. 堆的特点
- 堆的逻辑结构是数组,内存结构是完全二叉树.完全二叉树即只有最后一层才有叶子节点.
- 堆又分为大顶堆与小顶堆. 大顶堆的特点是 : 父亲节点比孩子节点的都要大. 小顶堆的特点与其相反.
- Java的优先级队列(PriorityQueue)的底层实现即用到了小顶堆. 所以下文我们就用Java代码来实现小顶堆.
- 本文没有像实现栈或队列那样使用了泛型,为了方便省去了泛型的步骤.
2. 小顶堆的实现
(1). 主要操作 :
- 堆化:传入一个数组,从下到上,最后一个非叶子节点开始,再从上到下不断进行下沉操作.
- offer()添加元素:从数组尾部添加元素,不断上浮.
- poll()弹出堆首元素.将堆首元素与最后一个叶子节点互换,size--,再从堆首开始下沉操作即可.
(2). 代码实现
//代码实现小顶堆
//逻辑结构是数组
public class MyHeap {private int size;private int[] heap;public MyHeap(int capacity) {heap = new int[capacity];}//堆化public void heapify(int[] arr) {for (int i = 0; i < arr.length; i++) {heap[i] = arr[i];}size = arr.length;//第一步 : 找到最后一个非叶子节点//第二步 : 从该节点出发, 从后往前, 以此堆化//size - 1即最后一个叶子节点, 依据公式, 该则为叶子节点的父亲节点for (int parent = (size - 1) / 2; parent >= 0; parent--) {int leftChild = parent*2 + 1;int rightChild = parent*2 + 2;int min = parent;//如果存在左孩子, 而且父亲节点比孩子节点要大if (leftChild < size && heap[min] > heap[leftChild]) {min = leftChild;}//如果存在右孩子, 而且右孩子的值比左孩子和父亲还要小if (rightChild < size && heap[min] > heap[rightChild]) {min = rightChild;}//如果最小值不是父亲, 那么需要下沉if (min != parent) {down(parent);}}}private void swap(int a, int b) {int temp;temp = heap[a];heap[a] = heap[b];heap[b] = temp;}private void down(int parent) {int leftChild = parent*2 + 1;int rightChild = parent*2 + 2;int min = parent;if (leftChild < size && heap[min] > heap[leftChild]) {min = leftChild;}if (rightChild < size && heap[min] > heap[rightChild]) {min = rightChild;}if (min != parent) {swap(min, parent);down(min);}}//向堆中添加元素, 如果该添加的元素比父亲节点(如果有的话)要小,//则需要上浮public void offer(int a) {if (size > heap.length) {return;}heap[size] = a;int child = size;size++;int parent;while (child >= 0) {parent = (child - 1) / 2;//如果添加的元素要比父亲要小if (heap[parent] > heap[child]) {swap(parent, child);child = parent;} else {//如果添加后父亲节点仍然符合小顶堆, 那么退出循环, 无需再上浮break;}}}//返回堆顶元素public int peek() {return heap[0];}//弹出堆顶元素//第一步 : 将最后一个叶子节点与堆顶元素互换, size--//第二步 : 从堆顶开始不断下沉public int poll() throws Exception {if (size == 0) {throw new Exception();}int value = peek();swap(0, size - 1);size--;//不断下沉int parent = 0;down(parent);return value;}
}
3. 单元测试
public class MyHeapTest {@Testpublic void test1() throws Exception {MyHeap heap = new MyHeap(10);int[] arr = new int[]{9, 12, 4, 3, 1};heap.heapify(arr);System.out.println(heap.peek());//1System.out.println(heap.poll());//1System.out.println(heap.peek());//3heap.offer(0);System.out.println(heap.peek());//0}
}