Priority Queue(优先队列)最大堆最小堆

优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。

实际上是一个堆(不指定Comparator时默认为最小堆),通过传入自定义的Comparator函数可以实现大顶堆。

这个特性能让写java的我们少了一大堆的建堆过程啊!!!

import java.util.Comparator;
import java.util.PriorityQueue;

class test3{
    public static void main(String[] args) {
        PriorityQueue minHeap = new PriorityQueue(); //小顶堆,默认容量为11
        PriorityQueue maxheap =  new PriorityQueue<>(11, new Comparator(){

            @Override
            public int compare(Integer i1, Integer i2) {
                return i2-i1;
            }

        });
    }
}

常用方法:peek():  获取但不移除此列的头,如果头为一,返回null

     我试了试remove()也可以哎??

     poll()获取而且移除此列的头,若此列为空,返回null

     toArray()返回包含此列内容的数组 

更多详细方法 http://www.cnblogs.com/yongh/p/9945539.html

1、题目 

  如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

思路

  所谓数据流,就是不会一次性读入所有数据,只能一个一个读取,每一步都要求能计算中位数。

  将读入的数据分为两部分,一部分数字小,另一部分大。小的一部分采用大顶堆存放,大的一部分采用小顶堆存放。当总个数为偶数时,使两个堆的数目相同,则中位数=大顶堆的最大数字与小顶堆的最小数字的平均值;而总个数为奇数时,使小顶堆的个数比大顶堆多一,则中位数=小顶堆的最小数字。

  因此,插入的步骤如下:

  1.若已读取的个数为偶数(包括0)时,两个堆的数目已经相同,将新读取的数插入到小顶堆中,从而实现小顶堆的个数多一。但是,如果新读取的数字比大顶堆中最大的数字还小,就不能直接插入到小顶堆中了 ,此时必须将新数字插入到大顶堆中,而将大顶堆中的最大数字插入到小顶堆中,从而实现小顶堆的个数多一。

  2若已读取的个数为奇数时,小顶堆的个数多一,所以要将新读取数字插入到大顶堆中,此时方法与上面类似。

这个例题答案在这里https://www.cnblogs.com/yongh/p/9944993.html、

2、

你有一个数列a1,a2,a3,…an 。你可以进行这样的一次操作,每次选择数列中其中一个数然后将其除2下取整,也就是选择一个数ai,变成⌊ai/2⌋。

请问对这些数字进行不超过k次操作,这些数字的总和最小值可能是多少。

第一行两个整数n,k。(1 ≤ n ≤ 105,0 ≤ k ≤ 109),表示数字个数和操作个数。
接下来n行,一共n个整数a1,a2,a3,…an,保证 1 <= ai <= 109。

样例输入

5 3
2 4 7 9 7

样例输出

16

因为要求数字总和最小,所以使用堆排序(构造大顶堆)每次弹出最大的再除2后放入堆中。最后把堆中所有值加起来即为数字最小总和。 使用堆排就不需要再去每次遍历去找最大的了;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;

class test3{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int result =0;
        int coop = sc.nextInt();
        //下面是两种不同的写法,输出是一样的
//        PriorityQueue pq = new PriorityQueue<>(n,(Integer a,Integer b)->{
//           return b-a;
//        });
        PriorityQueue pq = new PriorityQueue<>(n, new Comparator() {
            @Override
            public int compare(Integer integer, Integer t1) {
                return t1-integer;
            }
        });
        for(int i=0;i

2、题目:数据流中的中位数 
获取数据流中的中位数。如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

因为要每一步都可以求出中位数,所以不能每一次都排序,

 

主要思路:可以把输入数据平分成两部分,左边的数据都小于右边的数据,那么即使左右两边内部的数据没有排序,也可以根据左边最大的数和右边最小的数获取中位数。关键是,怎么获取左边的最大值和右边的最小值,并且保持左右两部分的个数之差不超过1? 
   可以借助最大堆和最小堆来实现,同时轮流把数据添加到左右部分。为了保证最小堆(右半部分)的所有元素都大于最大堆(左半部分)的所有元素,若当前数字本来要添加到最小堆中,但是当前数字比最大堆的最大值还小,那么,先把该数字添加到最大堆中,再把最大堆中的最大数字移出到最小堆中,这样就能保证最小堆中的所有元素都大于最大堆中的所有元素;若当前数字本来要添加到最大堆中,但是当前数字比最小堆的最小值还大,类似的,先添加该数字到最小堆,再移出最小堆的最小数字到最大堆。

这个,,,有一点点难懂,但是要好好考虑呀,

刚开始我写的代码一直报空指针异常,,,找了好久才突然想起来自己没有去把isodd来回变化奇偶数,,调试了好久才成功运行

import java.util.Comparator;
import java.util.PriorityQueue;

public class Test48 {
    static PriorityQueue big = new PriorityQueue<>();
//    static PriorityQueue small = new PriorityQueue<>(n, new Comparator() {
//        @Override
//        public int compare(Integer integer, Integer t1) {
//            return t1-integer;
//        }
//    });
    static PriorityQueue small = new PriorityQueue<>(Comparator.reverseOrder());
    static boolean isodd  = true;
    public static void main(String[] args) {
        insert(5);
        System.out.println(getmedian());//5.0
        insert(2);
        System.out.println(getmedian());//3.5
        insert(3);
        System.out.println(getmedian()); //3.0
        insert(4);
        System.out.println(getmedian()); //3.5
    }
    static void insert(int cur){
        if(isodd){
//为奇数本来要作为一个小数字添加到左边大顶堆,但是他要是比右边最小值要大的话,那就把他加到右边小顶堆,再把小顶堆最小值放到左边去
            if(small.size()>0 && cur>small.peek()){
                small.offer(cur);
              big.add(small.poll());

            }else {
                big.add(cur);
            }
        }else {
//为偶数本来要作为一个大数添加到右边,但是他要是比左边最大的数要小,那就先把他加到左边,再把左边最大值加到右边
            if(big.size()>0 && cur

 

你可能感兴趣的:(算法其他)