赞
踩
队列是先进先出的数据结构,优先队列的出队可以出最小值或者最大值。
简单提一下,表list、队列、栈都可以由数组实现。当长度变长超出数组长时,新建一个两倍长的数组。
1.优先队列的主要操作 优先队列是元素的容器,每个元素有一个相关的键值;
insert(key, data)
:插入键值为key的数据到优先队列中,元素以其key进行排序;deleteMin/deleteMax
:删除并返回最小/最大键值的元素;getMinimum/getMaximum
:返回最小/最大剑指的元素,但不删除它;2.优先队列的辅助操作
第k最小/第k最大
:返回优先队列中键值为第k个最小/最大的元素;大小(size)
:返回优先队列中的元素个数;堆排序(Heap Sort)
:基于键值的优先级将优先队列中的元素进行排序;3.优先队列的辅助操作
优先队列可以由无序数组、无序链表、树等实现,使用堆是最优解。
堆是一颗具有特定性质的二叉树,堆的基本要求就是堆中所有结点的值必须大于或等于(或小于或等于)其孩子结点的值,这也称为堆的性质;堆还有另一个性质,就是当 h > 0 时,所有叶子结点都处于第 h 或 h - 1 层(其中 h 为树的高度,完全二叉树),也就是说,堆应该是一颗完全二叉树;
数组
用数组来表示堆不仅不会浪费空间还具有一定的优势:
left child(i) = i * 2
;每个结点的右孩子为下标i的2倍加1:right child(i) = i * 2 + 1
parent(i) = i / 2
,注意这里是整数除,2和3除以2都为1;public class MaxHeap<E extends Comparable<E>> { private Array<E> data; public MaxHeap(int capacity){ data = new Array<>(capacity); } public MaxHeap(){ data = new Array<>(); } // 返回堆中的元素个数 public int size(){ return data.getSize(); } // 返回一个布尔值, 表示堆中是否为空 public boolean isEmpty(){ return data.isEmpty(); } // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引 private int parent(int index){ if(index == 0) throw new IllegalArgumentException("index-0 doesn't have parent."); return (index - 1) / 2; } // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引 private int leftChild(int index){ return index * 2 + 1; } // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引 private int rightChild(int index){ return index * 2 + 2; } }
// 向堆中添加元素
public void add(E e){
data.addLast(e);
siftUp(data.getSize() - 1);
}
private void siftUp(int k){
while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
data.swap(k, parent(k));
k = parent(k);
}
}
/ 默认实现了一个最小堆。
Queue<Integer> priorityQueue = new PriorityQueue<>();
// 实现最大堆
Queue<Integer> priorityQueue = new PriorityQueue<>((a, b) -> b - a);
在PriorityQueue提供的构造方法中,可以使用自定义的排序方法,也可以使用元素自带的Comparable排序,PriorityQueue要求在默认排序的时候,需要元素对象拥有Comparable功能。
private static Comparator<ListNode> comp =new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
// TODO Auto-generated method stub
return o1.val-o2.val;
}
};
public static ListNode mergeKLists(List<ListNode> lists){
PriorityQueue<ListNode> queue=new PriorityQueue<ListNode>(lists.size(),comp);
}
或者
PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val-o2.val;
}
});
合并k个排序链表,并且返回合并后的排序链表。
思路,把所有链表放到一个优先队列,然后将优先队列序列化成链表。
代码
public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) return null; PriorityQueue<ListNode> q = new PriorityQueue<ListNode>(new Comparator<ListNode>() { @Override public int compare(ListNode o1, ListNode o2) { return o1.val-o2.val; } }); for (int i = 0; i < lists.length; i++) { if (lists[i] != null) { q.add(lists[i]); } } ListNode dummy = new ListNode(0); ListNode tail = dummy; while (!q.isEmpty()) { tail.next = q.poll(); tail = tail.next; if (tail.next != null) { q.add(tail.next); } } return dummy.next; }
public int findKthLargest(int[] nums, int k) { // 正确性判断 if (0 == nums.length || null == nums || k <= 0 || k > nums.length) { return -1; } // 构造优先队列,默认为最小堆,传入自定义的比较器转换成最大堆 PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a); for (Integer num : nums) { pq.add(num); } for (int i = 0; i < k - 1; i++) { pq.remove(); } return pq.peek(); }
数字是不断进入数组的,在每次添加一个新的数进入数组的同时返回当前新数组的中位数。
中位数的定义:
中位数
不等同于数学定义里的中位数
。挑战:
时间复杂度为O(nlogn)
方法2:一个最小堆,一个最大堆
思路:
//求数据流的中位数,给定的数组是代表数据流,每增加一个数,动态计算当前数据集合中的中位数
1.初始化两个堆,最大堆和最小堆。最大堆放数据中较小的那部分数据,最小堆放数据中较大的那部分数据,
2.每次增加一个元素时,都先加载到最大堆,然后判断当前集合中元素的个数,
2.1如果是奇数,比较最大堆堆顶元素和最小堆堆顶元素大小
2.1.1 如果最大堆堆顶元素 > 最小堆堆顶元素, 说明最小部分中有大于最大部分的元素存在,需要交换两个堆的堆顶元素
2.1.2 如果最大堆堆顶元素 <= 最小堆堆顶元素,说明正常,无需其他操作
2.2如果是偶数,从最大堆中分一个最大值给最小堆,保持两个堆的个数相差<=1
3.count++
public class Solution { /** \* @param nums: A list of integers \* @return: the median of numbers */ private PriorityQueue<Integer> maxheap,minheap; private int count=0; public int[] medianII(int[] nums) { maxheap=new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); } }); minheap=new PriorityQueue<>(); int len=nums.length; int []result=new int[len]; for(int i=0;i<len;i++){ addNums(nums[i]); result[i]=getMedian(); } return result; } public void addNums(int x){ maxheap.offer(x); //数组中有奇数个元素时 if(count%2==0){ if(minheap.isEmpty()){ count++; return; }else{ if(maxheap.peek()>minheap.peek()){ int maxNum=maxheap.poll(); int minNum=minheap.poll(); maxheap.offer(minNum); minheap.offer(maxNum); } } }else{ minheap.offer(maxheap.poll()); } count++; } public int getMedian(){ return maxheap.peek(); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。