排序算法(四):计数排序

概念
以数组元素值为键,出现次数为值存进一个临时数组,最后再遍历这个临时数组还原回原数组。因为 JavaScript的数组下标是以字符串形式存储的,所以计数排序可以用来排列负数,但不可以排列小数。
复杂度
最好:O(n + k),k是最大值和最小值的差。
最坏:O(n + k)
平均:O(n + k)

分类

常规计数排序
代码

 function counting_sort(nums) {
  let arr = []
  let leg = nums.length;
  let max = Math.max(...nums)
  let min = Math.min(...nums)

  for (let i = 0; i < leg; i++) {
    let temp = nums[i]
    arr[temp] = arr[temp] + 1 || 1
  }
  
  let index = 0
  for (let i = min; i < max; i++) {
    while (arr[i] > 0) {
      nums[index++] = i
      arr[i]--
    }
  }
}

var sortArr = [9, 6, 3, 5, 2, 1, 7, 343, 6, 643, 243, 544, 5, 63, 234, 0, 56, 123]
counting_sort(sortArr)
console.log(sortArr)
// [0, 1, 2, 3, 5, 5, 6, 6, 7, 9, 56, 63, 123, 234, 243, 343, 544, 123]

缺点

在这里插入图片描述

优化计数排序

把每一个数组元素都加上 min 的相反数,来避免特殊情况下的空间浪费,通过这种优化可以把所开的空间大小从 max+1 降低为 max-min+1,max 和 min 分别为数组中的最大值和最小值。

比如数组 [103, 102, 101, 100],普通的计数排序需要开一个长度为 104 的数组,而且前面 100 个值都是 undefined,使用该优化方法后可以只开一个长度为 4 的数组。

    function counting_sort(nums) {
      let arr = []
      let leg = nums.length;
      let max = Math.max(...nums)
      let min = Math.min(...nums)

      let mark = 0
      let add = -min
      // 加上最小值的相反数来缩小数组范围
      for (let i = 0, len = nums.length; i < len; i++) {
        mark += 1
        let temp = nums[i];
        temp += add;
        arr[temp] = arr[temp] + 1 || 1;
      }
      console.log(arr)
      let index = 0
      for (let i = min; i <= max; i++) {
        let temp = arr[i + add];
        mark += 1
        while (temp > 0) {
          mark += 1
          nums[index++] = i;
          temp--;
        }
      }
      console.log(mark)
    }
    var sortArr = [9, 6, 3, 5, 2, 1, 7, 343, 6, 643, 243, 544, 5, 63, 234, 0, 56, 123, 9999]
    counting_sort(sortArr)
    console.log(sortArr)
    // 10038
    // [0, 1, 2, 3, 5, 5, 6, 6, 7, 9, 56, 63, 123, 234, 243, 343, 544, 643, 9999]
使用感受

就计数排序而言,最好数的最大最小差异不是很大,如果比较值本身差异很大,创建的数据空间就会越大,遍历数也会变多, 而且这个优化的计数排序如果数是正负都有的 那个 空间大小从 max+1 降低为 max-min+1 这个就会变成相加的,反而会让性能变差,而且这种优化感觉没什么大的用处

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基数排序(Radix Sort)是一种非比较排序算法,它根据元素的大小,将元素分配到不同的桶中进行排序计数排序(Counting Sort)是一种稳定的排序算法,它利用桶的思想,对每个元素出现的次数进行统计,再根据桶的顺序依次输出排序结果。 基数排序可以使用计数排序作为其内部排序算法,具体实现步骤如下: 1. 找到最大数,并确定其位数 2. 对所有数按照个位数进行排序,利用计数排序 3. 对所有数按照十位数进行排序,利用计数排序 4. 重复步骤 3,直到所有位数都排完序 下面是使用 C++ 实现基数排序的代码: ```cpp #include <iostream> #include <vector> using namespace std; void countingSort(vector<int>& arr, int exp) { vector<int> count(10, 0); vector<int> output(arr.size()); // 统计每个数位上出现的数字的个数 for (int i = 0; i < arr.size(); i++) { int digit = (arr[i] / exp) % 10; count[digit]++; } // 计算每个数字在输出数组中的位置 for (int i = 1; i < count.size(); i++) { count[i] += count[i - 1]; } // 将元素从输入数组复制到输出数组中,保证稳定性 for (int i = arr.size() - 1; i >= 0; i--) { int digit = (arr[i] / exp) % 10; output[count[digit] - 1] = arr[i]; count[digit]--; } // 将排序好的数组赋值给原数组 for (int i = 0; i < arr.size(); i++) { arr[i] = output[i]; } } void radixSort(vector<int>& arr) { int max_num = *max_element(arr.begin(), arr.end()); // 从个位开始,依次对每个数位进行排序 for (int exp = 1; max_num / exp > 0; exp *= 10) { countingSort(arr, exp); } } int main() { vector<int> arr = { 170, 45, 75, 90, 802, 24, 2, 66 }; radixSort(arr); for (auto num : arr) { cout << num << " "; } return 0; } ``` 输出结果为:2 24 45 66 75 90 170 802

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值