《算法》第五章部分程序 part 2
Posted cuancuancuanhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法》第五章部分程序 part 2相关的知识,希望对你有一定的参考价值。
? 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(计数 + 插排),(原地排序),(三路快排,与前面的三路归并排序相同)
● 计数 + 插排
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 6 public class class01 7 { 8 private static final int BITS_PER_BYTE = 8; 9 private static final int BITS_PER_INT = 32; 10 private static final int R = 256; 11 private static final int CUTOFF = 15; // 尺寸不超过 CUTOFF 的数组使用插入排序 12 13 private class01() {} 14 15 public static void sort(String[] a) // 对字符串的排序 16 { 17 int n = a.length; 18 String[] aux = new String[n]; 19 sortKernel(a, 0, n - 1, 0, aux); 20 } 21 22 private static void sortKernel(String[] a, int lo, int hi, int d, String[] aux) 23 { 24 if (hi <= lo + CUTOFF) // 数组较小,使用插入排序 25 { 26 insertion(a, lo, hi, d); 27 return; 28 } 29 int[] count = new int[R + 2]; 30 for (int i = lo; i <= hi; i++) 31 count[charAt(a[i], d) + 2]++; 32 for (int r = 0; r < R + 1; r++) 33 count[r + 1] += count[r]; 34 for (int i = lo; i <= hi; i++) 35 aux[count[charAt(a[i], d) + 1]++] = a[i]; 36 for (int i = lo; i <= hi; i++) // 写回时注意偏移 37 a[i] = aux[i - lo]; 38 for (int r = 0; r < R; r++) // 每个字母开头的子数组分别排序 39 sortKernel(a, lo + count[r], lo + count[r + 1] - 1, d + 1, aux); 40 } 41 42 private static void insertion(String[] a, int lo, int hi, int d) // 数组 a 关于第 d 位插入排序 43 { 44 for (int i = lo; i <= hi; i++) 45 { 46 for (int j = i; j > lo && less(a[j], a[j - 1], d); j--) 47 exch(a, j, j - 1); 48 } 49 } 50 51 private static void exch(String[] a, int i, int j) 52 { 53 String temp = a[i]; 54 a[i] = a[j]; 55 a[j] = temp; 56 } 57 58 private static int charAt(String s, int d) // 按索引取字符串的字符 59 { 60 assert d >= 0 && d <= s.length(); 61 if (d == s.length()) 62 return -1; 63 return s.charAt(d); 64 } 65 66 private static boolean less(String v, String w, int d) 67 { 68 //assert v.substring(0, d).equals(w.substring(0, d)); // 先检查等于 69 for (int i = d; i < Math.min(v.length(), w.length()); i++) 70 { 71 if (v.charAt(i) < w.charAt(i)) 72 return true; 73 if (v.charAt(i) > w.charAt(i)) 74 return false; 75 } 76 return v.length() < w.length(); 77 } 78 79 public static void sort(int[] a) // 对数组的排序 80 { 81 int n = a.length; 82 int[] aux = new int[n]; 83 sortKernel(a, 0, n - 1, 0, aux); 84 } 85 86 private static void sortKernel(int[] a, int lo, int hi, int d, int[] aux) 87 { 88 if (hi <= lo + CUTOFF) 89 { 90 insertion(a, lo, hi, d); 91 return; 92 } 93 int[] count = new int[R + 1]; 94 int mask = R - 1; 95 int shift = BITS_PER_INT - BITS_PER_BYTE * d - BITS_PER_BYTE; 96 for (int i = lo; i <= hi; i++) 97 { 98 int c = (a[i] >> shift) & mask; 99 count[c + 1]++; 100 } 101 for (int r = 0; r < R; r++) 102 count[r + 1] += count[r]; 103 if (d == 0) // 符号位,0x00-0x7F 要排在 0x80-0xFF 的后面 104 { 105 int shift1 = count[R] - count[R / 2]; 106 int shift2 = count[R / 2]; 107 for (int r = 0; r < R / 2; r++) 108 count[r] += shift1; 109 for (int r = R / 2; r < R; r++) 110 count[r] -= shift2; 111 } 112 for (int i = lo; i <= hi; i++) 113 { 114 int c = (a[i] >> shift) & mask; 115 aux[count[c]++] = a[i]; 116 } 117 for (int i = lo; i <= hi; i++) 118 a[i] = aux[i - lo]; 119 if (d == 4) // 已经到了最高位,不用分治了 120 return; 121 if (count[0] > 0) 122 sortKernel(a, lo, lo + count[0] - 1, d + 1, aux); 123 for (int r = 0; r < R; r++) 124 { 125 if (count[r + 1] > count[r]) // 存在数字第 d 位是 r 的数字需要排序 126 sortKernel(a, lo + count[r], lo + count[r + 1] - 1, d + 1, aux); 127 } 128 } 129 130 private static void insertion(int[] a, int lo, int hi, int d) 131 { 132 for (int i = lo; i <= hi; i++) 133 { 134 for (int j = i; j > lo && a[j] < a[j - 1]; j--) 135 exch(a, j, j - 1); 136 } 137 } 138 139 private static void exch(int[] a, int i, int j) 140 { 141 int temp = a[i]; 142 a[i] = a[j]; 143 a[j] = temp; 144 } 145 146 public static void main(String[] args) 147 { 148 String[] a = StdIn.readAllStrings(); 149 int n = a.length; 150 sort(a); 151 for (int i = 0; i < n; i++) 152 StdOut.println(a[i]); 153 } 154 }
● 原地排序
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 6 public class class01 7 { 8 private static final int R = 256; 9 private static final int CUTOFF = 0; 10 11 private class01() {} 12 13 public static void sort(String[] a) 14 { 15 int n = a.length; 16 sortKernel(a, 0, n - 1, 0); 17 } 18 19 private static void sortKernel(String[] a, int lo, int hi, int d) 20 { 21 if (hi <= lo + CUTOFF) 22 { 23 insertion(a, lo, hi, d); 24 return; 25 } 26 int[] heads = new int[R + 2]; // 需要记录每个字符出现的首位和末位 27 int[] tails = new int[R + 1]; 28 for (int i = lo; i <= hi; i++) 29 heads[charAt(a[i], d) + 2]++; 30 heads[0] = lo; // heads 首位设为 lo,方便直接做 a 的索引 31 for (int r = 0; r < R + 1; r++) 32 { 33 heads[r + 1] += heads[r]; 34 tails[r] = heads[r + 1]; // tails 等于前缀和的 heads 左移一格,等于下一个字符出现的位置 35 } 36 for (int r = 0; r < R + 1; r++) // 循环完成所有字符 37 { 38 for (; heads[r] < tails[r]; heads[r]++) // 循环直到所有 heads 向 tails 靠拢 39 { 40 // a[heads[r]] 作为临时位置,每次把其上字符串发送到排序后正确的位置上,替换下来的字符串放回,用于下一次发送 41 for (int c = charAt(a[heads[r]], d); c + 1 != r; c = charAt(a[heads[r]], d)) 42 exch(a, heads[r], heads[c + 1]++); // 每次发送后要后移同一字符串的目标位置 43 } 44 } 45 for (int r = 0; r < R; r++) // 分治所有子数组 46 sortKernel(a, tails[r], tails[r + 1] - 1, d + 1); 47 } 48 49 private static void insertion(String[] a, int lo, int hi, int d) 50 { 51 for (int i = lo; i <= hi; i++) 52 { 53 for (int j = i; j > lo && less(a[j], a[j - 1], d); j--) 54 exch(a, j, j - 1); 55 } 56 } 57 58 private static void exch(String[] a, int i, int j) 59 { 60 String temp = a[i]; 61 a[i] = a[j]; 62 a[j] = temp; 63 } 64 65 private static int charAt(String s, int d) 66 { 67 assert d >= 0 && d <= s.length(); 68 if (d == s.length()) 69 return -1; 70 return s.charAt(d); 71 } 72 73 private static boolean less(String v, String w, int d) 74 { 75 // assert v.substring(0, d).equals(w.substring(0, d)); 76 for (int i = d; i < Math.min(v.length(), w.length()); i++) 77 { 78 if (v.charAt(i) < w.charAt(i)) 79 return true; 80 if (v.charAt(i) > w.charAt(i)) 81 return false; 82 } 83 return v.length() < w.length(); 84 } 85 86 public static void main(String[] args) 87 { 88 String[] a = StdIn.readAllStrings(); 89 int n = a.length; 90 sort(a); 91 for (int i = 0; i < n; i++) 92 StdOut.println(a[i]); 93 } 94 }
● 三路快排
1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.StdRandom; 6 7 public class class01 8 { 9 private static final int CUTOFF = 15; 10 11 private class01() {} 12 13 public static void sort(String[] a) 14 { 15 StdRandom.shuffle(a); 16 sortKernel(a, 0, a.length - 1, 0); 17 } 18 19 private static void sortKernel(String[] a, int lo, int hi, int d) 20 { 21 if (hi <= lo + CUTOFF) 22 { 23 insertion(a, lo, hi, d); 24 return; 25 } 26 int lt = lo, gt = hi; 27 int v = charAt(a[lo], d); 28 for (int i = lo + 1; i <= gt;) 29 { 30 int t = charAt(a[i], d); 31 if (t < v) 32 exch(a, lt++, i++); 33 else if (t > v) 34 exch(a, i, gt--); 35 else 36 i++; 37 } 38 sortKernel(a, lo, lt - 1, d); 39 if (v >= 0) 40 sortKernel(a, lt, gt, d + 1); 41 sortKernel(a, gt + 1, hi, d); 42 } 43 44 private static void insertion(String[] a, int lo, int hi, int d) 45 { 46 for (int i = lo; i <= hi; i++) 47 { 48 for (int j = i; j > lo && less(a[j], a[j - 1], d); j--) 49 exch(a, j, j - 1); 50 } 51 } 52 53 private static boolean less(String v, String w, int d) 54 { 55 assert v.substring(0, d).equals(w.substring(0, d)); 56 for (int i = d; i < Math.min(v.length(), w.length()); i++) 57 { 58 if (v.charAt(i) < w.charAt(i)) 59 return true; 60 if (v.charAt(i) > w.charAt(i)) 61 return false; 62 } 63 return v.length() < w.length(); 64 } 65 66 private static int charAt(String s, int d) 67 { 68 assert d >= 0 && d <= s.length(); 69 if (d == s.length()) 70 return -1; 71 return s.charAt(d); 72 } 73 74 private static void exch(String[] a, int i, int j) 75 { 76 String temp = a[i]; 77 a[i] = a[j]; 78 a[j] = temp; 79 } 80 81 public static void main(String[] args) 82 { 83 String[] a = StdIn.readAllStrings(); 84 int n = a.length; 85 86 sort(a); 87 88 for (int i = 0; i < n; i++) 89 StdOut.println(a[i]); 90 } 91 }
以上是关于《算法》第五章部分程序 part 2的主要内容,如果未能解决你的问题,请参考以下文章