基数排序
啥也不说了,看代码
int maxbits(int* arr,int n){ //计算arr数组中数的最大位数
int maxn = INT_MIN;
for(int i = 0;i < n;++i){ //找到数组中最大的数
maxn = max(maxn,arr[i]);
}
int res = 0;
while(maxn != 0){
res++;
maxn /= 10;
}
return res;
}
int getDigit(int x, int d) { //从右往左取x的第d位数
return ((x / ((int) pow(10, d - 1))) % 10);
}
void radixprocess(int* arr,int begin,int end,int digit){
const int radix = 10;
int i = 0,j = 0;
//有多少个数准备多少辅助空间
int bucket[end-begin+1];
for(int d = 1;d <= digit;++d){ //有多少位就进出多少次
int count[radix] = {0}; //这个地方一定要给count数组赋初值
for(i = begin;i <= end;++i){
j = getDigit(arr[i],d); //d如果是1就取出个位数字,2就取出十位数字...
count[j]++; //count数组表示0...9这几个位置一共有多少个数
}
for(i = 1;i < radix;++i){ //将count数组装换 成前缀和数组
count[i] = count[i] + count[i-1];
}
for(i = end;i >= begin;--i){
j = getDigit(arr[i],d); // arr[i]的从右往左第d位数为j
bucket[count[j]-1] = arr[i]; //整个arr中从右往左第d位数小于等于j的一共是count[j]个,
count[j]--; // 所以arr[i]放在bucket的count[j]-1位置上 ,同时count[j]--
}
for(i = begin,j = 0;i <= end;++i,++j){ //将bucket中按从右往左第d的位数排好序的数放在arr中
arr[i] = bucket[j]; //准备下次轮按从右往左第d+1的位数进行排序
}
}
}
void radixSort(int* arr,int n){
if(n == 0 || n == 1) return;
radixprocess(arr,0,n-1,maxbits(arr,n));
}
时间复杂度 | 空间复杂度 | 稳定性 | |
选择排序 | 否 | ||
冒泡排序 | 是 | ||
插入排序 | 是 | ||
归并排序 | 是 | ||
随机快排 | 否 | ||
堆排序 | 否 |
补充:
1.随机快排经过验证是是最快的
2.需要稳定性选择归并排序
3.对空间有要求选择堆排序
4.基于比较的排序:
1)时间复杂度不能做到在O(N*logN)以下
2)在时间复杂度最低且空间复杂度低于O(N)的情况下,不能做到稳定
5.常见的坑:
1)归并排序的额外空间复杂度可以变成O(1),但是非常难,不需要掌握,有兴趣可以搜“归并排序内部缓存法”
2)“原地归并排序”的帖子都是垃圾,会让归并排序的时间复杂度变成O(N^2)
3)快速排序可以做到稳定性问题,但是非常难,不需要掌握,可以搜“01stable sort”
4)所有的改进都不重要,因为目前没有找到时间复杂度O(N*logN),额外空间复杂度O(1),又稳定的排序。
5)有一道题目,是奇数放在数组左边,偶数放在数组右边,还要求原始的相对次序不变,碰到这个问题,可以怼面试官。