排序---计数排序(稳定)

计数排序基本思想:

计数排序是一个非基于比较的排序算法。它的优势在于在对一定范围内的整数排序时,快于任何比较排序算法。
当然这是一种牺牲空间换取时间的做法。

  1. 输入的线性表的元素属于有限偏序集S;
    (意思是说,输入的数据必须是一定范围内的数据,比如高考成绩,必须要是0-750)

  2. 计数排序的基本思想是先统计数组中每个整数在数组中出现的次数,然后按照从小到大的循序将每个整数按照它出现的次数填到数组中。比如输入的数组是[2,3,4,2,3,2,1],通过循环可以直到1出现了1次,2出现了3次,3出现了2次,4出现了1次。然后按照先后循序依次在数组中填入1个1,3个2,2个3,1个4,就可以得到排序后的数组[1,2,2,2,3,3,4]。

下图是借鉴的其他博主的GIF

在这里插入图片描述

代码实现:

package count;

public class Count {

	public static int[] CountSort(int arr[]) {
		//新建一个结果集数组,用来存放排序后的数据
		int[] result = new int[arr.length];
		//找到待排序数组的最大值、最小值,因为这样就没必要开辟多余的空间,从而节省空间
		int max = arr[0], min = arr[0];
		for (int i : arr) {
			if (i > max) {
				max = i;
			}
			if (i < min) {
				min = i;
			}
		}
		int k = max - min + 1;
		//开辟的空间是待排序数组中max-min+1,
		//这样就可以尽可能避免开辟多余的空间
		int[] count = new int[k];
		
		//这是统计数组,统计待排序数组中每个数据出现的次数。
		//放到count数组中,减去min是为了让数据从cout[0]位置开始存储。
		for (int i = 0; i < arr.length; i++) {
			count[arr[i] - min]++;
		}
		
		//累加数组,对count数组进行操作,
		//比如数组:[1,0,2,3,2,3,1]
		//统计数组:[1,2,2,2]
		//累加数组:[1,3,5,7]
		for (int i = 1; i < count.length; i++) {
			count[i] = count[i] + count[i - 1];
		}
		
		//逆序遍历,待排序数组
		//按照上边举例数组,i=6,arr[6]为1,arr[6]-0为1,count[1]为3,减去1为2,
		//所以arr[6]为1这个值,最终放的位置是result[2]
		//这个1在待排序数组所有的1中,位置最后
		//在result数组所有1中位置也是最后的,所以这保证了排序的稳定性
		//那如果再遇到下一个1是什么情况呢?
		//当i=0,arr[0]为1,arr[0]-0为1,count[1]为2,(因为刚才执行了依次--count[1]),减去1为1,
		//所以arr[0]为1这个值,最终放的位置是result[1],能够保证排序先后它们的相对位置没有发生变化,所以排序是稳定的
		for (int i = arr.length - 1; i >= 0; i--) {
			result[--count[arr[i]-min]] = arr[i];
		}
		return result;
	}
}

弄一个测试类:

package count;

import java.util.Random;

public class TestCount {
	public static void main(String[] args) {
		Random random = new Random();
		int[] arr = new int[1000];
		for (int i = 0; i < 1000; i++) {
			arr[i] = random.nextInt(10);
		}
		int[] arr1 = Count.CountSort(arr);
		for (int i = 0; i < arr1.length; i++) {
			System.out.println(arr1[i]);
		}
	}
}

复杂度:

数组的长度为n,整数的范围为k
时间复杂度为:O(n+k)
创建了一个长度为k的辅助数组count
空间复杂度为:O(k)

当k比较小时,无论从时间复杂度和空间复杂度来说,计数排序都是非常高效的算法,
当k比较大时,计数排序就没有其他算法高效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值