• 《算法》第五章部分程序 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 }
  • 相关阅读:
    【职业规划】一位资深程序员大牛给予Java初学者的学习路线建议
    一个断点调试的小技巧
    无穷分数
    Spring事务异常回滚,捕获异常不抛出就不会回滚
    理解Servlet和Servlet容器、Web服务器等概念
    图解红黑树及Java进行红黑二叉树遍历的方法
    Majority Element
    Factorial Trailing Zeroes
    Valid Parentheses
    House Robber
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869279.html
Copyright © 2020-2023  润新知