“这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战”
时间复杂度 O(n) 的排序算法
时间复杂度 O(n)
又叫做,线性排序
下面三个排序算法是,不基于比较的排序算法,不涉及元素之间的比较
对要排序的数据要求很苛刻,需要适用场景
计数排序 VS 桶排序 VS 基数排序
- 计数排序:每个桶只存单一键值(三种排序里面面试问的最多的还是计数排序)
- 桶排序: 每个桶存储一定范围的数值
- 基数排序:根据键值的每位数字来分配桶
计数排序
- 计数排序,不是基于比较的排序算法;
- 核心是将输入的数据值转化为键存储在额外开辟的数组空间中
- 是一种拿空间换时间的算法
- 计数排序只能用在数据范围不大的场景中,如果数据范围K要比排序的数据n大很多,就不适用计数排序了
- 要转化成非负整数
- 时间复杂度:O(n+k)
- 空间复杂度:O(n+k)
原理
- 先查找数组里最大的那个值;
- 根据(最大的值+1)创建新的数组,用于将数据值转化为键存储,下标是[0,...,maxValue]
- 存储:计算每个元素的个数,进行存储,这样就得到,以旧数组的值为下标,相同值的个数为值的新数组
- 这里有个很巧妙的地方,就是bucket这个数组,相当于根据下标值排完序了
- 直接从小到大进行遍历
// n 代表数组的长度
function countSort (arr, n) {
if (arr.length <= 1) return arr;
// 先查找数组里最大的那个值;
let maxValue = arr[0];
for (let i = 1; i < n; i++) {
if (arr[i] >= maxValue) {
maxValue = arr[i];
}
}
// 创建新的数组,用于将数据值转化为键存储
// 下标是[0,...,maxValue]
let bucket = new Array(maxValue + 1);
// 计算每个元素的个数,进行存储
// 这样就得到,以旧数组的值为下标,相同值的个数为值的新数组
for (let i =0; i < n; i++) {
if (!bucket[arr[i]]) {
bucket[arr[i]] = 0;
}
bucket[arr[i]]++;
}
// PS: 这里有个很巧妙的地方,就是bucket这个数组,相当于根据下标值排完序了
// 所以,直接从小到大进行遍历就好了
// 对这个新数组进行遍历
let index = 0;
for (let j = 0; j < maxValue + 1; j++) {
// 当bucket有值的时候,赋给arr
while (bucket[j] > 0) {
arr[index++] = j;
bucket[j]--;
}
}
}
桶排序
Bucket sort,桶排序是计数排序的升级
- 时间复杂度:O(n)
- 空间复杂度:O(n)
原理
将要排序的数据,分到几个有序的桶里,每个桶里的数据再进行单独的排序。
桶内的排序完了,之后,再把每个桶里的数据依次的取出来,组成的序列就是有序的了。
桶排序比较适合用在外部排序之中。就是数据存储在外部磁盘当中,
数据量比较大,内存有限,无法将数据全部加载到内存中
步骤
- 遍历整个数组,找到最小的那个值,和最大的那个值
- 判断多个桶,每个桶有一个范围,
- 遍历数组,把数据放到每个桶里,
- 桶里的数据进行单独排序
- 最后依次取出,就完成桶排序了
基数排序
基数排序对要排序的数据是有要求的,需要分割出独立的位来比较,而且位之间有递进的关系,
如果a数据的高位比b数据大,那么剩下的低位就不用比较了
每一位的数据范围不能太大,要可以用线性排序算法来排序,
否则基数排序的时间复杂度就无法做到O(n)了
- 非比较排序
- 本质上是多关键字排序
- 桶思想的一种
算法思想
假如有一个数组[123,321,432,654],先取每个元素的个位数,进行计数排序,
排完之后,对新数组再继续用十位数排序,最后,给百位数进行计数排序,这样最后就得到排好的数组了
//LSD Radix Sort
var counter = [];
function radixSort(arr, maxDigit) {
var mod = 10;
var dev = 1;
for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for(var j = 0; j < arr.length; j++) {
var bucket = parseInt((arr[j] % mod) / dev);
if(counter[bucket]==null) {
counter[bucket] = [];
}
counter[bucket].push(arr[j]);
}
var pos = 0;
for(var j = 0; j < counter.length; j++) {
var value = null;
if(counter[j]!=null) {
while ((value = counter[j].shift()) != null) {
arr[pos++] = value;
}
}
}
}
return arr;
}