《算法》第五章部分程序 part 3

Posted cuancuancuanhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法》第五章部分程序 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 }

 

以上是关于《算法》第五章部分程序 part 3的主要内容,如果未能解决你的问题,请参考以下文章

《算法》第五章部分程序 part 2

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

[XJTUSE 算法设计与分析] 第五章 回溯法

ROS机器人程序设计(原书第2版)补充资料 (伍) 第五章 计算机视觉

算法第五章上机实践报告

python程序设计基础(嵩天)第五章课后习题部分答案