较为全面的堆知识

堆(heap)

概念:

  1. 堆逻辑上是一棵完全二叉树
  2. 堆物理上是保存在数组中
  3. 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
  4. 反之,则是小堆,或者小根堆,或者最小堆
  5. 堆的基本作用是,快速找集合中的最值

二叉树的顺序存储中就用到了堆,接下来就根据二叉树来创建一个小根堆
在这里插入图片描述

  1. index 如果已经是叶子结点,则整个调整过程结束
  2. 判断 index 位置有没有孩子
  3. 因为堆是完全二叉树,没有左孩子就一定没有右孩子,所以判断是否有左孩子
  4. 因为堆的存储结构是数组,所以判断是否有左孩子即判断左孩子下标是否越界,即 left >= size 越界
  5. 确定 left 或 right,谁是 index 的最小孩子 min
  6. 如果右孩子不存在,则 min = left
  7. 否则,比较 array[left] 和 array[right] 值得大小,选择小的为 min
  8. 比较 array[index] 的值 和 array[min] 的值,如果 array[index] <= array[min],则满足堆的性质,调整结束
  9. 否则,交换 array[index] 和 array[min] 的值
  10. 然后因为 min 位置的堆的性质可能被破坏,所以把 min 视作 index,向下重复以上过程
public static void shiftDown(int[] array, int size, int index) {
    int left = 2 * index + 1;
    while (left < size) {
        int min = left;
   int right = 2 * index + 2;
        if (right < size) {
            if (array[right] < array[left]) {
                min = right;
           }
       }
        
        if (array[index] <= array[min]) {
            break;
       }
        
        int t = array[index];
        array[index] = array[min];
        array[min] = t;
        index = min;
        left = 2 * index + 1;
   }
}
public static void createHeap(int[] array, int size) {
    for (int i = (size - 1 - 1) / 2; i >= 0; i--) {
        shiftDown(array, size, i);
   }
}

堆的应用(优先级队列)

概念:在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。
入队列

  1. 首先按尾插方式放入数组
  2. 比较其和其双亲的值的大小,如果双亲的值大,则满足堆的性质,插入结束
  3. 否则,交换其和双亲位置的值,重新进行 2、3 步骤
  4. 直到根结点

出队列(优先级最高)
为了防止破坏堆的结构,删除时并不是直接将堆顶元素删除,而是用数组的最后一个元素替换堆顶元素,然后通过向下调整方式重新调整成堆

public static void shiftUp(int[] array, int index) {
    while (index > 0) {
        int parent = (index - 1) / 2;
        if (array[parent] >= array[index]) {
            break;
       }
        
        int t = array[parent];
        array[parent] = array[index];
        array[index] = t;
        
        index = parent;
   }
}
public class MyPriorityQueue {
    
    private int[] array = new int[100];
    private int size = 0;
    //入队列
    public void offer(int e) {
        array[size++] = e;
        shiftUp(array, size - 1);
   }
    //出队列
    public int poll() {
        int oldValue = array[0];
        array[0] = array[--size];
        shiftDown(array, size, 0);
        return oldValue;
   }
    
    public int peek() {
        return array[0];
   }
}

TOPK问题

查找和最小的K对数字

一般这种问题建一个大小为K的堆,查最小(建大堆),查最大(建小堆),本题建一个大小为k的大堆,然后将[0,k-1]中的元素放进去,然后遍历[k,n]中的元素与堆中的元素比较,如果比堆中的元素小,则和队中元素互换位置。

public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
       List<List<Integer>> list=new ArrayList<List<Integer>>();
       PriorityQueue<List<Integer>> heap=new PriorityQueue<List<Integer>>((a,b)->{
           return -(a.get(0)+a.get(1))+(b.get(0)+b.get(1));
       });
       for(int i=0;i<nums1.length;i++){
           for(int j=0;j<nums2.length;j++){
               List<Integer> res=null;
               if(heap.size()<k){
                   res=new ArrayList<Integer>();
                   res.add(nums1[i]);
                   res.add(nums2[j]);
                   heap.offer(res);
               }else{
                   List<Integer> peek=heap.peek();
                   if(nums1[i]+nums2[j]<peek.get(0)+peek.get(1)){
                       res=new ArrayList<Integer>();
                       heap.poll();
                       res.add(nums1[i]);
                       res.add(nums2[j]);
                       heap.offer(res);
                   }else{
                       break;
                   }
               }
           }
       }
    while(heap.size()>0){
        list.add(heap.poll());
    }
    return list;
    }

堆排序

原理
基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。
注意: 排升序要建大堆;排降序要建小堆

 public static void adjust(int[] array,int parent,int len){
        int child=2*parent+1;
        while(child<len){
           if(child+1<len&&array[child]<array[child+1]){
               child++;  
             }
            if(array[child]>array[parent]){
                int tmp=array[parent];
                array[parent]=array[child];
                array[child]=tmp;
                parent=child;
                child=parent*2+1;
            }else{
                  break;
             }
        }
    }
    
    public static void createHeap(int[] array){
        for(int i=(array.length-1-1);i>=0;i--){
            adjust(array,i,array.length);
        }
    }
    public static void heapSort(int[] array){
        createHeap(array);
        int end=array.length;
        while(end>0){
            int tmp=array[end];
            array[end]=array[0];
            array[0]=tmp;
            adjust(array,0,end);
            end--;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值