数据结构与算法-排序算法(计数排序)

这其实是一个"投机取巧"地方法,应用的范围不是那么宽,还没有涉及到更深的思想,所以就放在前面来讲。

我们的排序问题实际上就是大的跟小的按照顺序输出。

排序的结果很显然是

1235677

思考这样一个问题,我们输出的实际上就是数字的大小和数目。

我们事先可以维护一个已经排序好的数字,然后根据遍历数组,按照数字的个数输出,不就是排好序的了吗

我们遍历数组,开始统计

7   

直到我们统计完所有的数字,这个数组就变为

根据记录的数目,输出对应次数的序号

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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值