2020-11-25 排序算法三(计数排序和桶排序)

2020-11-26  本文已影响0人  宇宙区长李小无

计数排序

计数排序非常容易理解,相信等我介绍完概念,大家都可以写出来。

通过数组下标来记录数列中各数的,通过下标对应的值来记录相同数出现的频率。打个比方,一个长度为10的数组,下标为0-9,如果我们要排序的数列为0-9之间的随机数,如list = [0, 0, 8, 3, 4, 2, 7, 7, 7, 5],要将其从小到大排列:

是不是很简单呢,代码如下:
需要注意,一开始我们是不确定数列的最大值的,所以我们要先找到数列中的最大值max,并将sortArray的长度设为max + 1,保证最大值可以找到其对应的下标

function countSort(list: number[]): number[] {
  let max = 0;
  for (let i = 0; i < list.length; i++) {
    if (list[i] > max) {
      max = list[i];
    }
  }
  const sortArray: number[] = new Array(max+1);
  list.forEach(item => {
    if (sortArray[item] === undefined) {
      sortArray[item] = 0;
    }
    sortArray[item]++;
  });
  const res = [];
  sortArray.forEach((sort, index) => {
    if (sort > 0) {
      for (let i = 0; i < sort; i++) {
        res.push(index);
      }
    }
  });
  return res;
}

这样是可以实现了排序,但是还可以进行优化,如果我们要排列的数组为[99, 98, 97, 93, 95]呢?最大值为99,所以我们建了一个长度为100的数组,而实际只利用了下标为93-99这一段空间。所以我们可以建立一个长度为max - min + 1的数组,来进行计数。最后统计的时候每个元素都加上最小值min即可。

function countSort(list: number[]): number[] {
  let max = 0;
  let min = 0;
  for (let i = 0; i < list.length; i++) {
    if (list[i] > max) {
      max = list[i];
    }
    if (list[i] < min) {
      min = list[i];
    }
  }
  const sortArray: number[] = new Array(max - min + 1);
  list.forEach(item => {
    const index = item - min;
    if (sortArray[index] === undefined) {
      sortArray[index] = 0;
    }
    sortArray[index]++;
  });
  const res = [];
  sortArray.forEach((sort, index) => {
    if (sort > 0) {
      for (let i = 0; i < sort; i++) {
        res.push(index + min);
      }
    }
  });
  return res;
}

上述方法只是记录了某个数出现的频率,并没有真正将输入的数列排列成有序的,造成了我们容易分不清相同大小的值谁在前谁在后。

改进

function countSort(list: number[]): number[] {
  let max = 0;
  let min = 0;
  for (let i = 0; i < list.length; i++) {
    if (list[i] > max) {
      max = list[i];
    }
    if (list[i] < min) {
      min = list[i];
    }
  }
  const sortArray: number[] = new Array(max - min + 1);
  list.forEach(item => {
    const index = item - min;
    if (sortArray[index] === undefined) {
      sortArray[index] = 0;
    }
    sortArray[index]++;
  });
  for (let i = 1; i < sortArray.length; i++) {
    // 排名递增
    if (sortArray[i] === undefined) {
      sortArray[i] = 0;
    }
    sortArray[i] += sortArray[i - 1];
  }
  const res = new Array(list.length);
  list.forEach(value => {
    const realIndex = value - min;
    res[sortArray[realIndex] - 1] = value;
    sortArray[realIndex]--;
  });
  return res;
}
总结

桶排序

基本思想就是:

function sortByBucket(list: number[]) {
  let max = list[0];
  let min = list[0];
  for (let i = 1; i < list.length; i++) {
    if (list[i] > max) {
      max = list[i];
    }
    if (list[i] < min) {
      min = list[i];
    }
  }
  const dValue = max - min;
  // 确定桶的存值区间
  const partValue = dValue / (list.length - 1);
  // 建桶
  const bucket: number[][] = [];
  for (let i = 0; i < list.length; i++) {
    bucket.push([]);
  }
  // 插值
  for (let i = 0; i < list.length; i++) {
    const index = Math.floor((list[i] - min) / partValue);
    bucket[index].push(list[i]);
    // 内部排序
    for (let i = bucket.length - 1; i > 1; i--) {
      const singleBucket = bucket[index];
      if (singleBucket[i - 1] > singleBucket[i]) {
        singleBucket[i - 1] = singleBucket[i] ^ singleBucket[i - 1];
        singleBucket[i] = singleBucket[i] ^ singleBucket[i - 1];
        singleBucket[i - 1] = singleBucket[i] ^ singleBucket[i - 1];
      }
    }
    console.log(bucket)
  }
  // 输出
  const res = [];
  for (let i = 0; i < bucket.length; i++) {
    res.push(...bucket[i]);
  }
  return res;
}

总结

image.png
上一篇下一篇

猜你喜欢

热点阅读