- 总结一下,常见时间复杂度为O(n)的排序算法,以及给出js实现
- 非比较排序,比较排序的时间复杂度下界为O(n*logn)
计数排序(Counting sort)
- 适用范围:待排数组arr[N],元素处在某一范围[min,max]
- 核心:假设元素为整数,空间换时间,需要空间大小为O(max-min)的空间,来存储所有元素出现的次数
- 如果元素个数多,但是数值范围较窄时,计数排序是很节省空间的
- 步骤:
- 遍历arr[N],使用计数数组count[max-min],对每个元素进行计数
- 遍历count[],还原arr[N],结束
- 补充:数组index肯定≥0的,待排元素的min不一定为0,需要引入一个offset来修正数值在计数数组count[]中的位置
- 时间复杂度为O(n),更准确的将是O(k+n),k表示输入数组元素范围为[0,k],空间复杂度O(k+n)
1 | function countSort(nums) { |
桶排序(Bucket sort)
- 适用范围:待排数组A[N],元素均匀分布在某一范围[min,max]
- 核心:假设元素是均匀分布的
- 平均时间复杂度为O(n),最坏的情况下所有数据都在一个桶内,其时间复杂度取决于桶内元素自排序的算法
- 即使数据不服从均匀分布,只要输入数据满足下列性质:所有桶的大小的平方与总的元素呈线性关系,桶排依然能在线性时间内完成
- 需要的辅助空间:
- 桶空间B
- 桶内的元素链表空间
- 步骤:
- 遍历A[N],元素A[i],放入对应的桶X
- A[i]放入桶X,如果桶X已有若干元素,一般使用稳定的插入排序,将A[i]放到桶内的合适位置
补充:
- 桶内的元素一直是有序的;
桶的个数设定
1
2
3
4桶排序中桶的设定非常重要,需要制定合理的getBucketIndex算法,使得元素能尽量均匀的放入不同的桶内;
最糟糕,无非所有元素都在一个桶内,时间复杂度就是桶内排序算法时间复杂度
区间划分越细,桶的数量越多,理论上分到每个桶的元素越少,桶内的排序越简单,时间复杂度越接近线性
极端情况下,每个桶内就一个元素,不再需要排序,因为他们都是相同的元素,那桶排序跟计数排序差不多了稳定,时间复杂度O(n)
1 | // 链表元素,用于桶内的元素排序 |