zoukankan      html  css  js  c++  java
  • 《算法》第五章部分程序 part 3

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(美国国旗排序)

    ● 美国国旗排序

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdIn;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.Stack;
      6 
      7 public class class01
      8 {
      9     private static final int BITS_PER_BYTE = 8;
     10     private static final int BITS_PER_INT = 32;
     11     private static final int R = 256;
     12     private static final int CUTOFF = 15;
     13 
     14     private class01() {}
     15 
     16     public static void sort(String[] a)
     17     {
     18         sortKernel(a, 0, a.length - 1);
     19     }
     20 
     21     public static void sortKernel(String[] a, int lo, int hi)
     22     {
     23         Stack<Integer> st = new Stack<Integer>();
     24         int[] first = new int[R + 2], next = new int[R + 2];
     25         int d = 0;
     26         for (st.push(lo), st.push(hi), st.push(d); !st.isEmpty();)
     27         {
     28             d = st.pop(); hi = st.pop(); lo = st.pop();
     29             if (hi <= lo + CUTOFF)
     30             {
     31                 insertion(a, lo, hi, d);
     32                 continue;
     33             }
     34             for (int i = lo; i <= hi; i++)      // 以字符串的第 d 位进行统计
     35                 first[charAt(a[i], d) + 2]++;
     36             first[0] = lo;                      // 前部垫起
     37             for (int c = 0; c <= R; c++)        // 前缀和与子问题分配
     38             {
     39                 first[c + 1] += first[c];
     40                 if (c > 0 && first[c + 1] - 1 > first[c])       // 存在至少 2 个第 d 位为 c 的字符串,注意排除 c == 0 的情况
     41                 {
     42                     st.push(first[c]);                          // 添加子问题,对第 d 位为 c 的所有字符串关于第 d+1 位进行排序
     43                     st.push(first[c + 1] - 1);
     44                     st.push(d + 1);
     45                 }
     46             }
     47             for (int c = 0; c < R + 2; c++)     // 拷贝 first 到 next 中,next 用于搬运字符串过程中的变化索引
     48                 next[c] = first[c];
     49             for (int k = lo; k <= hi; k++)      // 搬运字符串到指定位置,循环将 a[k] 作为交换的临时位置
     50             {
     51                 int c = charAt(a[k], d) + 1;                    // 取 a[k] 的第 d 位的下一个字符
     52                 for (; first[c] > k; c = charAt(a[k], d) + 1)   // 只要 c 出现的位置排在 k 后面,就交换 a[k] 和 a[next[c]],并且 next[c]向后移一个位置
     53                     exch(a, k, next[c]++);
     54                 next[c]++;                                      // 全部移完了,next[c] 再自增 1,表示 c 开头的索引已经等于 first[c+1],避免重复排序
     55             }
     56             for (int c = 0; c < R + 2; c++)     // 清除 first 和 next
     57                 first[c] = next[c] = 0;
     58         }
     59     }
     60 
     61     private static void insertion(String[] a, int lo, int hi, int d)
     62     {
     63         for (int i = lo; i <= hi; i++)
     64         {
     65             for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
     66                 exch(a, j, j - 1);
     67         }
     68     }
     69 
     70     private static int charAt(String s, int d)
     71     {
     72         assert d >= 0 && d <= s.length();
     73         if (d == s.length())
     74             return -1;
     75         return s.charAt(d);
     76     }
     77 
     78     private static void exch(String[] a, int i, int j)
     79     {
     80         String temp = a[i];
     81         a[i] = a[j];
     82         a[j] = temp;
     83     }
     84 
     85     private static boolean less(String v, String w, int d)
     86     {
     87         assert v.substring(0, d).equals(w.substring(0, d));
     88         for (int i = d; i < Math.min(v.length(), w.length()); i++)
     89         {
     90             if (v.charAt(i) == w.charAt(i))
     91                 continue;
     92             return v.charAt(i) < w.charAt(i);
     93         }
     94         return v.length() < w.length();
     95     }
     96 
     97     public static void sort(int[] a)                            // 数组排序
     98     {
     99         sortKernel(a, 0, a.length - 1);
    100     }
    101 
    102     private static void sortKernel(int[] a, int lo, int hi)
    103     {
    104         Stack<Integer> st = new Stack<Integer>();
    105         int[] first = new int[R + 1], next = new int[R + 1];
    106         int mask = R - 1, d = 0;
    107         for (st.push(lo), st.push(hi), st.push(d); !st.isEmpty();)
    108         {
    109             d = st.pop(); hi = st.pop(); lo = st.pop();
    110             if (hi <= lo + CUTOFF)
    111             {
    112                 insertion(a, lo, hi, d);
    113                 continue;
    114             }
    115             int shift = BITS_PER_INT - BITS_PER_BYTE * (d + 1); // 取从左往右的第 d 字节
    116             for (int i = lo; i <= hi; i++)
    117                 first[((a[i] >> shift) & mask) + 1]++;
    118             first[0] = lo;
    119             for (int c = 0; c < R; c++)
    120             {
    121                 first[c + 1] += first[c];
    122                 if (d < 3 && first[c + 1] - 1 > first[c])       // c > 0 条件改为,当前字节不是最低字节
    123                 {
    124                     st.push(first[c]);
    125                     st.push(first[c + 1] - 1);
    126                     st.push(d + 1);
    127                 }
    128             }
    129             for (int c = 0; c < R + 1; c++)
    130                 next[c] = first[c];
    131             for (int k = lo; k <= hi; k++)
    132             {
    133                 int c = (a[k] >> shift) & mask;
    134                 for (; first[c] > k; c = (a[k] >> shift) & mask)
    135                     exch(a, k, next[c]++);
    136                 next[c]++;
    137             }
    138             for (int c = 0; c < R + 1; c++)
    139                 first[c] = next[c] = 0;
    140         }
    141     }
    142 
    143     private static void insertion(int[] a, int lo, int hi, int d)
    144     {
    145         for (int i = lo; i <= hi; i++)
    146         {
    147             for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
    148                 exch(a, j, j - 1);
    149         }
    150     }
    151 
    152     private static void exch(int[] a, int i, int j)
    153     {
    154         int temp = a[i];
    155         a[i] = a[j];
    156         a[j] = temp;
    157     }
    158 
    159     private static boolean less(int v, int w, int d)
    160     {
    161         int mask = R - 1;
    162         for (int i = d; i < 4; i++)
    163         {
    164             int shift = BITS_PER_INT - BITS_PER_BYTE * (i + 1);
    165             int a = (v >> shift) & mask, b = (w >> shift) & mask;
    166             if (a == b)
    167                 continue;
    168             return a < b;
    169         }
    170         return false;
    171     }
    172 
    173     public static void main(String[] args)
    174     {
    175         if (args.length > 0 && args[0].equals("int"))
    176         {
    177             int[] a = StdIn.readAllInts();
    178             sort(a);
    179 
    180             for (int i = 0; i < a.length; i++)
    181                 StdOut.println(a[i]);
    182         }
    183         else
    184         {
    185             String[] a = StdIn.readAllStrings();
    186             sort(a);
    187 
    188             for (int i = 0; i < a.length; i++)
    189                 StdOut.println(a[i]);
    190         }
    191     }
    192 }

    ● 美国国旗排序 2

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdIn;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.Stack;
      6 
      7 public class class01
      8 {
      9     private static final int R = 256;
     10     private static final int CUTOFF = 15;
     11 
     12     private class01() {}
     13 
     14     public static void sort(String[] a)
     15     {
     16         sortKernel(a, 0, a.length - 1);
     17     }
     18 
     19     public static void sortKernel(String[] a, int lo, int hi)
     20     {
     21         Stack<Integer> st = new Stack<Integer>();
     22         int[] count = new int[R + 1];
     23         int d = 0;
     24         for (st.push(lo), st.push(hi), st.push(d); !st.isEmpty();)
     25         {
     26             d = st.pop(); hi = st.pop(); lo = st.pop();
     27             if (hi <= lo + CUTOFF)
     28             {
     29                 insertion(a, lo, hi, d);
     30                 continue;
     31             }
     32             for (int i = lo; i <= hi; i++)
     33                 count[charAt(a[i], d) + 1]++;
     34             count[0] += lo;
     35             for (int c = 0; c < R; c++)
     36             {
     37                 count[c + 1] += count[c];                   // count[c] 表示键值不大于 c 的元素个数(相当于字符 c+1 起始位置先前 1 格)
     38                 if (c > 0 && count[c + 1] - 1 > count[c])
     39                 {
     40                     st.push(count[c]);
     41                     st.push(count[c + 1] - 1);
     42                     st.push(d + 1);
     43                 }
     44             }
     45             for (int r = hi; r >= lo; r--)                  // r 从后向前
     46             {
     47                 int c = charAt(a[r], d) + 1;
     48                 for (; r >= lo && count[c] - 1 <= r;)
     49                 {
     50                     if (count[c] - 1 == r)
     51                         count[c]--;
     52                     r--;
     53                     if (r >= lo)
     54                         c = charAt(a[r], d) + 1;
     55                 }
     56                 if (r < lo)                                 // r 已经降到 lo 以下,调整完成
     57                     break;
     58                 for (count[c]--; count[c] != r; c = charAt(a[r], d) + 1, count[c]--)
     59                     exch(a, r, count[c]);
     60             }
     61         }
     62         for (int c = 0; c < R + 1; c++)                     // 清除 count
     63             count[c] = 0;
     64     }
     65 
     66     private static void insertion(String[] a, int lo, int hi, int d)
     67     {
     68         for (int i = lo; i <= hi; i++)
     69         {
     70             for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
     71                 exch(a, j, j - 1);
     72         }
     73     }
     74 
     75     private static int charAt(String s, int d)
     76     {
     77         assert d >= 0 && d <= s.length();
     78         if (d == s.length())
     79             return -1;
     80         return s.charAt(d);
     81     }
     82 
     83     private static void exch(String[] a, int i, int j)
     84     {
     85         String temp = a[i];
     86         a[i] = a[j];
     87         a[j] = temp;
     88     }
     89 
     90     private static boolean less(String v, String w, int d)
     91     {
     92         assert v.substring(0, d).equals(w.substring(0, d));
     93         for (int i = d; i < Math.min(v.length(), w.length()); i++)
     94         {
     95             if (v.charAt(i) == w.charAt(i))
     96                 continue;
     97             return v.charAt(i) < w.charAt(i);
     98         }
     99         return v.length() < w.length();
    100     }
    101 
    102     public static void main(String[] args)
    103     {
    104         String[] a = StdIn.readAllStrings();
    105         sort(a);
    106 
    107         for (int i = 0; i < a.length; i++)
    108             StdOut.println(a[i]);
    109     }
    110 }
  • 相关阅读:
    【POJ 1958】 Strange Towers of Hanoi
    【HNOI 2003】 激光炸弹
    【POJ 3263】 Tallest Cow
    【POJ 2689】 Prime Distance
    【POJ 2777】 Count Color
    【POJ 1995】 Raising Modulo Numbers
    【POJ 1845】 Sumdiv
    6月16日省中集训题解
    【TJOI 2018】数学计算
    【POJ 1275】 Cashier Employment
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869279.html
Copyright © 2011-2022 走看看