计数排序

计数排序

计数排序不是一个比较排序算法,时间复杂度为O(N),这是一种以空间换时间的算法。计数排序要求
输入的元素必须限制在一定范围内如学生数学成绩(0 - 100 分)

原理:
通过以元素值为索引下标,将元素写入统计的数组,然后遍历统计数组,顺次将统计数组中的数据取出,
放入结果数组。

例子如下:
七个同学的物理成绩如下:{ 108, 100, 105, 110, 105, 105, 100 }

物理成绩区间:[0, 120]
开辟一个 120 - 0 + 1 = 121 个空间的数组 int[] countArr = new int[121]

遍历所有同学的成绩,按照分数为索引,每出现一次,将索引指向的数据值 +1.
则统计结果为

countArr[100] = 2
countArr[105] = 3
countArr[108] = 1
countArr[110] = 1

则可看出 得到 100 分的同学数为 2人, 得到 105 分的同学数量为 3人等等

然后遍历 countArr 数组中值 > 0 的( > 0 则说明得到该分数的同学数至少为1人),

新建一个结果数组 int[] resultArr = new int[7];// 总共七个同学
将countArr[i] > 0 的索引,顺序写入 resultArr[ resultIndex++ ] 中

结果:
resultArr[0] = 100
resultArr[1] = 100
resultArr[2] = 105
resultArr[3] = 105
resultArr[4] = 105
resultArr[5] = 108
resultArr[6] = 110

从上边例子可以看出 countArr 存在严重的空间浪费,因为 成绩最大/最小分别为 max = 110 和 min = 100
然而却开辟了一个 121 个空间的数组,通过改进我们知道最多只需要 max - min + 1 = 11 个空间的数组。
然而空间优化后形如countArr[105] = 3 则会出现数组越界
解决方案 转换为 countArr[105 - min] = countArr[5] = 3
同理当写入 resultArr时也需要反转回原数据

countArr[index] = countArr[5],   
result =  index + min  = 105

实例图如下
在这里插入图片描述
在这里插入图片描述

将数据从 countArr 写入 resultArr
在这里插入图片描述
代码:

   void Sort()
    {
        int[] arr = new int[] { 108, 100, 105, 110, 105, 105, 100 };
        arr = CountSort(arr);
    }
    
    public int[] CountSort(int[] arr)
    {
        int max = arr[0];
        int min = arr[0];
        // 获取数组中最大和最小的值
        for (int i = 0; i < arr.Length; ++i)
        {
            if (arr[i] > max)
            {
                max = arr[i];
            }
            if (arr[i] < min)
            {
                min = arr[i];
            }
        }

        // 实例数组 { 108, 100, 105, 110, 105, 105, 100 }
        // 以 最大值(110) - 最小值(100) = 10 的区间数作为 统计数组的长度
        int length = max - min + 1;
        int[] countArr = new int[length];
        for (int i = 0; i < arr.Length; ++i)
        {
            // arr[i] 和 min = 100 的插值作为 统计数组的 索引下标
            // 如 105 - 100 = 5 作为索引下标
            // 标记一:
            int index = arr[i] - min;
            countArr[index]++;
        }

        // 结果数组的长度取原数组 arr.Length
        int[] resultArr = new int[arr.Length];
        int resultIndex = 0;
        for (int i = 0; i < countArr.Length; ++i)
        {
            // 遍历统计数组,只要是数值大于 0 的都添加进 结果数组
            while (countArr[i] > 0)
            {
                // i 为索引 = arr[下标] - min,如不理解找上边代码注释 //标记一: 
                // 所以此处 i + min 即转换为 arr[下标] 原数据的值
                resultArr[resultIndex] = i + min;
                countArr[i]--;
                resultIndex++;
            }
        }

        return resultArr;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值