二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
一般使用优先级队列来表示堆,优先级队列排序原理是二叉堆排序。
1.数组中的第k大元素
leetcode215题
解题思路:用优先级队列保存数据,优先级自然排序是降序,当堆大小超过k的时候,我们就删除掉堆顶的元素,队列中永远是k个最小的数。
```Java
public int findKthLargest(int[] nums, int k) {
//优先级队列降序
PriorityQueue<Integer> pq=new PriorityQueue<>();
for(int i:nums){
pq.offer(i);
//>k删除堆顶元素
if(pq.size()>k){
pq.poll();
}
}
return pq.peek();
}
```
## 2.数据流的中位数
leetcode295题
解题思路:将一个大顶堆分成一个大顶堆和一个小顶堆,如下图,中位数就等于大顶堆堆顶的值或者小顶堆堆顶值又或者是两者之除以2。
怎样将数添加到大小顶堆呢?
要满足两个要求:
1.两个堆中的元素个数之差小于1,当元素个数相等时往小顶堆添加数据;
2.大顶堆中的堆顶元素要小于等于小顶堆元素的堆顶。如果要往小顶堆添加元素,我们可以先往大顶堆添加元素,然后将大顶堆的堆顶元素添加到小顶堆中,往大顶堆添加元素同理。
```Java
private PriorityQueue<Integer> large;//小根堆
private PriorityQueue<Integer> small;//大根堆
//寻找中位数
public double findMedian() {
//如果元素不一样多,多的那个堆的堆顶元素就是中位数
if(large.size()<small.size()){
return small.peek();
}else if(large.size()>small.size()){
return large.peek();
}
//如果元素一样多,两个堆顶元素的平均数是中位数
return (large.peek()+small.peek())/2.0;
}
//添加中位数 small中最大的数要小于等于large中最小的数 给small添加数据,先给large添加,然后将large最小值添加到small中
//同时保证两个队列中的元素只差小于1
public void addNum(int num) {
if(small.size()>=large.size()){
small.offer(num);
large.offer(small.poll());
} else {
large.offer(num);
small.offer(large.poll());
}
}
```
至此,用二叉堆解决了中位数和第k大数两个问题。