题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
Java中的优先队列PriorityQueue
java.lang.Object
继承者java.util.AbstractCollection
继承者java.util.AbstractQueue
继承者java.util.PriorityQueue,已实现接口Serializable,Iterable,Collection,Queue
PriorityQueue是Java中的优先队列,它实现了Queue接口,不允许放入null值通过**小顶堆(最小堆)**实现,在JDK1.5中引入。
PriorityQueue对内部的元素采用的是堆排序,而且是最小堆(小顶堆)实现,此队列的头是按指定排序方式确定的最小元素,如果多个元素都是最小值,则头是其中的一个元素。最小堆排序只能保证堆顶元素是最小的,整个堆并不是有序的。
该集合内可以存放基本数据类型对象包装类(如:Integer,Long等)或者自定义的类。对于基本数据类型对象包装类,优先队列中的元素默认排列顺序是降序排列(小顶堆/最小堆),对应PriorityQueue的空参数构造函数,根据元素的自然顺序来排序(此时不允许插入不可比较的对象,否则会发生ClassCastException);如果想要升序排列(大顶堆/最大堆),可以自定义一个比较器(定义一个类或者匿名内部类实现Comparator< T >接口,并复写该接口中的public int compare(T o1,T o2)方法),并将该比较器作为参数传递给PriorityQueue类的构造函数。但是对于自定义的类而言,需要自己定义比较器(定义一个类或者匿名内部类实现Comparator< T >接口,并复写该接口中的public int compare(T o1,T o2)方法)。
//实现大顶堆,自定义比较器
//创建一个匿名内部类对象
Comparator<Integer> comp = new Comparator<Integer>()
{
public int compare(Integer e1,Integer e2)
{
return e2 - e1;
}
};
优先队列PriorityQueue是无界的,它会根据队列中元素的数量动态地增长。但是它有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列中添加元素,其容量会自动增加,因而无需指定容量增加策略的细节。
int i = size;
if(i >= queue.size)
grow(i + 1);
size = i + 1;
该类中的构造方法如下:
该类中的常用方法如下:
PS:
(1)优先级队列是通过数组实现的,但是该数组大小可以动态增加,容量无限。
(2)PriorityQueue不是同步的,不是线程安全的。对应的PriorityBlockingQueue 类是线程安全的类。
(3)队列中不能存放 null 元素。
(4)此实现为插入方法(offer(E e)、add(E e) 、poll()、remove()方法)提供 O(log(n)) 时间;为 remove(Object o) 和contains(Object o) 方法提供线性时间;为检索方法(peek()、element() 和 size())提供固定时间。
(5)方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。如果需要按顺序遍历,可以使用 Arrays.sort(arr)的方法(默认升序)。
转载:toArray()方法的使用问题https://blog.csdn.net/zy103118/article/details/81479118
Object[] arr = queue.toArray();//将集合转换为数组
Arrays.sort(arr);//默认是升序
(6)可以在PriorityQueue的构造函数中指定如何排序。
空参数构造函数PriorityQueue():使用默认的初始容量(大小为11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(元素自身必须具备比较性即实现了 Comparable接口,否则会发生ClassCastException)。
PriorityQueue(int initialCapacity):使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(元素自身必须具备比较性即实现了 Comparable接口)。
PriorityQueue(int initialCapacity, Comparator comparator):使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器comparator来排序其元素(有了comparator,优先按照comparator进行排序)。
(7)此类及其迭代器实现了 Collection 接口和 Iterator 接口的所有可选方法。
数据流中的中位数的Java代码如下:
import java.util.*;
public class Solution
{
//优先队列,是以最小堆(小顶堆)实现的,堆顶元素必为最小值,优先队列头部的元素是队列中的最小元素
private PriorityQueue<Integer> min = new PriorityQueue<Integer>();
//自定义比较器并将其作为参数传入PriorityQueue的构造函数中,实现大顶堆
private Comparator<Integer> comp = new Comparator<Integer>()//建立一个匿名内部类对象
{
public int compare(Integer e1,Integer e2)
{
return e2 - e1;
}
};
private PriorityQueue<Integer> max = new PriorityQueue<Integer>(comp);
public void Insert(Integer num)
{
int value = 0;
//为保证数据平均分配到两个堆中,因此两个堆中的数据的数目之差不能超过1(<=1)
//数据总数目是偶数时,将新数据插入最小堆
if(((min.size() + max.size()) & 1) == 0)//位运算比乘除运算的效率要高
{
//为了保证大顶堆中的元素都小于小顶堆中的元素
//判断该新数据是否小于大顶堆中的元素
if(max.size() > 0 && num < max.peek())//获取队列头部的元素(在大顶堆中,是此优先队列中的最大元素)
{
//先把新数据插入大顶堆,然后把大顶堆中的最大元素取出插入小顶堆
max.add(num);
value = max.poll();
min.add(value);
}
else
min.add(num);
}
else
//数据总数目是奇数时,将新数据插入最大堆
{
//为了保证大顶堆中的元素都小于小顶堆中的元素
//判断该新数据是否大于小顶堆中的元素
if(min.size() > 0 && num > min.peek())//获取队列头部的元素(在小顶堆中,是此优先队列中的最小元素)
{
//先把新数据插入小顶堆,然后把小顶堆中的最小元素取出插入大顶堆
min.add(num);
value = min.poll();
max.add(value);
}
else
max.add(num);
}
}
public Double GetMedian()
{
int size = min.size() + max.size();
double median = 0.0;
if((size & 1) == 1)//数据总数目为奇数
median = min.peek();
else//数据总数目为偶数
median = (min.peek() + max.peek()) / 2.0;
return median;
}
}