数据结构实现之最小索引优先队列
来源:互联网 发布:朱乒乓网络课 编辑:程序博客网 时间:2024/04/28 14:04
在很多应用中,允许用例引用进入优先队列中的元素是有必要的。做到这一点的一种简单方式是给每个元素一个索引。
另外,一种常见的情况是用例已经有了总量为N的多个元素,而且可能还同时使用了多个(平行)数组来存储这些元素的信息。此时,其他无关的用例代码可能已经在使用一个整数索引来引用这些无关元素了。这些考虑引导我们设计了如下所示的API。
理解这种数据结构的一个较好方法是将它看成一个能够快速访问其中最小元素的数组。事实上它还要更好——它能够快速访问数组的一个特定子集中的最小元素(指所有被插入的元素)。换句话说,可以将名为pq的IndexMinPQ类优先队列看做数组pq[0…N-1]中的一部分元素的代表。将pq.insert(i,key)看做将i加入这个子集并使pq[i] = key,pq.changeKey(i,key)则代表令pq[i]=key。这两种操作没有改变其他操作所依赖的数据结构,其中最重要的就是delMin()(删除最小元素并返回min的索引)和changeKey(i,key)(改变数据结构中没有索引对应的键值即pq[i]=key)。这些操作在许多应用中都有很重要并且依赖于对元素的引用(索引)。
一般来说,当堆发生变化时,我们可以用adjustDown(向下调整堆)或adjustUp(向上调整堆)来恢复堆的有序性。在这些操作中,我们可以用索引查找元素。能够定位堆中的任意元素也使我们在API中加入一个delete(int i)操作。
索引优先队列用例见索引优先队列用例(多路归并)
package xwq.dt;import java.util.Iterator;import java.util.NoSuchElementException;import xwq.util.StdOut;import xwq.util.StdRandom;/** * 使用二叉堆实现的索引最小优先队列 * class IndexMinPQ是一个支持泛型的索引优先队列。 * IndexMinPQ支持普通的insert、delete-the-minimum、delete以及change-the-key方法。 * 用户可以使用队列中的0到maxN-1号索引执行删除和修改方法。 * IndexMinPQ支持获取队列最小元素,队列最小元素索引操作。 * IndexMinPQ支持迭代器迭代所有插入的索引号。 * * IndexMinPQ的实现使用二叉堆。 * The <em>insert</em>, <em>delete-the-minimum</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 IndexMinPQ <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 IndexMinPQ(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; } /** * 返回最小值的索引号 * @return 最小值的索引号 */ public int minIndex() { if(isEmpty()) throw new NoSuchElementException("IndexMinPQ underflow."); return pq[1]; } /** * 返回优先队列最小值,即二叉堆根节点 * @return 优先队列最小值 */ public Key minKey() { if(isEmpty()) throw new NoSuchElementException("IndexMinPQ underflow."); return keys[pq[1]]; } /** * 索引i对应优先队列中的键值 * @param i 索引i * @return 索引i对应的键值 */ public Key keyOf(int i) { if(!contains(i)) throw new NoSuchElementException("IndexMinPQ has not contains index i"); 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("index i out of boundary."); if(contains(i)) throw new IllegalArgumentException("index i has allocted"); N++; qp[i] = N; pq[N] = i;//pq,qp互为映射 keys[i] = key; adjustUp(N); } /** * 删除最小键值并返回其对应的索引 * @return 最小键值对应的索引 */ public int delMin() { if(isEmpty()) throw new NoSuchElementException("IndexMinPQ underflow."); int min = minIndex(); delete(min); return min; } /** * 删除索引i以及其对应的键值 * @param i 待删除的索引i */ public void delete(int i){ if(!contains(i)) throw new NoSuchElementException("IndexMinPQ has not contains index i"); int pqi = qp[i]; swap(pqi,N--); adjustUp(pqi); adjustDown(pqi); qp[i] = -1; //删除 keys[i] = null; //便于垃圾收集 pq[N+1] = -1; //不是必须,但是加上便于理解 } /** * 改变与索引i关联的键值 * @param i 待改变键值的索引 * @param key 改变后的键值 */ public void changeKey(int i,Key key) { if(!contains(i)) throw new NoSuchElementException("IndexMinPQ has not contains index i"); if(keys[i].compareTo(key) == 0) throw new IllegalArgumentException("argument key equpal to the original value."); if(key.compareTo(keys[i]) > 0) increaseKey(i,key);//原键值增加 else decreaseKey(i,key);//原键值减小 } /** * 减小与索引i关联的键值到给定的新键值 * @param i 与待减小的键值关联的索引 * @param key 新键值 */ public void decreaseKey(int i,Key key) { if(!contains(i)) throw new NoSuchElementException("IndexMinPQ has not contains index i"); if(key.compareTo(keys[i]) > 0) throw new IllegalArgumentException("argument key more than the original value."); keys[i] = key; int pqi = qp[i]; adjustUp(pqi); adjustDown(pqi); } /** * 增加与索引i关联的键值到给定的新键值 * @param i 与待增加的键值关联的索引 * @param key 新键值 */ public void increaseKey(int i,Key key) { if(!contains(i)) throw new NoSuchElementException("IndexMinPQ has not contains index i"); if(key.compareTo(keys[i])<0) throw new IllegalArgumentException("argument key less than the original value"); keys[i] = key; int pqi = qp[i]; adjustUp(pqi); adjustDown(pqi); } /*************************************************************************** * General helper functions. ***************************************************************************/ /** * 交换一级索引值,以及其对称映射中的值 * @param i 使用一级索引的二叉堆的索引i * @param j 使用一级索引的二叉堆的索引j */ private void swap(int i,int j) { int t = pq[i]; pq[i] = pq[j]; pq[j] = t; int qpi = pq[i]; int qpj = pq[j]; qp[qpi] = i; qp[qpj] = j; } /** * 判断键值的大小关系 * @param i 使用一级索引的二叉堆的索引i * @param j 使用一级索引的二叉堆的索引j * @return keys[ki] < keys[kj] 返回true,否则返回false */ private boolean less(int i,int j) { int ki = pq[i]; int kj = pq[j]; 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; while(l<N && less(l+1,l)) l++; swap(l,i); i = l; } } /** * 向上调整最小二叉堆 * @param i 一级索引的二叉堆的索引i,pq数组的数组位置 */ private void adjustUp(int i) { while(i>1) { int p = i/2; if(less(p,i)) break; swap(p,i); i = p; } } @Override public Iterator<Integer> iterator() { return new HeapIterator(); } /*************************************************************************** * Iterators. ***************************************************************************/ /** * Returns an iterator that iterates over the keys on the * priority queue in ascending 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 IndexMinPQ<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 IndexMinPQ<Key>(maxN); for(int i=1;i<=N;i++) { int ki = pq[i]; Key key = keys[ki]; copy.insert(ki, key); } } @Override public boolean hasNext() { return !copy.isEmpty(); } @Override public Integer next() { if(!hasNext()) throw new NoSuchElementException("IndexMinPQ underflow."); return copy.delMin(); } @Override public void remove() { throw new UnsupportedOperationException("unsupported remove operation."); } } /** * Unit tests the <tt>IndexMinPQ</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" }; IndexMinPQ<String> pq = new IndexMinPQ<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 + " " + pq.keyOf(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.minKey(); int i = pq.delMin(); 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); } }}
0 0
- 数据结构实现之最小索引优先队列
- 数据结构实现之最大索引优先队列
- 数据结构实现之最小优先队列(最小堆)
- 数据结构实现之索引优先队列用例(多路归并)
- 【数据结构】之用堆实现优先队列
- 数据结构之优先队列
- 数据结构之优先队列
- 最小优先队列--堆实现
- 索引优先队列的实现
- 索引优先队列的实现
- poj1789之最小优先队列
- 常用类之三----最小堆实现优先队列
- C#数据结构之优先队列
- 数据结构 之 priority_queue 优先队列
- 数据结构之---优先队列(堆)
- 数据结构之优先队列--二叉堆(Java实现)
- 数据结构之优先队列--二叉堆(Java实现)
- 数据结构实现之最大优先队列(最大堆)
- 最小公倍数问题 算法设计
- Codevs 1069关押罪犯[Noip2010]
- 点击返回键,直接回退到桌面
- 关于内存越界
- LeetCode 9:Palindrome Number
- 数据结构实现之最小索引优先队列
- 各整形的数据范围
- CSS+DIV:理论实战缺一不可
- 努力
- 小知识点-JAVA
- Android使用adb获得activity堆栈信息
- Android应用实现退出时关闭所有Activity
- junit(一)
- 数据结构实现之最大索引优先队列