堆、优先队列和堆排序03:优先队列
什么是优先队列
普通队列:先进先出,后进后出
优先队列:出队顺序和入队顺序无关,和优先级相关
实现优先队列的数据结构 | 入队 | 出队(拿出最大元素) |
---|---|---|
普通线性结构 | O(1) | O(n) |
顺序线性结构 | O(n) | O(1) |
堆 | O(logn) | O(logn) |
interface Queue<E> {
int getSize();
boolean isEmpty();
void enqueue(E element);
E dequeue();
E getFront();
}
class PriorityQueue<E extends Comparable<E>> implements Queue<E>{
private MaxHeap<E> maxHeap;
public PriorityQueue(){
maxHeap = new MaxHeap();
}
@Override
public int getSize(){
return maxHeap.size();
}
@Override
public boolean isEmpty(){
return maxHeap.isEmpty();
}
@Override
public E getFront(){
return maxHeap.findMax();
}
@Override
public void enqueue(E element){
maxHeap.add(element);
}
@Override
public E dequeue(){
return maxHeap.extractMax();
}
}
class MaxHeap<E extends Comparable<E>>{
private Array<E> heap;
public MaxHeap(int capacity){
heap = new Array<>(capacity);
}
public MaxHeap(){
heap = new Array<>(10);
}
public MaxHeap(E[] arr){
heap = new Array<>(arr);
heapify(arr);
}
public int size(){
return heap.getSize();
}
public boolean isEmpty(){
return heap.getSize() == 0;
}
public int parent(int index){
if (index == 0) {
throw new IllegalArgumentException("根节点没有父节点");
}
return (index - 1) / 2;
}
private int leftChild(int index){
return 2 * index + 1;
}
private int rightChild(int index){
return 2 * index + 2;
}
public void add(E e){
heap.addLast(e);
siftUp(size() - 1);
}
private void siftUp(int index){
while (index > 0 && heap.get(index).compareTo(heap.get(parent(index))) > 0){
heap.swap(index, parent(index));
index = parent(index);
}
}
public E findMax(){
if (size() == 0){
throw new IllegalArgumentException("堆为空");
}
return heap.get(0);
}
public E extractMax(){
E max = findMax();
heap.swap(0, size() - 1);
heap.remove(size() - 1);
siftDown(0);
return max;
}
public void siftDown(int index){
while (leftChild(index) < size()){
int max = leftChild(index);
if (rightChild(index) < size() && heap.get(leftChild(index)).compareTo(heap.get(rightChild(index))) < 0){
max = rightChild(index);
}
if (heap.get(index).compareTo(heap.get(max)) >= 0){
break;
}
heap.swap(index, max);
index = max;
}
}
public void heapify(E[] arr){
if (arr.length > 1){
for (int i = parent(arr.length - 1); i >= 0; i--) {
siftDown(i);
}
}
}
public E replace(E e){
E max = findMax();
heap.set(e, 0);
siftDown(0);
return max;
}
}
class Array<E>{
private E[] data;
private int size;
public Array(int capacity){
data = (E[]) new Object[capacity];
size = 0;
}
public Array(E[] arr){
data = (E[]) new Object[arr.length];
for (int i = 0; i < arr.length; i++) {
data[i] = arr[i];
}
size = arr.length;
}
public Array(){
data = (E[]) new Object[10];
size = 0;
}
public int getSize(){
return size;
}
public void swap(int index1, int index2){
E temp;
temp = data[index1];
data[index1] = data[index2];
data[index2] = temp;
}
public E get(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("索引值非法");
}
return data[index];
}
public void set(E e, int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("索引值非法");
}
data[index] = e;
}
public void add(E e, int index){
if (index < 0 || index > size){
throw new IllegalArgumentException("索引值非法");
}
if (size == data.length){
resize(2 * data.length);
}
for (int i = index - 1; i >= index; i++) {
data[i + 1] = data[i];
}
data[index] = e;
size++;
}
public void addLast(E e){
add(e, size);
}
public void remove(int index){
if (index < 0 || index >= size){
throw new IllegalArgumentException("索引值非法");
}
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
data[size] = null;
if (size == data.length / 2 && data.length / 2 != 0){
resize(data.length / 2);
}
}
public void resize(int newCapacity){
E[] temp = (E[])new Object[newCapacity];
for (int i = 0; i < size; i++) {
temp[i] = data[i];
}
data = temp;
}
@Override
public String toString(){
StringBuilder str = new StringBuilder();
str.append("[");
for (int i = 0; i < size; i++) {
str.append(data[i]);
if (i != size - 1){
str.append(", ");
}
}
str.append("]");
return str.toString();
}
}
优先队列的优势:不需要一次性知道所有的数据,也不用把所有的数据进行存储,而是采用数据流的方式获取数据,每当获取到一个数据,就进行排序比较,实时更新,在数据规模很大的时候,可以快速的知道最大的元素是多少