这其实是一个"投机取巧"地方法,应用的范围不是那么宽,还没有涉及到更深的思想,所以就放在前面来讲。
我们的排序问题实际上就是大的跟小的按照顺序输出。
排序的结果很显然是
1235677
思考这样一个问题,我们输出的实际上就是数字的大小和数目。
我们事先可以维护一个已经排序好的数字,然后根据遍历数组,按照数字的个数输出,不就是排好序的了吗
我们遍历数组,开始统计
7
1
直到我们统计完所有的数字,这个数组就变为
根据记录的数目,输出对应次数的序号
0->0次 1->1次 2->1次 3->1 5->1 6->1 7->2
得到结果1235677 (排序成功)
那么他的原理是什么,我们前面介绍的冒泡和选择排序都是一个元素一个元素的定位。
而该方法的原理就是先排好序,再统计元素数目,由于序号已经是有序的了,所以输出的就是排好序的数组
实际代码:(实际例子就使用java写了,比较通用的写法,其他程序也差不多,推荐的在线网站https://tool.lu/coderunner/)
public class HelloWorld {
public static void main(String []args) {
int[] c=new int[]{7,1,2,6,3,7,5};
int max=0;
for(int i=0;i<c.length;i++) //获取最大值 申请特定大小的数组用于计数
{
if(c[i]>max)
{
max=c[i];
}
}
int[] order = new int[max+1];
for(int i =0;i<c.length;i++) //计数统计
{
order[c[i]]++;
}
int index=0;
int[] sorted = new int[c.length];
for(int i=0;i<order.length;i++) //将统计得到的结果输出到数组
{
for(int j=0;j<order[i];j++)
{
sorted[index]=i; //根据统计的数目输出对应个数次元素
index++;
}
}
for(int a:sorted)
System.out.println(a);
//System.out.println(Arrays.toString(sorted));
}
}
有人可能发现了,我们需要申请的数组大小需要是最大值+1,这样才可以用序号统计元素的个数,这确实是该方法的缺点,如果元素囊括的范围很大,那么将会申请过大的无用空间。但是如果仅仅数字大而范围不大,那么还是没有问题的,我们可以使用单独的变量记录基数,输出的时候在加回来就可以了,例如我们的数组变为
{107,101,102,106,103,107,105};
public class HelloWorld {
public static void main(String []args) {
int[] c=new int[]{107,101,102,106,103,107,105};
int max=0;
int base=c[0]; //随机抽选一个作为基底
for(int i=0;i<c.length;i++) //获取最大值 和 最小值
{
if(c[i]>max)
{
max=c[i];
}
if(c[i]<base)
{
base=c[i];
}
}
int[] order = new int[max-base+1]; //申请元素范围大小的数组
for(int i =0;i<c.length;i++) //计数统计
{
order[c[i]-base]++; //所有的元素减去基底 再统计
}
int index=0;
int[] sorted = new int[c.length];
for(int i=0;i<order.length;i++) //将统计得到的结果输出到数组
{
for(int j=0;j<order[i];j++)
{
sorted[index]=base+i; //根据统计的数目输出对应个数次元素 恢复原大小
index++;
}
}
for(int a:sorted)
System.out.println(a);
//System.out.println(Arrays.toString(sorted));
}
}
那我们来审视一下该算法的一些性能。
时间复杂度:我们的核心均是单层遍历,并没有嵌套的循环,遍历的次数为n次 n+1次,总结来说复杂度为O(n)
空间复杂度:我们申请了max+1大小的空间用来统计这n个数(k为n中的元素范围值),然后又申请了大小同等为n的临时数组保存输出结果,总的来说空间复杂度为O(n).
稳定性:在实际的运用中,统计的时候就是从头到尾遍历,记录的时候各元素的相对顺序的不会发生变化的,所以是稳定排序。
这是一个比较明显的用空间换时间的例子,比较冒泡排序和选择排序的O(n^2)的时间复杂度,该算法仅为O(n);
而空间复杂度,冒泡排序和选择排序均为O(1),而该算法为O(n);