堆的基本知识及应用

廉价感情. 提交于 2019-11-28 21:45:52

本文主要内容:
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]

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!