数据结构堆heap(以小根堆为例,大根堆类似)
关于堆的介绍和操作可以参考:https://www.jianshu.com/p/6b526aa481b1
上面这篇文章写得非常详细。
堆的操作主要有:插入元素、删除堆顶元素两个操作。
以下代码都以小根堆为例。
插入元素代码:
/** * 小根堆 * 在堆中插入元素 * * @param arr 堆数组 * @param size 当前堆的大小 * @param data 待插入的元素 */ public void heapInsert(int[] arr, final int size, int data) { //每个元素的父节点计算规则:parentIndex = (i-1)/2 //现将元素插入到堆最后一个位置 arr[size] = data; //开始shiftUp操作 int curIndex = size; int parentIndex = (curIndex - 1) / 2; while (parentIndex >= 0) { if (arr[curIndex] < arr[parentIndex]) { //子节点要比父节点小,需要作交换 int tmp = arr[parentIndex]; arr[parentIndex] = arr[curIndex]; arr[curIndex] = tmp; //进行下标上移 curIndex = parentIndex; parentIndex = (curIndex - 1) / 2; } else { //没有发生交换,说明已经有序了,退出 break; } } }
删除堆顶元素代码:
/** * 小根堆 * 删除堆顶元素 * * @param arr 堆数组 * @param size 当前堆的大小 * @return 新堆的大小 */ public int heapDelete(int[] arr, final int size) { if (size == 1) { //只剩一个元素了,直接删除 return size - 1; } //将根元素删除,将最后一个元素放置到根元素 arr[0] = arr[size - 1]; //开始shiftDown操作 int parentIndex = 0; int leftChildIndex = parentIndex * 2 + 1; int rightChildIndex = parentIndex * 2 + 2; while (leftChildIndex < size) { int smallest = arr[parentIndex]; int change = 0; //0表示不交换 if (smallest > arr[leftChildIndex]) { change = leftChildIndex; //可能会交换左节点 smallest = arr[leftChildIndex]; } if (rightChildIndex < size && smallest > arr[rightChildIndex]) { //需要交换右节点 change = rightChildIndex; } //如果change != 0,表示需要交换 if (change != 0) { int tmp = arr[parentIndex]; arr[parentIndex] = arr[change]; arr[change] = tmp; //再交换坐标 parentIndex = change; leftChildIndex = parentIndex * 2 + 1; rightChildIndex = parentIndex * 2 + 2; } else { //没有发生交换,直接退出循环 break; } } return size - 1; }
测试代码(创建堆、删除堆顶元素):
public void heapOps() { int[] arr = new int[]{100, 30, 3, 5, 80, 70, 200, 3000, 800, 10, 20, 50, 70}; //开始构建小根堆 for (int i = 1; i < arr.length; i++) { StringBuffer sb = new StringBuffer(); //仅用于输出 heapInsert(arr, i, arr[i]); sb.append("[ "); for (int j = 0; j <= i; j++) { sb.append(arr[j]).append(" "); } sb.append("]"); System.out.println(sb.toString()); sb.setLength(0); } //开始删除小根堆 for (int i = arr.length; i>0; i--){ StringBuffer sb = new StringBuffer(); //仅用于输出 sb.append("[ "); heapDelete(arr, i); for (int j = 0; j < i; j++) { sb.append(arr[j]).append(" "); } sb.append("]"); System.out.println(sb.toString()); sb.setLength(0); } }
输出结果:
[ 30 100 ] [ 3 100 30 ] [ 3 5 30 100 ] [ 3 5 30 100 80 ] [ 3 5 30 100 80 70 ] [ 3 5 30 100 80 70 200 ] [ 3 5 30 100 80 70 200 3000 ] [ 3 5 30 100 80 70 200 3000 800 ] [ 3 5 30 100 10 70 200 3000 800 80 ] [ 3 5 30 100 10 70 200 3000 800 80 20 ] [ 3 5 30 100 10 50 200 3000 800 80 20 70 ] [ 3 5 30 100 10 50 200 3000 800 80 20 70 70 ] [ 5 10 30 100 20 50 200 3000 800 80 70 70 ] [ 10 20 30 100 70 50 200 3000 800 80 70 ] [ 20 70 30 100 70 50 200 3000 800 80 ] [ 30 70 50 100 70 80 200 3000 800 ] [ 50 70 80 100 70 800 200 3000 ] [ 70 70 80 100 3000 800 200 ] [ 70 100 80 200 3000 800 ] [ 80 100 800 200 3000 ] [ 100 200 800 3000 ] [ 200 3000 800 ] [ 800 3000 ] [ 3000 ] [ ]