键索引计数法

键索引计数法作为三种字符串排序算法中两种的基础,本身也很适用于小整数键的简单排序。

键索引计数法主要分为四步:统计频率,将频率转换为索引,数据分类,回写。

例如老师在统计学生的分数时可能会遇到以下数据处理问题。学生被分为若干班级,标号为1、2、3等。我们希望全校同学按班级分类,分类后每个班级中的姓名顺序与分类前的顺序相同(类似于从全校同学的成绩排名中抽离出每个班级同学的成绩排名),如图。因为班级的编号是较小的整数,使用键索引计数法来排序是很合适的。
5.1.1

为了说明这种方法,假设数组 a[] 中的每个元素都保存了一个名字和一个班级编号,总共N个,其中编号在0到R-1之间,代码 a[i].key() 会返回指定学生的编号。

统计频率
第一步是使用 int 数组 count[] 来统计所有键(班级编号)出现的频率。
注意这里每个班级下标加一对应的才是count数组的下标。这里下标进行了错位。

for(int i =0; i< N; i++){
	count[a[i].key()+1]++;
}

5.1.2
由于班级的编号是 0 到 R-1 的数字,所以 count 数组的长度为 R+1。

将频率转换为索引
将频率转换为索引即将频率累加。

for(int r = 0; r< R; r++){
	count[r+1] += count[r];
}

注意这里r 的判断条件为小于R,因为 count 的长度为 R+1,即最大下标为R。
5.1.3
数据分类
在将count数组转换为一张索引表后,将所有的元素(学生)移动到一个辅助数组aux[](aux是辅助的缩写)中以进行排序。每个元素在 aux[] 中的位置取决于它的键对应的 count[]值。因为之前count的统计中做了错位,即 count 数组中下标为1 的值为0,即当第一个1班的同学被读到时,存入 aux[0]的位置中,并且给 count 数组中该值自增,这样下一个1班的同学被读到时,count数组中下标为1的值对应为1了,将它存入 aux[1] 中。同理,如果读到了一个2班同学,在count[2]中找到值为3,即将它存入 aux[3]中,并将count[2]加一变为4。

for(int i = 0; i< N; i++){
	aux[ count[a[i].key()]++ ] = a[i];
}

5.1.4
5.1.5
回写
即将aux中的元素转移到原数组a中。

最终代码

int N = a.length;

int[] count = new int[R+1];
String[] aux = new String[N];

//统计频率:
for(int i = 0; i<N; i++){
	count[a[i].key()+1]++;
}
//计算起始索引:
for(int r= 0; r < R; r++){
	count[r+1] += count[r];
}
//数据分类:
for(int i = 0; i<N; i++){
	aux[ count[ a[i].key() ]++ ] = a[i];
}
//回写:
for(int i = 0; i<N; i++){
	a[i] = aux[i];
}

建索引计数法排序 N个 键为 0 到 R-1 之间的整数元素需要访问数组 11N + 4R + 1次,突破了 NlogN 的排序算法运行时间下限,只要当 R 和 N 的一个常数因子范围之内,它都是一个线性时间级别的排序算法。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值