《算法》第五章部分程序 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 }

原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869261.html

时间: 2024-08-04 21:32:29

《算法》第五章部分程序 part 2的相关文章

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

? 书中第五章部分程序,包括在加上自己补充的代码,Trie 树类,Trie 集合,三值搜索树(Ternary Search Trie) ● Trie 树类 1 package package01; 2 3 import edu.princeton.cs.algs4.StdIn; 4 import edu.princeton.cs.algs4.StdOut; 5 import edu.princeton.cs.algs4.Queue; 6 7 public class class01<Value>

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

? 书中第五章部分程序,包括在加上自己补充的代码,字母表类,字符串低位优先排序(桶排) ● 字母表类 1 package package01; 2 3 import edu.princeton.cs.algs4.StdOut; 4 5 public class class01 6 { 7 public static final class01 BINARY = new class01("01"); 8 9 public static final class01 OCTAL = new

《算法》第五章部分程序 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 B

Gradle 1.12用户指南翻译——第四十五章. 应用程序插件

文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc 本文翻译所在分支: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/usergu

《算法》第一章部分程序

? 书中第一章部分程序,加上自己补充的代码.包括若干种二分搜索和寻找图上连通分量数的两种算法. ● 代码,二分搜索 1 package package01; 2 3 import java.util.Arrays; 4 import edu.princeton.cs.algs4.StdRandom; 5 6 public class class01 7 { 8 public int binarySearch(int [] a, int target) // 非递归实现 9 { 10 int lp

第五章 C程序结构

一.数值类型 1.实数常量的表示:3.5(双精度),3.5f(单精度),3.5L(长双精度) 2.整数常量:char字符常量('a','b','0')当做一个整型常量参加运算 3.数字字符与英文字母字符的编号(Ascll码)都是顺序连接的 二.控制语句 1.while和do while的区别:当while条件不成立时,while()循环不执行循环语句,而do while会循环执行一次循环语句再判断 2.流程控制语句:continue(中断本次循环)    break(跳出整个循环) 3.开关语句

算法第五章小结

一.回溯算法的概念以及理解 概念:回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标. 理解:在回溯法中,每次扩大当前部分解时,都面临一个可选的状态集合,新的部分解就通过在该集合中选择构造而成.这样的状态集合,其结构是一棵多叉树,每个树结点代表一个可能的部分解,它的儿子是在它的基础上生成的其他部分解.树根为初始状态,这样的状态集合称为状态空间树. 二.“子集和”问题的解空间结构和约束函数 1.解空间结构 非负非零的整数集合 S = {x1, x2, …, xn}

算法第五章上机实践报告

一 . 实践题目 7-2 工作分配问题 二 . 问题描述 设有n件工作分配给n个人.将工作i分配给第j个人所需的费用为cij . 设计一个算法,对于给定的工作费用,为每一个人都分配1 件不同的工作,并使总费用达到最小. 输入格式: 输入数据的第一行有1 个正整数n (1≤n≤20).接下来的n行,每行n个数,表示工作费用. 输出格式: 将计算出的最小总费用输出到屏幕. 输入样例: 3 10 2 3 2 3 4 3 4 5 输出样例: 9 三 . 算法描述 1. 解空间 第一个人选择第几个工作,第

算法第五章 | 回溯算法

一. 回溯算法 回溯法有"通用的解题法"之称.可以系统地搜索一个问题的所有解或任一解,是一个既带有系统性又带有跳跃性的搜索算法. 它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树.算法搜索至解空间树的任一结点时,先判断该结点是否包含问题的解.如果肯定不包含,则跳过对以该结点为根的子树的搜索,逐层向其祖先结点回溯.否则,进入该子树,继续按深度优先策略搜索.回溯法求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束.回溯法求问题的一个解时,只要搜索到问题的一个解