本文主要内容:
1.堆的向上调整、向下调整
2.建大堆、建小堆
3.优先级队列
4.TopK问题
1.二叉树可以用数组的形式保存吗?
可以,按照层序的方式把值平铺在数组上(完全二叉树)
非完全二叉树平铺到数组上会有很多的空洞,往往不用这种方式(堆)
2.关注下标的变化
已知parent的下标,左孩子的下标为2parent+1,右孩子的下标为2parent+2
已知child的下标(不分左右孩子),parent= (child-1)/2
3.堆
(1)在逻辑上是一颗完全二叉树
(2)物理上是一个数组(写代码时当数组处理)
(3)满足任意位置的值大于等于它的左右孩子的值(大堆),反之小堆。
堆的基本功能:找最值
4.关于堆,有以下几个重要操作:
向下调整(堆化)
前提:在整个堆中,除了要调整的位置之外,其余位置都已经满足堆的性质
(1)找到两个孩子中最大的孩子
(2)比较最大孩子的值和要调整位置的值,如果满足堆的性质就不需要调整了,否则交换两者的值。继续调整原来最大孩子的下标位置
注意:如果要调整的位置是叶子结点就不需要调整了
前提:除了index位置外,其他位置都满足堆的性质,经过向下调整
首先判断index位置是不是叶子结点,即结点的左孩子是不是大于等于size,接着判断index结点是否有右孩子(分为三种情况),如果有右孩子,判断右孩子的值与左孩子的值,取最大的,然后用最大的与index结点比较,如果满足堆性质,不交换,否则交换,继续判断下面的结点。
5.建堆:任意数组转成堆(建堆的时间复杂度为O(n),粗略为nO(log(n)))
从最后一个非叶子结点向上调整
如果算法中出现了二叉树(接近完全二叉树)
如果算法的消耗时间与高度有关:
(1)结点个数为n
(2)最后一层结点个数为n
时间复杂度均为O(log(n))
log(1000)约等为10 log(100万) 约等于20 log(10亿)约为30
应用:
(1)优先级队列:在java中自带优先级队列PriorityQueue,如何实现优先级队列?
(2)TopK问题(3)堆排序
6.实现优先级队列
7.找到最大的k个数(建小堆[向下调整])
public class Solution2 {
//创建一个数组,元素随机
public static int[] createArray(){
Random random = new Random(135531);
int[] array = new int[10];
for(int i = 0;i<array.length;i++){
int a = random.nextInt(100);
array[i] = a;
}
return array;
}
//打印数组
public static void showArray(int[] array){
for(int i =0;i<array.length;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
//交换
public static void swap(int[] array,int a,int b){
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
//堆化,即向下调整(时间复杂度:log(n))
//首先判断下标为index的位置是否为叶子结点,如果不是,则需要判断index结点的父结点是否有右孩子
//如果有右孩子,则取左右孩子结点中最大的与父节点进行比较,如果孩子结点大,则与其父节点进行交换,继续向下调整
public static void heapifyMax(int[] array,int size,int index) {
while (true) {
int left = 2 * index + 1;
if (left >= size) {
return;
}
int max = left;
int right = left + 1;
if (right < size && array[right] > array[max]) {
max = right;
}
if (array[index] >= array[max]) {
return;
}
swap(array, index, max);
index = max;
}
}
public static void createMaxHeap(int[] array,int size){
//建大堆:时间复杂度:n*log(n)
//从最后一个结点的父节点往前遍历,依次做向下调整
for(int i = (size-2)/2;i>=0;i--){
heapifyMax(array,size,i);
}
}
//向上调整
//首先判断index位置是否小于size,然后让index结点与它的父节点进行比较,如果父节点较小则两者交换,继续调整
public static void adjustUp(int[] array,int index){
while (index>0){
int parent = (index-1)/2;
if(array[parent]>=array[index]){
return;
}
swap(array,parent,index);
index = parent;
}
}
public static void heapifyMin(int[] array,int size,int index){
while (true) {
int left = 2 * index + 1;
if (left >= size) {
return;
}
int min = left;
if (left+1< size && array[left+1] < array[min]) {
min = left+1;
}
if (array[index] <= array[min]) {
return;
}
swap(array, index, min);
index = min;
}
}
public static void createMinHeap(int[] array,int size){
//建小堆
//从最后一个结点的父节点往前遍历,依次做向下调整
for(int i = (size-2)/2;i>=0;i--){
heapifyMin(array,size,i);
}
}
public static void main(String[] args) {
int[] a = createArray();
showArray(a);
createMaxHeap(a,a.length);
showArray(a);
System.out.println("================================");
createMinHeap(a,a.length);
showArray(a);
}
}
//运行结果:
39 91 83 19 40 0 11 61 51 73
91 73 83 61 40 0 11 19 51 39
================================
0 19 11 51 39 83 91 61 73 40
public class MyPriorityQueue {
//先不考虑array存不下数据的情况
private int[] array = new int[100];
private int size;
//O(log(n))
public void add(int element){
array[size++] = element;
Solution2.adjustUp(array,size-1);
}
//O(log(n))
public int pop(){
int e = array[0];
array[0]=array[--size];
Solution2.heapifyMin(array,size,0);
return e;
}
//O(1)
public int peek(){
return array[0];
}
}
public class PriorityQueueDemo {
public static void main(String[] args) {
PriorityQueue<Integer> queue1 = new PriorityQueue<>();
Queue<Integer> queue2 = new LinkedList<>();
Random random = new Random(20190828);
for(int i = 0;i<10;i++){
int a = random.nextInt(100);
queue1.add(a);
queue2.add(a);
}
while (!queue1.isEmpty()){
int a = queue1.poll();
System.out.print(a+" ");
}
System.out.println();
while (!queue2.isEmpty()) {
int a = queue2.poll();
System.out.print(a + " ");
}
System.out.println();
}
}
//运行结果:
2 4 16 20 27 37 49 67 81 89
89 4 37 16 67 81 20 27 2 49
public class TopKDemo {
//在多个元素中找前k名,建小堆
public static int[] TopK(int[] array,int k){
int[] heap = new int[k];
for(int i = 0;i<k;i++){
heap[i] = array[i];
}
Solution2.createMinHeap(heap,heap.length);
for(int i = k;i<array.length;i++){
if(array[i]>heap[0]){
heap[0] = array[i];
Solution2.heapifyMin(heap,k,0);
}
}
return heap;
}
public static void main(String[] args) {
Random random = new Random(114158);
int[] array = new int[100];
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(1000);
}
int[] topK = TopK(array, 5);
System.out.println(Arrays.toString(topK));
System.out.println("====================================");
Arrays.sort(array);
System.out.println(Arrays.toString(
Arrays.copyOfRange(array, array.length-10, array.length)
));
}
}
//运行结果:
[884, 895, 975, 989, 917]
====================================
[859, 862, 867, 868, 876, 884, 895, 917, 975, 989]
来源:https://blog.csdn.net/weixin_43256788/article/details/100127040