桶排序(Bucket Sort)是一种排序算法,它将待排序的元素分布到一些有序的桶中,然后对每个桶中的元素进行排序,最后将这些桶按顺序合并成一个有序的序列。桶排序适用于待排序元素分布相对均匀的情况
常规的基数排序需要准备N个桶来计数(N为几进制),但还有更优化的办法 本文重点介绍不用桶的算法
计数排序的核心思想是统计每个元素的出现次数,然后根据这些统计信息将元素放回正确的位置。
计数排序适用于一些特殊情况,其中输入数据的范围相对较小,例如整数或有限范围的字符。在这些情况下,计数排序可以在线性时间内完成排序,效率非常高。
void countsort(vector& arr) {
if (arr.empty())
return ;
int min= arr[0],max=arr[0];
for (int i = 1; i < arr.size(); i++) {
max = arr[i] > max ? arr[i] : max;
min = arr[i] < min ? arr[i] : min;
}
int range = max - min + 1;
vectorcountarr(range, 0);
for (int i = 0; i < countarr.size(); i++) {
countarr[arr[i] - min]++;
}
for (int i = 0,index=0; i < range; i++) {
while (countarr[i]--) {
arr[index++] = i + min;
}
}
}
缺点就是对数据状况有很高的要求
传统做法:设置N个桶(栈,队列,或者是数组) 根据个位数导入相应桶 再导出,根据十位数导入桶 再导出。。再依次对百位等高位重复相同的过程,直到最高位。
这种做法在数据范围比较大或位数较多的情况下,需要创建的桶数量可能较多,这可能会影响算法的空间复杂度。
下面重点介绍 优化做法 优雅的创建一个桶
count数组用来记录每数位的数出现次数
count‘是count的前缀和数组 然后再建一个help辅助数组
如图要排序的数组是[021,010,111,022,011,012]
将要排序的数组从右往左遍历
012的出现范围是0-5(查前缀和数组)根据出桶顺序 放到数组第五位置
011放到第三位置。以此类推。这样就能得到一个类似桶的数组 且不用创建很多个桶 。
另外,函数 getdigit
用于获取一个数字在某一位上的数字,如个位、十位等。这个函数帮助我们将数字分配到相应的桶中。
radix是进制数 进制数越大 时间复杂度越低 时间复杂度为nlogradix。
void radixSort(int arr[], int L, int R, int dight) {
const int radix = 10; int i = 0, j = 0;
int* help = new int[R - L + 1];
for (int d = 1; d <= dight; d++) {
int* count = new int[radix];//count[i] 当前位是0-i的数字的个数
for (i = L; i <= R; i++) {
j = getdigit(arr[i], d);
count[j]++;
}
for (int i = 1; i < radix; i++)
count[i] = count[i] + count[i - 1];//求前缀和数组
for (i = R; i >= L; i--) {
j = getdigit(arr[i], d);
help[count[j] - 1] = arr[i];//arr[i]放到j的词频-1的位置
count[j]--;
}
for (i = L, j = 0; i <= R; i++, j++)
arr[i] = help[j];
}
}
int getdigit(int x, int d) {
return ((x / (int)pow(10, d - 1)) % 10);
}
最后将排序完的help拷贝到arr.