桶排序算法详解及应用实例
创作时间:
作者:
@小白创作中心
桶排序算法详解及应用实例
引用
CSDN
1.
https://blog.csdn.net/qq_67693066/article/details/139455262
什么是桶排序
桶排序(Bucket Sort)是一种分布式排序算法,它将待排序的数组分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序的工作原理如下:
初始化:首先确定桶的数量和大小,理想情况下桶的数量与待排序数组中的最大值和最小值的范围相关,且各个桶之间是互斥的。例如,如果数组中的元素范围是0到100,可以创建100个桶,每个桶负责收集一个数值范围内的元素。
分配:遍历原始数组,将每个元素放入对应的桶中。这个过程通常是通过计算元素值与桶区间的关系来决定元素应归属的桶。例如,如果数组元素是0到1之间的浮点数,可以将它们乘以桶的数量然后取整,以此作为桶的索引来分配元素。
桶内排序:对于每个非空的桶,单独对桶内的元素进行排序。这一步可以使用任何有效的排序算法,比如插入排序、快速排序等。如果桶内元素数量很少,插入排序往往是一个不错的选择。
收集:按顺序遍历所有的桶,将桶中的元素依次取出并合并成一个有序数组。这一步是线性的,只需将各桶的元素依次连接起来即可。
桶排序的优点是,当输入数据均匀分布在桶中时,排序效率非常高,时间复杂度接近O(n),其中n是数组长度。然而,如果数据分布极不均匀,桶排序的效率会大大降低,最坏情况下的时间复杂度接近O(n^2),特别是当所有元素都落在同一个桶中时。
桶排序适用于数据范围明确且分布较为均匀的情况,比如在处理大量浮点数排序时,若这些浮点数的分布已知且较为集中,桶排序可以发挥很好的效果。
桶排序的代码实现
我们先来看一个版本的实现:
void buckets_sort(int score[], int size) {
// 选取最大的数据作为新数组的大小
int max = score[0];
for (int i = 0; i < size; i++) {
if (score[i] > max) {
max = score[i];
}
}
// 开辟数组,并初始化所有对应下标储存元素为0
std::vector<int> newArray(max + 1, 0);
for (int j = 0; j < size; j++) {
newArray[score[j]]++;
}
// 遍历数组
for(int i = 0; i <= max; i++) {
// 对应元素的打印次数
for (int j = 0; j < newArray[i]; j++) {
std::cout << i << " ";
}
}
}
int main() {
int a1[] = { 92,84,99,81,77,100,102,113,100 };
buckets_sort(a1, sizeof(a1)/sizeof(a1[0]));
}
接下来是另一个版本的实现,这个版本中每个位置都是一个桶,而不是标记次数:
void buckets_sort(std::vector<int>& array) {
// 首先寻找数组中的最大元素,以确定桶的数量
int Max = array[0];
for(int i = 1; i < array.size(); i++) {
if(array[i] > Max) {
Max = array[i]; // 更新最大值
}
}
// 根据最大值开辟空间,创建相应数量的桶,注意索引从0开始,所以桶的大小为Max + 1
std::vector<std::vector<int>> buckets;
buckets.resize(Max + 1);
// 遍历原数组,将每个元素放入对应的桶中,元素值即为其所在桶的索引
for(auto num : array) {
buckets[num].push_back(num); // 将num放入其值对应的桶内
}
// 对每个桶内的元素进行排序,这里使用了std::sort,实际可以根据情况选择不同的排序算法
for (auto& bucket : buckets) {
std::sort(bucket.begin(), bucket.end()); // 对桶内元素进行排序
}
// 收集排序后的元素回到原数组
int index = 0;
for(auto& bucket : buckets) {
for(auto number : bucket) {
array[index++] = number; // 依次将排序后的元素放回原数组
}
}
}
int main() {
std::vector<int> a2 = { 77,92,84,99,81,77,100,102,113,100 };
buckets_sort(a2);
for(auto e : a2) {
std::cout << e << " ";
}
}
这个方法有点像哈希表的拉链法,只不过我们对桶的内部进行了排序。
桶排序的应用案例
字符串中的第一个唯一字符
这道题非常适合用桶排序来解决:
class Solution {
public:
int firstUniqChar(std::string s) {
int arrayA[26]={0};
for(int i = 0;i<s.size();i++) {
arrayA[s[i]-'a']++;
}
for(int i = 0;i<s.size();i++) {
if(arrayA[s[i]-'a']==1) {
return i;
}
}
return -1;
}
};
数组的相对排序
这道题也可以使用桶排序来解决:
class Solution {
public:
std::vector<int> relativeSortArray(std::vector<int>& arr1, std::vector<int>& arr2) {
// 寻找最大数
int max = 0;
for(int i = 0;i < arr1.size(); i++) {
max = std::fmax(max,arr1[i]);
}
// 开辟第一个数组
std::vector<int> Array1(max + 1);
for(auto number : arr1) {
Array1[number]++;
}
// 开辟第二个数组
std::vector<int> Array2(arr1.size());
int x = 0;
for(auto index : arr2) {
while(Array1[index]!=0) {
Array2[x++] = index;
Array1[index]--;
}
}
// 没出现在arr2中元素,需要再次遍历一遍,放在数组最后面
for(int i = 0; i < max + 1; i++) {
for(int j = 0; j< Array1[i]; j++) {
Array2[x++] = i;
}
}
return Array2;
}
};
热门推荐
中航资本:市盈率静和动分别是什么意思?市盈率静和动看哪个准?
英语:解析 “Coworkers” 和 “Colleagues” 的区别
道教神仙体系:三清、四御、五老、六司、七元、八极、九曜、十都
80后,90后,00后,谁是最艰难的一代人?
如何精准获取和分析海关进出口数据,指导企业出口决策?
梅州开通C5驾驶证考试,为残障人士圆驾车梦
常泰长江大桥:世界最大跨度公铁两用斜拉桥,助力常州打造“长三角中轴枢纽城市”
高效、精准、安全:医院药械部门自动化物流系统解析
揭秘大清帝国:从盛世辉煌到覆灭之路
全国首例MCN公司诉“中之人”违约合同案!虚拟主播行业如何破解“合规”难题?
探秘娲皇宫,古老神话的现代演绎
射频滤波器:未来通信技术的“隐形英雄”
最小的自然数是多少(最小的偶数是0还是2权威解释)
如何选购最适合您的光纤HDMI线材
Excel中检查名字是否重名的三种方法
你是什么样的人,就拥有什么样的爱情
教育大模型智能体的开发、应用现状与未来展望
如何了解闯红灯的判定标准?这种了解对遵守交通法规有何帮助?
学校烘焙课程教育计划,培养烘焙技艺与创意融合的综合型人才
面对职场竞争如何保持个人价值
开关电源重点可靠性测试项目与测试方法
评析《美国队长4》能否抗住票房和口碑双重考验
荒垣真次郎人物实战解析
宇字起名寓意是什么
电动汽车为何难以带来快感,事故率又为何会高于燃油车?
中秋烤肉食材清单表:推荐蔬菜肉类、热量排行公开!5原则健康吃
电阻分压电路:【图文讲解】
弱水三千什么意思
高收入人群的税务风险日益增加
如果面容 ID 在你的 iPhone 或 iPad Pro 上无法正常工作