排序算法(5)-线性时间排序
算法导论有证明,基于比较的排序(插入,选择,归并,快速,堆排序)的渐进时间复杂度下限为O(lg(n))。因此,这里提到的线性时间排序,必然不是基于比较的排序。本质上讲,个人认为这些线性时间排序就是用空间换取时间。
计数排序,a,b均为长度为n的数组,a为输入,b为排序好的数组,要求是a的元素必须都为小于k的非负数,计数排序直接将值作为c数组的寻址
1 void counting_sort(int a[], int b[], int n, int k) 2 { 3 int* c = new int[k]; 4 5 for (int i = 0; i < k; ++i) 6 c[i] = 0; 7 for (int i = 0; i < n; ++i) 8 ++c[a[i]]; 9 for (int i = 1; i < k; ++i) 10 c[i] += c[i - 1]; 11 for (int i = n - 1; i >= 0; --i) 12 { 13 b[c[a[i]] - 1] = a[i]; 14 --c[a[i]]; 15 } 16 17 delete[] c; 18 }
基排序,最直观的理解是,当所有数的位数都小于d时,我们可以从最低位开始排序,直到最高位,类似于n个百位数,我们先比较个位,再比较十位,再比较百位,就可以完成排序了
void radix_sort(int a[], int n, int d) { for (int i = 0; i < d; ++i) // sort array a on digit i by some stable sort method. }
对于某个位的数字来说,必然小于k(十进制下,小于9),那么我们就可以用计数排序在O(n+k)内完成排序,整个排序在O(d(n+k))内完成。
很显然,计数排序,基排序都只能对非负整数进行排序,对浮点数则无效。桶排序则没有这个限制。桶排序假定数字都在[0,1)区间内,且数组a分布均匀,那么我们可以设置n个小桶将[0,1)区间划分,n*a[i]的整数值就可以得到a[i]所属于的桶,然后对每个桶里面的少量元素排序,最后将所有桶区间的结果按照顺序合并起来,就可以得到排序结果。这里就不放置代码了,放置一个原理图可能更能说明问题: