键索引计数法
- 频率统计
- 将频率转换为索引
- 数据分类
- 回写
频率统计:统计每个字符出现的次数
将频率转换为索引:确定不同字符首位置
低位优先的字符串排序
从右到左检查检查键中的字符
public class LSD {
public static void sort(String[] a, int w){
int n = a.length;
int R = 256;
String[] aux = new String[n];
for(int d=w-1; d>=0; d--){ //根据第d个字符用键索引计数法排序
int[] count = new int[R+1]; //计算出现频率
for(int i=0; i<n; i++)
count[a[i].charAt(d)+1]++;
for(int r=0; r<R; r++) //将频率转换为索引
count[r+1] += count[r];
for(int i=0; i<n; i++) //将元素分类
aux[count[a[i].charAt(i)]++] = a[i];
for(int i=0; i<n; i++) //回写
a[i] = aux[i];
}
}
}
高位优先的字符串排序
从左到右检查键中的字符,使用递归算法和键索引计数法
public class MSD {
private static int R = 256; //基数
private static final int M = 15; //小数组的切换阈值
private static String[] aux; //数据分类的辅助数组
private static int charAt(String s, int d){
if(d<s.length()) return s.charAt(d);
else return -1;
}
public static void sort(String[] a){
int n = a.length;
aux = new String[n];
sort(a,0,n-1,0);
}
private static void sort(String[] a, int lo, int hi, int d){
if(hi <= lo+M){
Insertion.sort(a, lo, hi, d); //小数组(小于等于M个字符串)使用插入排序,提高性能
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; 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++)
sort(a, lo+count[r], lo+count[r+1]-1, d+1); //递归
}
}
三向字符串快速排序
根据键的首字母进行三向切分,仅在中间子数组的下一个字符(因为键的首字母都与切分字符相等)继续递归排序.
public class Quick3string {
private static int charAt(String s, int d){
if(d<s.length()) return s.charAt(d);
else return -1;
}
public static void sort(String[] a){
sort(a, 0, a.length, 0);
}
private static void sort(String[] a, int lo, int hi, int d){
if(hi<=lo) return;
int lt = lo, gt = hi;
int v = charAt(a[lo], d);
int i = lo+1;
while(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++;
}
sort(a, lo, lt-1, d); //三部分中的上半部分(小)
if(v>0) sort(a, lt, gt, d+1); //三部分中的中间部分
sort(a, gt+1, hi, d); //三部分中的下半部分(大)
}
}