zoukankan      html  css  js  c++  java
  • 《算法》第二章部分程序 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         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 inputMaxN)
     17     {
     18         if (maxN < 0)
     19             throw new IllegalArgumentException("
    <construct> maxN < 0.
    ");
     20         maxN = inputMaxN;
     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("
    <insert> exist i already exist.
    ");
     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("
    <maxIndex> underflow.
    ");
     63         return pq[1];
     64     }
     65 
     66     public Key topKey()                 // 显示堆顶元素
     67     {
     68         if (n == 0)
     69             throw new NoSuchElementException("
    <maxKey> underflow.
    ");
     70         return keys[pq[1]];
     71     }
     72 
     73     public int delTop()                 // 弹出堆顶元素
     74     {
     75         if (n == 0)
     76             throw new NoSuchElementException("
    <delMax> underflow.
    ");
     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("
    <KeyOf> index i not exist.
    ");
     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("
    <changeKey> index i not exist.
    ");
    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("
    <increaseKey> index i not exist.
    ");
    113         if (keys[i].compareTo(key) >= 0)
    114             throw new IllegalArgumentException("
    <increaseKey> given key less than the older one.
    ");
    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("
    <decreaseKey> index is not in the priority queue.
    ");
    126         if (keys[i].compareTo(key) <= 0)
    127             throw new IllegalArgumentException("
    <decreaseKey> given key mroe than the older one.
    ");
    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("
    <delete> index i not exist.
    ");
    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 }
  • 相关阅读:
    git-【六】分支的创建与合并
    git-【五】远程仓库
    git-【四】撤销修改和删除文件操作
    git-【三】理解工作区与暂存区的区别
    git-【二】本地git操作提交、版本回退
    git-【一】概述安装
    java-基础-【四】实际编程中的对象
    博客园打赏、赞助功能
    js-template-art【四】通过helper方法注册,调用外部方法
    js-template-art【三】js api
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9776431.html
Copyright © 2011-2022 走看看