▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(计数 + 插排),(原地排序),(三路快排,与前面的三路归并排序相同)

● 计数 + 插排

 package package01;

 import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private static final int BITS_PER_BYTE = 8;
private static final int BITS_PER_INT = 32;
private static final int R = 256;
private static final int CUTOFF = 15; // 尺寸不超过 CUTOFF 的数组使用插入排序 private class01() {} public static void sort(String[] a) // 对字符串的排序
{
int n = a.length;
String[] aux = new String[n];
sortKernel(a, 0, n - 1, 0, aux);
} private static void sortKernel(String[] a, int lo, int hi, int d, String[] aux)
{
if (hi <= lo + CUTOFF) // 数组较小,使用插入排序
{
insertion(a, lo, hi, d);
return;
}
int[] count = new int[R + 2];
for (int i = lo; i <= hi; i++)
count[charAt(a[i], d) + 2]++;
for (int r = 0; r < R + 1; r++)
count[r + 1] += count[r];
for (int i = lo; i <= hi; i++)
aux[count[charAt(a[i], d) + 1]++] = a[i];
for (int i = lo; i <= hi; i++) // 写回时注意偏移
a[i] = aux[i - lo];
for (int r = 0; r < R; r++) // 每个字母开头的子数组分别排序
sortKernel(a, lo + count[r], lo + count[r + 1] - 1, d + 1, aux);
} private static void insertion(String[] a, int lo, int hi, int d) // 数组 a 关于第 d 位插入排序
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
exch(a, j, j - 1);
}
} private static void exch(String[] a, int i, int j)
{
String temp = a[i];
a[i] = a[j];
a[j] = temp;
} private static int charAt(String s, int d) // 按索引取字符串的字符
{
assert d >= 0 && d <= s.length();
if (d == s.length())
return -1;
return s.charAt(d);
} private static boolean less(String v, String w, int d)
{
//assert v.substring(0, d).equals(w.substring(0, d)); // 先检查等于
for (int i = d; i < Math.min(v.length(), w.length()); i++)
{
if (v.charAt(i) < w.charAt(i))
return true;
if (v.charAt(i) > w.charAt(i))
return false;
}
return v.length() < w.length();
} public static void sort(int[] a) // 对数组的排序
{
int n = a.length;
int[] aux = new int[n];
sortKernel(a, 0, n - 1, 0, aux);
} private static void sortKernel(int[] a, int lo, int hi, int d, int[] aux)
{
if (hi <= lo + CUTOFF)
{
insertion(a, lo, hi, d);
return;
}
int[] count = new int[R + 1];
int mask = R - 1;
int shift = BITS_PER_INT - BITS_PER_BYTE * d - BITS_PER_BYTE;
for (int i = lo; i <= hi; i++)
{
int c = (a[i] >> shift) & mask;
count[c + 1]++;
}
for (int r = 0; r < R; r++)
count[r + 1] += count[r];
if (d == 0) // 符号位,0x00-0x7F 要排在 0x80-0xFF 的后面
{
int shift1 = count[R] - count[R / 2];
int shift2 = count[R / 2];
for (int r = 0; r < R / 2; r++)
count[r] += shift1;
for (int r = R / 2; r < R; r++)
count[r] -= shift2;
}
for (int i = lo; i <= hi; i++)
{
int c = (a[i] >> shift) & mask;
aux[count[c]++] = a[i];
}
for (int i = lo; i <= hi; i++)
a[i] = aux[i - lo];
if (d == 4) // 已经到了最高位,不用分治了
return;
if (count[0] > 0)
sortKernel(a, lo, lo + count[0] - 1, d + 1, aux);
for (int r = 0; r < R; r++)
{
if (count[r + 1] > count[r]) // 存在数字第 d 位是 r 的数字需要排序
sortKernel(a, lo + count[r], lo + count[r + 1] - 1, d + 1, aux);
}
} private static void insertion(int[] a, int lo, int hi, int d)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && a[j] < a[j - 1]; j--)
exch(a, j, j - 1);
}
} private static void exch(int[] a, int i, int j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
} public static void main(String[] args)
{
String[] a = StdIn.readAllStrings();
int n = a.length;
sort(a);
for (int i = 0; i < n; i++)
StdOut.println(a[i]);
}
}

● 原地排序

 package package01;

 import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01
{
private static final int R = 256;
private static final int CUTOFF = 0; private class01() {} public static void sort(String[] a)
{
int n = a.length;
sortKernel(a, 0, n - 1, 0);
} private static void sortKernel(String[] a, int lo, int hi, int d)
{
if (hi <= lo + CUTOFF)
{
insertion(a, lo, hi, d);
return;
}
int[] heads = new int[R + 2]; // 需要记录每个字符出现的首位和末位
int[] tails = new int[R + 1];
for (int i = lo; i <= hi; i++)
heads[charAt(a[i], d) + 2]++;
heads[0] = lo; // heads 首位设为 lo,方便直接做 a 的索引
for (int r = 0; r < R + 1; r++)
{
heads[r + 1] += heads[r];
tails[r] = heads[r + 1]; // tails 等于前缀和的 heads 左移一格,等于下一个字符出现的位置
}
for (int r = 0; r < R + 1; r++) // 循环完成所有字符
{
for (; heads[r] < tails[r]; heads[r]++) // 循环直到所有 heads 向 tails 靠拢
{
// a[heads[r]] 作为临时位置,每次把其上字符串发送到排序后正确的位置上,替换下来的字符串放回,用于下一次发送
for (int c = charAt(a[heads[r]], d); c + 1 != r; c = charAt(a[heads[r]], d))
exch(a, heads[r], heads[c + 1]++); // 每次发送后要后移同一字符串的目标位置
}
}
for (int r = 0; r < R; r++) // 分治所有子数组
sortKernel(a, tails[r], tails[r + 1] - 1, d + 1);
} private static void insertion(String[] a, int lo, int hi, int d)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
exch(a, j, j - 1);
}
} private static void exch(String[] a, int i, int j)
{
String temp = a[i];
a[i] = a[j];
a[j] = temp;
} private static int charAt(String s, int d)
{
assert d >= 0 && d <= s.length();
if (d == s.length())
return -1;
return s.charAt(d);
} private static boolean less(String v, String w, int d)
{
// assert v.substring(0, d).equals(w.substring(0, d));
for (int i = d; i < Math.min(v.length(), w.length()); i++)
{
if (v.charAt(i) < w.charAt(i))
return true;
if (v.charAt(i) > w.charAt(i))
return false;
}
return v.length() < w.length();
} public static void main(String[] args)
{
String[] a = StdIn.readAllStrings();
int n = a.length;
sort(a);
for (int i = 0; i < n; i++)
StdOut.println(a[i]);
}
}

● 三路快排

 package package01;

 import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom; public class class01
{
private static final int CUTOFF = 15; private class01() {} public static void sort(String[] a)
{
StdRandom.shuffle(a);
sortKernel(a, 0, a.length - 1, 0);
} private static void sortKernel(String[] a, int lo, int hi, int d)
{
if (hi <= lo + CUTOFF)
{
insertion(a, lo, hi, d);
return;
}
int lt = lo, gt = hi;
int v = charAt(a[lo], d);
for (int i = lo + 1; i <= gt;)
{
int t = charAt(a[i], d);
if (t < v)
exch(a, lt++, i++);
else if (t > v)
exch(a, i, gt--);
else
i++;
}
sortKernel(a, lo, lt - 1, d);
if (v >= 0)
sortKernel(a, lt, gt, d + 1);
sortKernel(a, gt + 1, hi, d);
} private static void insertion(String[] a, int lo, int hi, int d)
{
for (int i = lo; i <= hi; i++)
{
for (int j = i; j > lo && less(a[j], a[j - 1], d); j--)
exch(a, j, j - 1);
}
} private static boolean less(String v, String w, int d)
{
assert v.substring(0, d).equals(w.substring(0, d));
for (int i = d; i < Math.min(v.length(), w.length()); i++)
{
if (v.charAt(i) < w.charAt(i))
return true;
if (v.charAt(i) > w.charAt(i))
return false;
}
return v.length() < w.length();
} private static int charAt(String s, int d)
{
assert d >= 0 && d <= s.length();
if (d == s.length())
return -1;
return s.charAt(d);
} private static void exch(String[] a, int i, int j)
{
String temp = a[i];
a[i] = a[j];
a[j] = temp;
} public static void main(String[] args)
{
String[] a = StdIn.readAllStrings();
int n = a.length; sort(a); for (int i = 0; i < n; i++)
StdOut.println(a[i]);
}
}

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

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(美国国旗排序) ● 美国国旗排序 package package01; import edu.princeton.cs.algs4 ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,适用于基因序列的 2-Bit 压缩算法,行程长压缩算法,Huffman 压缩算法,LZW 压缩算法 ● 适用于基因序列的 2-Bit 压缩算法 pac ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串的二进制表示.十六进制表示.图形表示 ● 二进制表示 package package01; import edu.princeton.cs.al ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,非确定性有穷自动机(NFA),grep 命令(利用 NFA 匹配) ● 非确定性有穷自动机(NFA) package package01; impor ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,Knuth-Morris-Pratt 无回溯匹配,Boyer - Moore 无回溯匹配,Rabin - Karp 指纹匹配 ● Knuth-Morr ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,Trie 树类,Trie 集合,三值搜索树(Ternary Search Trie) ● Trie 树类 package package01; imp ...

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

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字母表类,字符串低位优先排序(桶排) ● 字母表类 package package01; import edu.princeton.cs.algs4. ...

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

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  9. 《算法》第一章部分程序 part 1

    ▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...

随机推荐

  1. 《LOST》 电视

    还没看正剧,所以转来帮助看电视 从起源到终点:<LOST>剧情全解析(一)   此文是LOST完结之后的剧情解析,剧透,慎入   从起源到终点:<LOST>剧情全解析(一) 转 ...

  2. CAD二次开发中浮动面板不浮动的问题

    CAD二次开发中创建了一个浮动面板,想让它创建出来后以浮动状态显示, 但是DockSides.None设置完后,面板还是不浮动.搞了很久,最后原来是 需要先设置Visible,再设置DockSides ...

  3. ALGO-12_蓝桥杯_算法训练_幂方分解(递归)

    问题描述 任何一个正整数都可以用2的幂次方表示.例如: =++ 同时约定方次用括号来表示,即ab 可表示为a(b). 由此可知,137可表示为: ()+()+() 进一步:= ++ (21用2表示) ...

  4. C++进阶--静态初始化的惨败

    /* Initialization Fiasco 一个会使程序崩溃的细微的问题 */ // 不同文件的编译顺序是不确定的 // 如果一个文件依赖另一个文件的对象先初始化,可能出现问题 // 解决方法: ...

  5. [Java]JGit用法总结

    clone public static void gitClone(String remoteUrl, File repoDir) { try { Git git = Git.cloneReposit ...

  6. Flume的Sink

    一.Logger Sink 记录指定级别(比如INFO,DEBUG,ERROR等)的日志,通常用于调试 要求,在 --conf(-c )参数指定的目录下有log4j的配置文件 根据设计,logger ...

  7. 服务容错保护断路器Hystrix之六:缓存功能的使用

    高并发环境下如果能处理好缓存就可以有效的减小服务器的压力,Java中有许多非常好用的缓存工具,比如Redis.EHCache等,当然在Spring Cloud的Hystrix中也提供了请求缓存的功能, ...

  8. 廖雪峰Java2面向对象编程-4抽象类和接口-2接口

    1.接口的定义 抽象方法本质上是定义接口规范. 在抽象类中定义了一个抽象方法,子类中必须实现这个抽象方法. public abstract class Person{ public abstract ...

  9. 廖雪峰Java1-2程序基础-9数组

    数组初识 1.数组的特点: 数组所有元素初始化默认值,int默认值为0 数组创建后大小不可改变 数组索引从0开始 数组是引用类型 使用索引下标访问数组元素,索引超出范围会报错 2.数组的定义: 类型[ ...

  10. JQuery中Ajax的Post提交在IE下中文乱码的解决方法

    原文地址:http://www.bitscn.com/pdb/ajax/316671.html 引言: 在JQuery的Ajax POST请求中,进行请求,其中的中文在后台,显示为乱码,该如何解决呢? ...