排序算法-计数排序

141 阅读3分钟

计数排序

计数排序不是交换排序,它的核心思想是将数组进行遍历并新建一个新的数组,新数组的索引就是原数组里的元素,索引对应的元素是该元素在原数组出现的次数,最后遍历新数组,根据元素出现的次数打印几次元素。计数排序可以分为基础版本和优化版本,基础版本不是稳定排序(如果有相同元素排序后元素的位置不变),优化后的计数排序是稳定排序。计数排序平均时间复杂度O(n+m) m为最大数与最小数的差值,空间复杂度O(n)。

计数排序有两个很明显的缺点:

  1. 最大值与最小值的差值太大不适用计数排序,差值太大会大大浪费空间,并且随之时间复杂度会升高
  2. 数组元素不是正整数也不适用计数排序,计数排序的核心思想是统计元素出现次数,而元素本身是一个索引

代码实现

基础版

基础版的计数排序并不是稳定排序,排序后相同的元素位置不明确

function countSort(array) {
  // 找到数组最大值
  const max = Math.max(...array);
  // 找到数组最小值
  const min = Math.min(...array);
  // 偏移量
  const offset = max - min;
  // 统计数组
  const countArray = Array(offset + 1).fill(0);
  // 遍历原数组并做统计
  for(let i = 0; i < array.length; i++){
      countArray[array[i] - min] += 1;
  }
  // 定义排序后的数组
  const sortedArray = [];
  // 排序数组的索引
  let index = 0;
  // 遍历统计数组
  for(let i = 0; i < countArray.length; i++){
     // 根据元素出现的次数遍历
     for(let j = 0; j < countArray[i]; j++){
         sortedArray[index++] = i + min;
     }
  }
  return sortedArray;
}

const array = [95,94,91,98,99,90,99,93,91,92];

console.log(countSort(array));

优化版

由于基础版的计数排序不是稳定排序,排序后相同元素位置不明确,所以需要优化一下。具体优化方案是: 统计数组不再是统计元素出现的次数,而是从第二个元素开始,每一个元素都加上前面所有元素之和。然后倒序遍历原始数组,每遍历一次,统计数组元素值就会减一。这样一来相同元素的也会出现在正确的位置上。

function countSort(array) {
  // 找到数组最大值
  const max = Math.max(...array);
  // 找到数组最小值
  const min = Math.min(...array);
  // 偏移量
  const offset = max - min;
  // 统计数组
  const countArray = Array(offset + 1).fill(0);
  // 遍历原数组并做统计
  for(let i = 0; i < array.length; i++){
      countArray[array[i] - min] += 1;
  }
  // 优化 countArray 元素是之前元素的总和
  let sum = 0;
   for(let i = 0; i < countArray.length; i++){
      sum += countArray[i];
      countArray[i] = sum;
  }
  
  // 定义排序后的数组
  const sortedArray = Array(array.length).fill(0);
  
  // 优化  倒序遍历原始数组,从统计数组找到正确位置,输出到结果数组
  for(let i = array.length - 1 ; i >=0; i--){
    // 统计数组的元素值其实就是该元素在排序数组的位置 
    sortedArray[countArray[array[i] - min] - 1] = array[i];
    // 将统计数组元素值 减一,下次遇到同样的元素位置才会正确
    countArray[array[i] - min]--;
  }
  return sortedArray;
}

const array = [95,94,91,98,99,90,99,93,91,92];

console.log(countSort(array));

参考

归并排序