2つの古典的な文字列の並べ替え方法を説明するための例示および例のコード解析を介して文字列のソートの核となるアイデアの周りにこの記事では、コンテンツは、物品の端部に配置され、非常に詳細で完全なコードです。
まず、キーインデックス表記
一般絶えず要素と比較されなければならないの並べ替え、およびこのようなものは、比較する必要がない文字列では、別のアイデアがあります。キーインデックス計数法では、ソートアルゴリズムNlongN実行時間制限を破る、とすることができ、それはレベルが線形である時間です!
アルファベットの概念の導入:
など3として見「」1とみなし、2とみなさ「B」、「C」として比較してほしくない文字列、我々はアルファベットの概念を導入する必要があるが、これは続けて、唯一の26文字が必要ですアレイ27の長さは、(添字0なし)で表されることができ、それらは図面(Z 1〜26から対応する)に従って順序付けられます。
だから、「ABCDEFG ..」これらの文字は、整数(のcharAt()関数を使用して)、そこに対応する天然の配列であるので、我々はただ情報の各文字を保存するために使用される適当な大きさの配列を見つける必要があるに変換され、それはすることができます。今、私たちは256の[]配列のサイズをカウント作成、インデックスは、時間を節約するために使用され、対応する周波数仕分けの文字が表示されます。
インデックス表記は、4つのステップに分割され、そして実施例について説明します。(タイプ文字Rで示される、Rは、Rの文字の順序を表します。)
図1に示すように、周波数を計算します。
以下のために(int型 i = 0; iがNを<; iは++ ){ //计算频率
カウント[[I] .charAt(D) +1] ++ ;
}
すべての文字列を通じ、Dは、文字列のd番目の文字(下の例では一桁の文字列です)です。
表示されたどのような文字、我々は(R + 1は、あなたがなぜ知っている次のステップを参照してください理由である)、カウント[R + 1]プラスワンに対応します。
2、指数を計算します:
用(INT R&LT = 0; R&LT <R&LT; R&LT ++){ //は周波数インデックス変換
COUNT [R&LT + 1] + = COUNT [R&LTを];
}
我々は、計算された周波数に基づいてする必要がありますCOUNT [R&LT + 1] + COUNT = [R&LT]
それは、常にプラスかつての投稿数配列になります。
例:
教師は、プレイを組織し、学生は4つのグループに分けられた、あなたがそれを行う必要があるグループ番号(Rが4である場合には、配列のサイズはインデックス0なしで、R + 2でカウント)で学生をソートすることです
図1は、出現頻度を算出します
図2は、周波数の開始インデックスに変換されます。
最後の二つは、図列からわかるように、rは0に対応するインデックス、すなわち、ゼロから順序付けられたセットです。
Rは、開始ソートからインデックス1、すなわち、二つのグループに対応する2です。
そして第三の群屈折率は、第二群の1つから4つの完全な位置から示す、5です。
3、データ分類
以下のために(int型 i = 0; iがNを<; iは++){ //数据分类
AUX [カウント[I] .charAt(D)] ++] = [I]。
}
データ分類我々は、一時的にソートされたデータを格納するために使用される補助配列AUXを、必要とします。
すべての注文に形成されている文字列配列に変換する補助データ。
4、ライトバック
以下のために(int型 i = 0; iがNを<; iは++){ // 回写
[I] = AUX [I]。
}
補助文字列配列の内容は、バック群れに移動します。
到此为止键索引计数法就完成了,接下来利用它来实现LSD/MSD。
二、低位优先排序(LSD)
第位优先排序与高位优先排序的主要区别在于排序的方向,核心思想算法都是通过键索引计数法。低位优先算法是从字符串的右到左来排序(这可能会出现一些问题,在高位优先排序的介绍中将会提到)。
下图为一个地位优先排序的完整过程:
利用索引计数法,从左到右对每一位进行索引计数,这就形成了第位优先排序。
for (int d=W-1;d>=0;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(d)]++]=a[i];
}
for(int i=0;i<N;i++){//回写
a[i]=aux[i];
}
}
三、高位优先排序(MSD)
在低位优先排序中,可能会出现一点问题。比如字符串“ab”与“ba”,长度为2需要进行两次排序,第一次排序结果为“ba”、“ab”,第二次排序结果为“ab”、“ba”,第一次排序的结果对第二次毫无意义,这就造成了时间上的浪费。
而在高位优先排序中,只会进行一次排序。结果为“ab”、“ba”。
不同之处:
在高位排序中又引入了分组的概念,即用首字母来切分下一个排序组。
在代码中我们使用递归的方式来不断切分排序组。
1 public static void sort(String[] a,int lo,int hi,int d){
2 if(lo>=hi){
3 return;
4 }
5 int[] count=new int[R+2];
6 for(int i=lo;i<=hi;i++){
7 count[charAt(a[i],d)+2]++;
8 }
9 for(int r=0;r<R+1;r++){
10 count[r+1]+=count[r];
11 }
12 for(int i=0;i<=hi;i++){
13 aux[count[charAt(a[i],d)+1]++]=a[i];
14 }
15 for(int i=0;i<=hi;i++){
16 a[i]=aux[i];
17 }
18 for(int r=0;r<R;r++){
19 sort(a,lo+count[r],lo+count[r+1]-1,d+1);
20 }
21 }
上面这段代码非常简洁,但其中有一些地方是复杂的,请研究下面例子的调用过程确保你理解了算法。
图3 sort(a,0,9,0)的顶层调用
在下一期带来另一种字符串排序方法,三向字符串快速排序,相比于这两种方法,将会有更广的受用面!
四、完整代码
1 public class LSD { 2 public static void sort(String[] a,int W){//W表示字符串的长度 3 int N=a.length; 4 int R=256;//依字符的种类数目而定 5 String aux[]=new String[N]; 6 for (int d=W-1;d>=0;d--){//从右到左对所有字符串的每位判断 7 int count[]=new int[R+1]; 8 for(int i=0;i<N;i++){//计算频率 9 count[a[i].charAt(d)+1]++; 10 } 11 for(int r=0;r<R;r++){//将频率转换为索引 12 count[r+1]+=count[r]; 13 } 14 for(int i=0;i<N;i++){//排序 15 aux[count[a[i].charAt(d)]++]=a[i]; 16 } 17 for(int i=0;i<N;i++){//回写 18 a[i]=aux[i]; 19 } 20 } 21 } 22 }
1 public class MSD { 2 private static int R=256; 3 private static String[] aux; 4 5 public static int charAt(String s,int d){ 6 if(d<s.length()){ 7 return s.charAt(d); 8 }else{ 9 return -1; 10 } 11 } 12 13 public static void sort(String[] a){ 14 int N=a.length; 15 aux=new String[N]; 16 sort(a,0,N-1,0); 17 } 18 19 public static void sort(String[] a,int lo,int hi,int d){ 20 if(lo>=hi){ 21 return; 22 } 23 int[] count=new int[R+2]; 24 for(int i=lo;i<=hi;i++){ 25 count[charAt(a[i],d)+2]++; 26 } 27 for(int r=0;r<R+1;r++){ 28 count[r+1]+=count[r]; 29 } 30 for(int i=0;i<=hi;i++){ 31 aux[count[charAt(a[i],d)+1]++]=a[i]; 32 } 33 for(int i=0;i<=hi;i++){ 34 a[i]=aux[i]; 35 } 36 for(int r=0;r<R;r++){ 37 sort(a,lo+count[r],lo+count[r+1]-1,d+1); 38 } 39 } 40 }