大顶堆和小顶堆-java

一、大顶堆和小顶堆的原理

1、大顶堆

  • 根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大顶堆。大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。

2、小顶堆

  • 根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者,称为小顶堆。小根堆要求根节点的关键字既小于或等于左子树的关键字值,又小于或等于右子树的关键字值。

3、大顶推和小顶堆的实现

public class MaxHeap {
    public static void main(String[] args) {
        //原始数组内容
        int i,size,data[]={0,5,6,10,8,3,2,19,9,11};

        size=data.length;

        System.out.print("原始数组:");

        for(i=1;i<size;i++)
            System.out.print("["+data[i]+"] ");

        System.out.println("");
        //建立堆积树
        MaxHeap.heap(data,size);
    }
    public static void heap(int data[] ,int size)
    {
        int i,j,tmp;
        //建立堆积树节点
        for(i=(size/2);i>0;i--)
            MaxHeap.ad_heap(data,i,size-1);
        System.out.print("\n堆积内容:");
        //原始堆积树内容
        for(i=1;i<size;i++)
            System.out.print("["+data[i]+"] ");
    }

    public static void ad_heap(int data[],int i,int size){
        int j,tmp,post;
        j=2*i;
        tmp=data[i];
        post=0;
        while(j<=size && post==0)
        {
            if(j<size)
            {
                //小顶堆的比较           
                //if(data[j]>data[j+1])  
                //找出两个子节点最大值
                if(data[j]<data[j+1])  
                    j++;
            }
            //小顶堆的比较
            //if(tmp<=data[j])   
            //若树根较大,结束比较过程
            if(tmp>=data[j])    {
                post=1;  
            } else {
                //若树根较小,则继续比较,这里将最大子节点赋值给父节点
                data[j/2]=data[j];     
                j=2*j;
            }
        }
        //指定树根为父节点
        data[j/2]=tmp;                
    }
}

二、小顶堆的应用

1、求最大的k个数

  • 1、求10亿个数中的最大的前10个数,时时构建只有10个元素的小顶堆,如果比堆顶小,则不处理;如果比堆顶大,则替换堆顶,然后依次下沉到适当的位置。 详细讲解请看公众号:码农有道
  • 2、选择最大的K个数
public class findTopK {
    //用PriorityQueue默认是自然顺序排序,要选择最大的k个数,构造小顶堆,每次取数组中剩余数与堆顶的元素进行比较,如果新数比堆顶元素大,则删除堆顶元素,并添加这个新数到堆中。
    //找出前k个最大数,采用小顶堆实现
    public static int[] findKMax(int[] nums, int k) {
        //队列默认自然顺序排列,小顶堆,不必重写compare
        PriorityQueue<Integer> pq = new PriorityQueue<>(k);
        
        for (int num : nums) {
            if (pq.size() < k) {
                pq.offer(num);
                //如果堆顶元素 < 新数,则删除堆顶,加入新数入堆
            } else if (pq.peek() < num) {
                pq.poll();
                pq.offer(num);
            }
        }
        
        int[] result = new int[k];
        for (int i = 0; i < k&&!pq.isEmpty(); i++) {
            result[i] = pq.poll();
        }
        return result;
    }

 public static void main(String[] args) {
        int[]arr=new int[]{1, 6, 2, 3, 5, 4, 8, 7, 9};
        System.out.println(Arrays.toString(findKMax( arr,5)));
    }
}

2、数组中的第K个最大元素

 // 小顶堆
  PriorityQueue<Integer> pq = new PriorityQueue<>();
    for (int val : nums) {
        pq.add(val);
        // 维护堆的大小为 K
        if (pq.size() > k) {
        //弹出最顶端的数,并删除
             pq.poll();
        }
    }
    //取最顶端的数
    return pq.peek();
    }

三、大顶堆的应用

  • PriorityQueue通过传入自定义的compara函数可以实现大顶堆

1、要选择最小的K个数使用大顶堆,每次取数组中剩余数与堆顶的元素进行比较,如果新数比堆顶元素小,则删除堆顶元素,并添加这个新数到堆中。

public static int[] findKMin(int[] nums,int k ){
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int num:nums){
            if (pq.size() <k){
                pq.offer(num);
                //如果堆顶元素 > 新数,则删除堆顶,加入新数入堆
            }else if(pq.peek() > num){
                pq.poll();
                pq.offer(num);

            }
        }
        int[] result = new int[k];
        for (int i = 0;i<k&&!pq.isEmpty();i++){
            result[i] = pq.poll();
        }
        return result;
    }

    public static void main(String[] args) {
        int[]arr=new int[]{1, 6, 2, 3, 5, 4, 8, 7, 9};
        System.out.println(Arrays.toString(findKMin( arr,5)));
    }

2、数组中的第K个最小元素

   public static int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int val : nums) {
            pq.add(val);
            // 维护堆的大小为 K
            if (pq.size() > k) {
                pq.poll();
            }
        }
        return pq.peek();
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值