《算法》第二章部分程序 part 4

▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列

● 优先队列

  1 package package01;
  2 
  3 import java.util.Comparator;
  4 import java.util.Iterator;
  5 import java.util.NoSuchElementException;
  6 import edu.princeton.cs.algs4.StdIn;
  7 import edu.princeton.cs.algs4.StdOut;
  8 
  9 public class class01<Key> implements Iterable<Key>
 10 {
 11     private int n;                      // 实际元素数
 12     private Key[] pq;                   // 放堆的数组,注意 pq[0] 不使用
 13     private Comparator<Key> comparator; // 比较器
 14 
 15     public class01(int initCapacity)
 16     {
 17         n = 0;
 18         pq = (Key[]) new Object[initCapacity + 1];
 19     }
 20 
 21     public class01(int initCapacity, Comparator<Key> comparator)
 22     {
 23         n = 0;
 24         pq = (Key[]) new Object[initCapacity + 1];
 25         this.comparator = comparator;
 26     }
 27 
 28     public class01()
 29     {
 30         this(1);            // 对象自身的指针可以当构造函数名用
 31     }
 32 
 33     public class01(Comparator<Key> comparator)
 34     {
 35         this(1, comparator);
 36     }
 37 
 38     public class01(Key[] keys)          // 含传入数组的构造函数
 39     {
 40         n = keys.length;
 41         pq = (Key[]) new Object[keys.length + 1];
 42         for (int i = 0; i < n; i++)
 43             pq[i + 1] = keys[i];
 44         for (int k = n / 2; k >= 1; k--)// 逐元素下沉建堆
 45             sink(k);
 46     }
 47 
 48     public boolean isEmpty()
 49     {
 50         return n == 0;
 51     }
 52 
 53     public int size()
 54     {
 55         return n;
 56     }
 57 
 58     public Key max()                    // 取最大元素(堆顶)
 59     {
 60         if (isEmpty())
 61             throw new NoSuchElementException("Priority queue underflow");
 62         return pq[1];
 63     }
 64 
 65     public Key delMax()                 // 弹出最大元素
 66     {
 67         if (isEmpty())
 68             throw new NoSuchElementException("Priority queue underflow");
 69         Key max = pq[1];
 70         exch(1, n--);                               // 把最后的元素放到堆顶,然后下沉
 71         sink(1);
 72         pq[n + 1] = null;                           // 帮助垃圾回收
 73         if ((n > 0) && (n == (pq.length - 1) / 4))  // 减少堆尺寸
 74             resize(pq.length / 2);
 75         return max;
 76     }
 77 
 78     private void resize(int capacity)               // 调整堆大小
 79     {
 80         assert capacity > n;
 81         Key[] temp = (Key[]) new Object[capacity];  // 建一个新堆,然后搬进去
 82         for (int i = 1; i <= n; i++) 
 83             temp[i] = pq[i];
 84         pq = temp;
 85     }
 86 
 87     public void insert(Key x)               // 插入新元素
 88     {
 89         if (n == pq.length - 1)             // 堆满了,扩建
 90             resize(2 * pq.length);
 91 
 92         pq[++n] = x;                        // 把新元素放到堆最后,然后上浮
 93         swim(n);        
 94     }
 95 
 96     private void swim(int k)                    // 上浮
 97     {
 98         for (; k > 1 && less(k / 2, k); k = k / 2)
 99             exch(k, k / 2);
100     }
101 
102     private void sink(int k)                    // 下沉
103     {
104         for (int j = k + k; j <= n; exch(k, j), k = j, j = k + k)
105         {
106             if (j < n && less(j, j + 1))       // 选择 a[k] 子节点中较大者
107                 j++;
108             if (!less(k, j))                   // 调整 a[k] 及其子节点,若 a[k] > a[j] 则停止调整
109                 break;
110         }
111     }
112 
113     private boolean less(int i, int j)          // 需要小根堆时把两个不等号变向,其他所有地方都不改
114     {
115         if (comparator == null)
116             return ((Comparable<Key>) pq[i]).compareTo(pq[j]) < 0;
117             //return ((Comparable<Key>) pq[i]).compareTo(pq[j]) > 0;
118         else
119             return comparator.compare(pq[i], pq[j]) < 0;
120             //return comparator.compare(pq[i], pq[j]) > 0;
121     }
122 
123     private void exch(int i, int j)
124     {
125         Key swap = pq[i];
126         pq[i] = pq[j];
127         pq[j] = swap;
128     }
129 
130     private boolean isMaxHeap()
131     {
132         return isMaxHeap(1);
133     }
134 
135     private boolean isMaxHeap(int k)
136     {
137         if (k > n)
138             return true;
139         int left = 2 * k, right = 2 * k + 1;
140         if (left <= n && less(k, left) || right <= n && less(k, right))
141             return false;
142         return isMaxHeap(left) && isMaxHeap(right);
143     }
144 
145     public Iterator<Key> iterator() // 迭代器
146     {
147         return new HeapIterator();
148     }
149 
150     private class HeapIterator implements Iterator<Key>
151     {
152         private class01<Key> copy;
153 
154         public HeapIterator()
155         {
156             if (comparator == null)
157                 copy = new class01<Key>(size());
158             else
159                 copy = new class01<Key>(size(), comparator);
160             for (int i = 1; i <= n; i++)
161                 copy.insert(pq[i]);
162         }
163 
164         public boolean hasNext()
165         {
166             return !copy.isEmpty();
167         }
168 
169         public void remove()
170         {
171             throw new UnsupportedOperationException();
172         }
173 
174         public Key next()
175         {
176             if (!hasNext()) 
177                 throw new NoSuchElementException();
178             return copy.delMax();
179         }
180     }
181 
182     public static void main(String[] args) // 交互式出入优先队列
183     {
184         class01<String> pq = new class01<String>();
185         for(; !StdIn.isEmpty();)
186         {
187             String item = StdIn.readString();
188             if (!item.equals("-"))
189                 pq.insert(item);
190             else if (!pq.isEmpty())
191                 StdOut.print(pq.delMax() + " ");
192         }
193         StdOut.println("(" + pq.size() + " left on pq)");
194     }
195 }

● 索引优先队列

  1 package package01;
  2 
  3 import java.util.Iterator;
  4 import java.util.NoSuchElementException;
  5 import edu.princeton.cs.algs4.StdRandom;
  6 import edu.princeton.cs.algs4.StdOut;
  7 
  8 public class class01<Key extends Comparable<Key>> implements Iterable<Integer>
  9 {
 10     private int maxN;       // 队列最大元素个数
 11     private int n;
 12     private int[] pq;       // 索引堆,初值为 0,pq[0] 不用,pq[i] == j 表示堆的数组表示中第 i 位置上的元素是 keys[j]
 13     private int[] qp;       // 索引堆的逆,初值为 -1,qp[pq[i]] = pq[qp[i]] = i,qp[j] == i 表示元素 keys[i] 在堆的数组表示中位于第 i 的位置
 14     private Key[] keys;     // 仅保存值(不移动)
 15 
 16     public class01(int maxN)
 17     {
 18         if (maxN < 0)
 19             throw new IllegalArgumentException("\n<construct> maxN < 0.\n");
 20         this.maxN = maxN;
 21         n = 0;
 22         pq = new int[maxN + 1];
 23         qp = new int[maxN + 1];
 24         keys = (Key[]) new Comparable[maxN + 1];
 25         for (int i = 0; i <= maxN; i++)
 26             qp[i] = -1;
 27     }
 28 
 29     public boolean isEmpty()
 30     {
 31         return n == 0;
 32     }
 33 
 34     public boolean contains(int i)      // 判断 qp 中第 i 位置是否被占用
 35     {
 36         if (i < 0 || i >= maxN)
 37             throw new IllegalArgumentException();
 38         return qp[i] != -1;
 39     }
 40 
 41     public int size()
 42     {
 43         return n;
 44     }
 45 
 46     public void insert(int i, Key key)
 47     {
 48         if (i < 0 || i >= maxN)
 49             throw new IllegalArgumentException();
 50         if (contains(i))
 51             throw new IllegalArgumentException("\n<insert> exist i already exist.\n");
 52         n++;                            // 新元素插到末尾,然后上浮
 53         qp[i] = n;
 54         pq[n] = i;
 55         keys[i] = key;
 56         swim(n);
 57     }
 58 
 59     public int topIndex()
 60     {
 61         if (n == 0)
 62             throw new NoSuchElementException("\n<maxIndex> underflow.\n");
 63         return pq[1];
 64     }
 65 
 66     public Key topKey()                 // 显示堆顶元素
 67     {
 68         if (n == 0)
 69             throw new NoSuchElementException("\n<maxKey> underflow.\n");
 70         return keys[pq[1]];
 71     }
 72 
 73     public int delTop()                 // 弹出堆顶元素
 74     {
 75         if (n == 0)
 76             throw new NoSuchElementException("\n<delMax> underflow.\n");
 77         int top = pq[1];
 78         exch(1, n--);                   // 将堆尾元素换到堆顶,然后下沉
 79         sink(1);
 80         //assert pq[n + 1] == top;        // 确保原来堆顶的元素被替换到了最后
 81         qp[top] = -1;                   // 清除尾部元素的占用(代表被弹出的堆顶元素)
 82         keys[top] = null;               // 有助于垃圾回收
 83         pq[n + 1] = -1;                 // 可以不要?
 84         return top;
 85     }
 86 
 87     public Key keyOf(int i)                 // 查询 keys 中第 i 个元素
 88     {
 89         if (i < 0 || i >= maxN)
 90             throw new IllegalArgumentException();
 91         if (!contains(i))
 92             throw new NoSuchElementException("\n<KeyOf> index i not exist.\n");
 93         else return keys[i];
 94     }
 95 
 96     public void changeKey(int i, Key key)   // 在keys 的第 i 位置上替换成元素 key,然后调整其在堆中的位置
 97     {
 98         if (i < 0 || i >= maxN)
 99             throw new IllegalArgumentException();
100         if (!contains(i))
101             throw new NoSuchElementException("\n<changeKey> index i not exist.\n");
102         keys[i] = key;
103         swim(qp[i]);
104         sink(qp[i]);
105     }
106 
107     public void increaseKey(int i, Key key) // 增加某个元素的键
108     {
109         if (i < 0 || i >= maxN)
110             throw new IllegalArgumentException();
111         if (!contains(i))
112             throw new NoSuchElementException("\n<increaseKey> index i not exist.\n");
113         if (keys[i].compareTo(key) >= 0)
114             throw new IllegalArgumentException("\n<increaseKey> given key less than the older one.\n");
115         keys[i] = key;                      // 替换后只要上浮即可
116         swim(qp[i]);
117         //sink(qp[i]);                        // 最小有优先队列中这里要改成下沉
118     }
119 
120     public void decreaseKey(int i, Key key) // 减少某个元素的键
121     {
122         if (i < 0 || i >= maxN)
123             throw new IllegalArgumentException();
124         if (!contains(i))
125             throw new NoSuchElementException("\n<decreaseKey> index is not in the priority queue.\n");
126         if (keys[i].compareTo(key) <= 0)
127             throw new IllegalArgumentException("\n<decreaseKey> given key mroe than the older one.\n");
128         keys[i] = key;                      // 替换后只要下沉即可
129         sink(qp[i]);
130         //swim(qp[i]);                        // 最小有优先队列中这里要改成上浮 
131     }
132 
133     public void delete(int i)               // 删除节点
134     {
135         if (i < 0 || i >= maxN)
136             throw new IllegalArgumentException();
137         if (!contains(i))
138             throw new NoSuchElementException("\n<delete> index i not exist.\n");
139         int index = qp[i];                  // 把目标元素与堆尾元素互换,然后调整
140         exch(index, n--);
141         swim(index);
142         sink(index);
143         keys[i] = null;
144         qp[i] = -1;
145     }
146 
147     private boolean less(int i, int j)                  // 最大优先队列用 less 来做上浮和下沉
148     {
149         return keys[pq[i]].compareTo(keys[pq[j]]) < 0;
150     }
151 
152     private boolean greater(int i, int j)               // 最小优先队列用 greater 来做上浮和下沉
153     {
154         return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
155     }
156 
157     private void exch(int i, int j) // 单纯交换 i 和 j(不用调整位置?)
158     {
159         int swap = pq[i];
160         pq[i] = pq[j];
161         pq[j] = swap;
162         qp[pq[i]] = i;
163         qp[pq[j]] = j;
164     }
165 
166     private void swim(int k)
167     {
168         for (; k > 1 && less(k >> 1, k); k >>= 1)
169         //for (; k > 1 && greater(k >> 1, k); k >>= 1)    // 最小优先队列用
170             exch(k, k >> 1);
171     }
172 
173     private void sink(int k)
174     {
175         for (int j = k << 1; j <= n; exch(k, j), k = j, j = k << 1)
176         {
177             if (j < n && less(j, j + 1))
178             //if (j < n && greater(j, j + 1))             // 最小优先队列用
179                 j++;
180             if (!less(k, j))
181                 break;
182         }
183     }
184 
185     public Iterator<Integer> iterator() // 迭代器,原理是临时建立一个把 key 排好序的堆用于迭代
186     {
187         return new HeapIterator();
188     }
189 
190     private class HeapIterator implements Iterator<Integer>
191     {
192         private class01<Key> copy;
193 
194         public HeapIterator()
195         {
196             copy = new class01<Key>(pq.length - 1);
197             for (int i = 1; i <= n; i++)
198                 copy.insert(pq[i], keys[pq[i]]);
199         }
200 
201         public boolean hasNext()
202         {
203             return !copy.isEmpty();
204         }
205 
206         public void remove()
207         {
208             throw new UnsupportedOperationException();
209         }
210 
211         public Integer next()
212         {
213             if (!hasNext())
214                 throw new NoSuchElementException();
215             return copy.delTop();
216         }
217     }
218 
219     public static void main(String[] args)
220     {
221         String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" };
222 
223         class01<String> pq = new class01<String>(strings.length);
224         for (int i = 0; i < strings.length; i++)                    // 入队
225             pq.insert(i, strings[i]);
226 
227         for (int i : pq)                                            // 用迭代器显示队列状态,等效于逐个出队
228             StdOut.println(i + " " + strings[i]);
229         StdOut.println();
230 
231         for (int i = 0; i < strings.length; i++)                    // 尝试改变元素的键
232         {
233             if (StdRandom.uniform() < 0.5)
234                 pq.increaseKey(i, "zzz");                           // 换成优先级更高的字符串
235             else
236                 pq.decreaseKey(i, strings[i].substring(0, 1));      // 换成原来字符串的子串
237         }
238 
239         for (; !pq.isEmpty();)                                       // 诸葛弹出元素
240         {
241             String key = pq.maxKey();
242             int i = pq.delMax();
243             StdOut.println(i + " " + key);
244         }
245         StdOut.println();
246 
247         for (int i = 0; i < strings.length; i++)                    // 再次入队
248             pq.insert(i, strings[i]);
249 
250         int[] perm = new int[strings.length];                       // 随机删除,生成一个随机数组,按数组元素的值删减队列中的元素
251         for (int i = 0; i < strings.length; i++)
252             perm[i] = i;
253         StdRandom.shuffle(perm);
254         for (int i = 0; i < perm.length; i++)
255         {
256             String key = pq.keyOf(perm[i]);
257             pq.delete(perm[i]);
258             StdOut.println(perm[i] + " " + key);
259         }
260     }
261 }

猜你喜欢

转载自www.cnblogs.com/cuancuancuanhao/p/9776431.html
今日推荐