优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。
实际上是一个堆(不指定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.若已读取的个数为偶数(包括0)时,两个堆的数目已经相同,将新读取的数插入到小顶堆中,从而实现小顶堆的个数多一。但是,如果新读取的数字比大顶堆中最大的数字还小,就不能直接插入到小顶堆中了 ,此时必须将新数字插入到大顶堆中,而将大顶堆中的最大数字插入到小顶堆中,从而实现小顶堆的个数多一。
2若已读取的个数为奇数时,小顶堆的个数多一,所以要将新读取数字插入到大顶堆中,此时方法与上面类似。
这个例题答案在这里https://www.cnblogs.com/yongh/p/9944993.html、
你有一个数列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