您的位置:首页 > 理论基础 > 数据结构算法

数据结构实现之最大索引优先队列

2016-01-24 17:25 519 查看
具体索引优先队列的说明见数据结构实现之最小优先队列

package xwq.dt;

import java.util.Iterator;
import java.util.NoSuchElementException;

import xwq.util.StdOut;
import xwq.util.StdRandom;

/**
* 使用二叉堆实现的索引最大优先队列
* class IndexMaxPQ是一个支持泛型的索引优先队列。
* IndexMaxPQ支持普通的insert、delete-the-maximum、delete以及change-the-key方法。
* 用户可以使用队列中的0到maxN-1号索引执行删除和修改方法。
* IndexMaxPQ支持获取队列最小元素,队列最小元素索引操作。
* IndexMaxPQ支持迭代器迭代所有插入的索引号。
*
* IndexMaxPQ的实现使用二叉堆。
*  The <em>insert</em>, <em>delete-the-maximum</em>, <em>delete</em>,
*  <em>change-key</em>, <em>decrease-key</em>, and <em>increase-key</em>
*  操作时间复杂度为O(lgN).
*  The <em>is-empty</em>, <em>size</em>, <em>min-index</em>, <em>min-key</em>, and <em>key-of</em>
*  operations 时间复杂度为O(1).

* @author xwq
*
* @param <Key>
*/
public class IndexMaxPQ <Key extends Comparable<Key>> implements Iterable<Integer>{
private int maxN;//索引优先队列中元素的最大个数
private int N;//当前索引优先队列中元素的个数
private int[] pq;//使用一级索引的二叉堆
private int[] qp;//pq的对称映射 qp[pq[i]] = pq[qp[i]] = i,用于映射key索引对应pq二叉堆中的位置
private Key[] keys;//keys[i] = priority of i

/**
* 初始化索引区间为(0到maxN-1)的空索引优先队列
* @param capacity
*/
public IndexMaxPQ(int capacity) {
if(capacity<=0)
throw new IllegalArgumentException();
maxN = capacity;
N = 0;
pq = new int[capacity+1];
qp = new int[capacity+1];
keys = (Key[])new Comparable[capacity+1];

//初始每个索引都没用过
for(int i=0;i<=maxN;i++)
qp[i] = -1;
}

/**
* 如果队列为空返回true
* @return 如果队列为空返回true,否则返回false
*/
public boolean isEmpty() {
return N == 0;
}

/**
* 队列的当前元素个数
* @return 队列的当前元素个数
*/
public int size() {
return N;
}

/**
* 判断优先队列是否已存在索引i
* @param i 索引i
* @return 如果索引i之前已插入,返回true,否则false
*/
public boolean contains(int i) {
return qp[i] != -1;
}

public Key maxKey() {
if(N == 0)
throw new NoSuchElementException("IndexMaxPQ was underflow.");
return keys[pq[1]];
}

/**
* 返回最大键值的索引号
* @return 最大键值的索引号
*/
public int maxIndex() {
if(N == 0)
throw new NoSuchElementException("IndexMaxPQ was underflow.");
return pq[1];
}

/**
* 返回优先队列最小值,即二叉堆根节点
* @return 优先队列最小值
*/
public Key keyOf(int i) {
if(i<0 || i>=maxN)
throw new IndexOutOfBoundsException();
if(!contains(i))
throw new IllegalArgumentException("i not exists in IndexMaxPQ");
return keys[i];
}

/**
* 将索引i与键值key关联
* @param i 索引i
* @param key 键值key
*/
public void insert(int i,Key key) {
if(i<0 || i>=maxN)
throw new IllegalArgumentException();
if(contains(i))
throw new IllegalArgumentException("index i has existed");
N++;
qp[i] = N;
pq
= i;
keys[i] = key;
adjustUp(N);
}

/**
* 删除最大键值并返回其对应的索引
* @return 最大键值对应的索引
*/
public int delMax() {
if(N == 0)
throw new NoSuchElementException("IndexMaxPQ was underflow.");
int max = pq[1];
swap(1,N--);
adjustDown(1);
qp[max] = -1;
keys[max] = null;
pq[N+1] = -1;
return max;
}

/**
* 删除索引i以及其对应的键值
* @param i 待删除的索引i
*/
public void delete(int i) {
if(i<0 || i>=maxN)
throw new IllegalArgumentException();
if(!contains(i))
throw new NoSuchElementException("IndexMaxPQ not existe index i.");

int index = qp[i];
swap(index,N--);
adjustUp(index);
adjustDown(index);
qp[i] = -1;
keys[i] = null;
pq[N+1] = -1;
}

/**
* 改变与索引i关联的键值
* @param i 待改变键值的索引
* @param key 改变后的键值
*/
public void changeKey(int i,Key key) {
if(i<0 || i>=maxN)
throw new IllegalArgumentException();
if(!contains(i))
throw new NoSuchElementException("IndexMaxPQ not existe index i.");
if(keys[i] == key)
throw new IllegalArgumentException("key equal to will be changed value");
if(keys[i].compareTo(key)<0)
increaseKey(i,key); //key比原来的key值大
else
decreaseKey(i,key);//key比原来的key值小
}

/**
* 减小与索引i关联的键值到给定的新键值
* @param i  与待减小的键值关联的索引
* @param key 新键值
*/
public void decreaseKey(int i,Key key) {
if(i<0 || i>=maxN)
throw new IllegalArgumentException();
if(!contains(i))
throw new NoSuchElementException("IndexMaxPQ not existe index i.");
if(keys[i].compareTo(key)<=0)
throw new IllegalArgumentException("Calling decreaseKey() with given argument would not strictly decrease the key");
keys[i] = key;
adjustDown(qp[i]);
}

/**
* 增加与索引i关联的键值到给定的新键值
* @param i 与待增加的键值关联的索引
* @param key 新键值
*/
public void increaseKey(int i,Key key) {
if(i<0 || i>=maxN)
throw new IllegalArgumentException();
if(!contains(i))
throw new NoSuchElementException("IndexMaxPQ not existe index i.");
if(keys[i].compareTo(key)>=0)
throw new IllegalArgumentException("Calling increaseKey() with given argument would not strictly increase the key");
keys[i] = key;
adjustUp(qp[i]);
}

/***************************************************************************
* General helper functions.
***************************************************************************/
/**
* 交换一级索引值,以及其对称映射中的值
* @param i 使用一级索引的二叉堆的索引i
* @param j 使用一级索引的二叉堆的索引j
*/
private void swap(int pqi,int pqj) {
int t = pq[pqi];
pq[pqi] = pq[pqj];
pq[pqj] = t;
qp[pq[pqi]] = pqi;
qp[pq[pqj]] = pqj;
}

/**
* 判断键值的大小关系
* @param pqi 使用一级索引的二叉堆的索引i
* @param pqj 使用一级索引的二叉堆的索引j
* @return keys[ki] < keys[kj] 返回true,否则返回false
*/
private boolean less(int pqi,int pqj) {
int ki = pq[pqi];
int kj = pq[pqj];
return keys[ki].compareTo(keys[kj]) < 0;
}

/***************************************************************************
* Heap helper functions.
***************************************************************************/
/**
* 向下调整最大二叉堆
* @param i 一级索引的二叉堆的索引i,pq数组的数组位置
*/
private  void adjustDown(int i) {
while(2*i <= N) {
int l = 2*i;
if(l<N && less(l,l+1))
l++;
//已满足最大堆性质,自身的值大于左右两节点的值
if(less(l,i))
break;
swap(l,i);
i = l;
}
}

/**
* 向上调整最大二叉堆
* @param i 一级索引的二叉堆的索引i,pq数组的数组位置
*/
private void adjustUp(int i) {
while(i>1) {
int p = i/2;
//自身元素值小于父元素值,满足最大堆性质,返回
if(less(i,p))
break;
swap(i,p);
i = p;
}
}

@Override
public Iterator<Integer> iterator() {
// TODO Auto-generated method stub
return new HeapIterator();
}

/***************************************************************************
* Iterators.
***************************************************************************/
/**
* Returns an iterator that iterates over the keys on the
* priority queue in descending order.
* The iterator doesn't implement <tt>remove()</tt> since it's optional.
*
* @return an iterator that iterates over the keys in ascending order
*/
private class HeapIterator implements Iterator<Integer>{
// create a new pq
private IndexMaxPQ<Key> copy;

// add all elements to copy of heap
// takes linear time since already in heap order so no keys move
public HeapIterator() {
copy = new IndexMaxPQ<Key>(maxN);
for(int i=1;i<=N;i++)
copy.insert(pq[i],keys[pq[i]]);
}

@Override
public boolean hasNext() {
return !copy.isEmpty();
}

@Override
public Integer next() {
if(copy.isEmpty())
throw new NoSuchElementException();
return copy.delMax();
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}

}

/**
* Unit tests the <tt>IndexMaxPQ</tt> data type.
*/
public static void main(String[] args) {
// insert a bunch of strings
String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" };

IndexMaxPQ<String> pq = new IndexMaxPQ<String>(strings.length);
for (int i = 0; i < strings.length; i++) {
pq.insert(i, strings[i]);
}
StdOut.print();
// print each key using the iterator
for (Integer i : pq) {
StdOut.println(i + " " + strings[i]);
}
StdOut.println();

// increase or decrease the key
for (int i = 0; i < strings.length; i++) {
if (StdRandom.uniform() < 0.5)
pq.increaseKey(i, strings[i] + strings[i]);
else
pq.decreaseKey(i, strings[i].substring(0, 1));
}

// delete and print each key
while (!pq.isEmpty()) {
String key = pq.maxKey();
int i = pq.delMax();
StdOut.println(i + " " + key);
}
StdOut.println();

// reinsert the same strings
for (int i = 0; i < strings.length; i++) {
pq.insert(i, strings[i]);
}

// delete them in random order
int[] perm = new int[strings.length];
for (int i = 0; i < strings.length; i++)
perm[i] = i;
StdRandom.shuffle(perm);
for (int i = 0; i < perm.length; i++) {
String key = pq.keyOf(perm[i]);
pq.delete(perm[i]);
StdOut.println(perm[i] + " " + key);
}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: