键索引计数法

我们先介绍一种适合小整数键的简单排序方法,这是我们将要学习的字符串排序的基础,举个例子,我们希望将全班学生按组分类。如图

姓名

An

Br

Da

Ga

Ha

Ja

Jh

Jn

Ma

组号

2

3

3

4

1

3

4

3

1

姓名

Mb

Mi

Mo

Ro

Sm

Ta

Ta

Tp

Wh

组号

2

2

1

2

4

3

4

4

2

姓名

Wl

Ws

 

组号

3

4

 

 

我们这里用数组a[]来存储每个元素,其中每个元素都包含=一个名字和一个组号,a[i].key()返回元素的组号。

排序后的结果

姓名

Ha

Ma

Mo

An

Mb

Mi

Ro

Wh

Br

组号

1

1

1

2

2

2

2

2

3

姓名

Da

Ja

Jn

Ta

Wl

Ga

Jh

Sm

Ta

组号

3

3

3

3

3

4

4

4

4

姓名

Tp

Ws

 

组号

4

4

 

排序共分为四个步骤:

(一)频率统计

组号在0-R之间,键为组号,用一个int数组(初始全为0)统计每个键出现的频率,如果键为r,则count[r]++,但是在实际使用中我们用count[r+1]++,至于为什么将r加1,这是为了计算方便(下一步详细说明)

我i们先来进行统计:

An在第二组中,count[2+1]加1,count[3]==1继续扫描数组,Br在第三组,count[4]+1,count[4]==1,继续扫描,Da在第三组中,count[4]+1,count[4]==2……

扫描一遍数组得到count[0]=0,count[1]=0,count[2]=3,count[3]=5,count[4]=6,count[5]=6,即键1,2,3,4出现的次数分别为3,5,6,6次。

 

将频率转化为索引:

用count[]来计算每个键在排序结果中的索引位置,例如,第一组有三个人,第二组有5个人,那么第三组的同学在排序结果数组中的位置一定是8。

如图:下标从0开始

1

1

1

2

2

2

2

2

3(下标为8)

……

键1下标开始count[1]=count[1]+count[0]=0

键2下标开始count[2]=count[2]+count[1]+count[0]=3.

键3下标开始count[3]=count[3]+count[2]+count[1]+count[0]=8

即对于每个键r,小于r+1的键的频率之和为小于r的键的频率之和在加上count[r]。

这样我们就能直观的看出来,计算某个键的起始位置,只需要计算count[这个键]+……count[0]即可,count[]数组的根本目的在于计算并存储索引位置,不在于存储键的频率。

 

数据分类

‘在将count[]数组转化为一张索引表后,我们将所有元素移到一个辅助数组aux[]中进行排序,每个元素在aux[]中的位置是由它的键(组号)决定的,在移动后将count[]中对应的元素加1,这个过程只需要遍历一遍数组即可完成。这种排序是稳定的。

for(int i=0;i<a.length;i++)

{   aux[count[a[i].key()]++]=a[i];

}

其中a[i].key()获取元素的组号,count[a[i].key()]++来保证下一个元素的索引位置。

步骤如图:

分类前:

aux[]

Count[1]

 

 

Count[2]

 

 

 

 

Count[3]

 

 

 

 

 

Count[4]

 

 

 

 

 

 

分类中:

1

Count[1

 

2

2

Count[2]

 

 

3

3

3

3

Count[3]

 

4

4

Count[4]

 

 

 

 

分类后:

1

1

1

2

2

2

2

2

3

3

3

3

3

3

4

4

4

4

4

其中count[]指向3,count[2]指向8……

回写:

将辅助数组中的元素移动到原数组中

 

相关代码:

int N=a.length;

String aux[]=new String[N];

int[] count=new int[R+1];

//计算出现的次数

for(int i=;i<N;i++)

{

 count[a[i].key()+1]++;

}

 

//将频率转化为索引

for(int r=0;r<R;r++)

{

  count[r+1]+=count[r];

 }

 

 //将元素分类

 for(int i=;i<N;i++)

{

  aux[count[a[i].key()]++]=a[i];

}

 

//回写

 

for(int i=;i<N;i++)

{

 a[i]=aux[i];

}

 

 

低优先的字符串排序

一般称为低位优先,对于一个字符串,从右向左扫描,这个方法依赖于我们上面介绍的键索引记数法,非常适合排序定长的字符串,比如身份证,车牌号,IP地址等。

代码实现:

 1 public class LSD {
 2     
 3     public static void sort(String[] a,int w)
 4     {
 5         int N=a.length;
 6         int R=256;//使用扩展的ASCII字符集
 7         String[] aux=new String[N];
 8         
 9         for(int d=w-1;d>=0;d--)
10         
11         {
12             int[] count=new int[R+1];
13             for(int i=0;i<N;i++)
14             {
15                 
16               count[a[i].charAt(d)+1]++;
17             }
18             
19             for(int r=0;r<R;r++)
20             {
21                 count[r+1]+=count[r];
22             }
23             
24             for(int i=0;i<N;i++)
25             {
26                 aux[count[a[i].charAt(d)]++]=a[i];
27             }
28             
29             for(int i=0;i<N;i++)
30             {
31                 a[i]=aux[i];
32             }
33         }
34     }
35 
36     public static void main(String[] args) {
37         String[] a= {"564","964","637","159"};
38         System.out.println(a[1].charAt(2));
39         sort(a,3);
40         for(String s:a)
41         {
42             System.out.println(s);
43         }
44     }
45 
46 }
View Code

相关文章:

  • 2022-12-23
  • 2021-05-22
  • 2021-06-07
  • 2022-12-23
  • 2021-11-11
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-18
  • 2021-05-21
相关资源
相似解决方案