一、优先队列
- 当一颗二叉树的每个结点都大于等于它的两个子结点时,称堆有序。根节点是堆有序的二叉树中的最大结点。
- 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储(不使用数组的第一个位置0)
- 上浮:某个节点比他的父节点大,则需要通过交换它和它的父节点
- 下沉:当某个节点比他的两个子节点要小,则通过将他和它的两个子节点中的较大者交换来恢复堆。
- 插入元素:将新元素添加到数组末尾,增加堆的大小,并让这个新元素上浮到合适的位置
- 删除最大元素:从数组顶端删去最大元素并将数组的最后一个元素放到顶端,减小堆的大小并让这个元素下沉到合适的位置
package 二叉排序树;
//基于堆的优先队列
public class MaxPQ {
private int[] num;
private int N=0;
public MaxPQ(int maxN) {
num=new int[maxN+1];
}
public int size(){
return N;
}
public boolean empty(){
return N==0;
}
public void insert(int x){
num[++N]=x;
swim(N);
}
private void swim(int n) {
while (n>1&& less(n/2,n)){
exch(n/2,n);
n/=2;
}
}
public int delMax(){
int max=num[1];
exch(max,N--);//把最后一个节点放到顶端
num[N+1]=-1;
sink(1);//保持堆的有序性
return max;
}
private void sink(int n){
while (n*2<N){
int j=2*n;
if(j<N&&less(j,j+1))j=j+1;
if(!less(n,j)){
break;
}else exch(j,n);
n=j;
}
}
public boolean less(int x,int y){
return num[x]-num[y]<0;
}
public void exch(int x,int y){
int temp=num[x];
num[x]=num[y];
num[y]=temp;
}
}
二、索引优先队列
- keys的作用是存储对象的引用,我们将每个对象存储在与之相关的整数作为下标的位置中,keys存储的对象不一定在数组中连续存放。
- pq存储是与对象相关的整数值,注意数组pq是连续存放的。此时pq作为优先队列。
- 为了能够快速找到pq中元素值对应的下标,我们需要额外设置一个数组qp,它的作用是存储与对象相关的整数在pq数组中的下标,并在上浮和下沉的过程中同时维护它。
package 二叉排序树;
import java.util.NoSuchElementException;
public class IndexPQ<Key extends Comparable<Key>> {
private Key[] keys;//索引保存的值
private int[] pq;//优先队列,绑定的是索引信息
private int[] qp;//反向绑定 qp[pq[i]] = pq[qp[i]] = i
private int n;//PQ大小
private int maxN;
public IndexPQ(int maxN) {
if(maxN < 0)
throw new IllegalArgumentException("The size of IndexMinPQ should larger than 0");
this.maxN = maxN;
keys = (Key[]) new Comparable[maxN + 1];
pq = new int[maxN + 1];
qp = new int[maxN + 1];
for(int i = 0; i <= maxN; i++)
qp[i] = -1;
n = 0;
}
public boolean isEmpty() {
return n == 0;
}
public int size() {
return n;
}
public boolean contains(int k) {
if(k < 0 || k >= maxN)
throw new IndexOutOfBoundsException();
return qp[k] != -1;
}
public void insert(int k, Key key) {
if (k < 0 || k >= maxN)
throw new IndexOutOfBoundsException();
if (contains(k))
throw new IllegalArgumentException("index is already in the priority queue");
n++;
qp[k] = n;
pq[n] = k;
keys[k] = key;
swim(n);
}
public Key min() {
if(n == 0)
throw new NoSuchElementException("IndexMinPQ underflow");
return keys[pq[1]];
}
public int minIndex() {
if(n == 0)
throw new NoSuchElementException("IndexMinPQ underflow");
return pq[1];
}
public int delMin() {
if(n == 0)
throw new NoSuchElementException("IndexMinPQ underflow");
int indexOfMin = pq[1];
exch(1, n--);
sink(1);
keys[pq[n+1]] = null;
qp[pq[n+1]] = -1;
return indexOfMin;
}
public void delete(int i) {
if (i < 0 || i >= maxN)
throw new IndexOutOfBoundsException();
if (!contains(i))
throw new NoSuchElementException("index is not in the priority queue");
int index = qp[i];
exch(index, n--);
swim(index);
sink(index);
keys[i] = null;
qp[i] = -1;
}
public void changeKey(int i, Key key) {
if (i < 0 || i >= maxN)
throw new IndexOutOfBoundsException();
if (!contains(i))
throw new NoSuchElementException("index is not in the priority queue");
keys[i] = key;
swim(qp[i]);
sink(qp[i]);
}
/***************************************************************************
* General helper functions.
***************************************************************************/
private boolean greater(int i, int j) {
return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
}
private void exch(int i, int j) {
int swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
qp[pq[i]] = i;
qp[pq[j]] = j;
}
/***************************************************************************
* Heap helper functions.
***************************************************************************/
private void swim(int k) {
while (k > 1 && greater(k/2, k)) {
exch(k, k/2);
k = k/2;
}
}
private void sink(int k) {
while (2*k <= n) {
int j = 2*k;
if (j < n && greater(j, j+1)) j++;
if (!greater(k, j)) break;
exch(k, j);
k = j;
}
}
}
三、多项归并
public class Multiway {
// This class should not be instantiated.
private Multiway() { }
// merge together the sorted input streams and write the sorted result to standard output
private static void merge(In[] streams) {
int n = streams.length;
IndexMinPQ<String> pq = new IndexMinPQ<String>(n);
for (int i = 0; i < n; i++)
if (!streams[i].isEmpty())
pq.insert(i, streams[i].readString());
// Extract and print min and read next from its stream.
while (!pq.isEmpty()) {
StdOut.print(pq.minKey() + " ");
int i = pq.delMin();
if (!streams[i].isEmpty())
pq.insert(i, streams[i].readString());
}
StdOut.println();
}
/**
* Reads sorted text files specified as command-line arguments;
* merges them together into a sorted output; and writes
* the results to standard output.
* Note: this client does not check that the input files are sorted.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
int n = args.length;
In[] streams = new In[n];
for (int i = 0; i < n; i++)
streams[i] = new In(args[i]);
merge(streams);
}
}