桶排序算法(Java, Python, C/C++ 代码示例
什么是桶排序?
桶排序,通常称为 bin 排序,是一种比较排序方法,它接受未排序数组作为输入,并生成已排序数组作为结果。此方法的工作原理是将元素分配到几个桶中,然后使用任何排序算法(例如插入排序)对每个桶进行单独排序。然后,所有桶合并在一起以形成已排序数组。
当元素为以下情况时,通常使用桶排序:
- 浮点值
- 均匀分布在一定范围内
桶排序的时间复杂度取决于使用的桶数和输入分布的均匀性。虽然不同的排序算法,如 壳排序、归并排序、堆排序和 快速排序 可以达到最佳时间复杂度O(n*logn),而桶排序算法可以以线性时间复杂度或O(n)实现相同的效果。
桶排序遵循分散-聚集方法。应用此方法,元素被分散到相应的桶中,在桶中排序,最后聚集起来形成排序数组。此分散-聚集方法将在下一节中讨论
分散-聚集方法
大规模、复杂的问题有时很难解决。分散-聚集方法试图通过将整个数据集划分为簇来解决此类问题。然后分别处理每个簇,并将所有内容重新组合在一起以获得最终答案。
桶排序算法实现分散-聚集方法的方式如下:
桶排序的工作原理
桶排序的基本工作原理如下:
- 创建一组空的bucket,根据不同的策略,bucket的数量可以不同。
- 从输入数组中,将每个元素放入其对应的存储桶中。
- 对这些存储桶进行单独排序。
- 连接已排序的存储桶以创建单个输出数组。
以下章节提供了详细的工作步骤。
伪代码
Start Create N empty buckets For each array element: Calculate bucket index Put that element into the corresponding bucket For each bucket: Sort elements within each bucket Merge all the elements from each bucket Output the sorted array End
方法 1:浮点数的桶排序算法 Numbers
针对0.0~1.0范围内浮点数的桶排序算法:
步骤1) 创建十 (10) 个空桶,第一个桶包含 [0.0, 0.1) 范围内的数字。第二个桶包含 [0.1, 0.2) 范围内的数字,以此类推。
步骤2) 对于每个数组元素:
-
a. 使用以下公式计算桶索引:
bucket 索引 = no_of_buckets *array_element
-
b. 将元素插入到bucket[bucket_index]中
步骤3) 使用插入排序对每个桶单独进行排序。
步骤4) 将所有存储桶连接成一个数组。
让我们看一个桶排序示例。在此示例中,我们将使用桶排序算法对以下数组进行排序-
步骤1) 首先,我们将创建 10 个空存储桶。第一个存储桶将包含 [0.0, 0.1) 之间的数字。然后第二个存储桶将包含 [0.1, 0.2) 之间的数字,依此类推。
步骤2) 对于每个数组元素,我们将计算存储桶索引并将元素放入该存储桶中。
桶指数可使用以下公式计算:
bucket_index=存储桶数量*数组元素
桶索引计算:
一)0.78
bucket_index = 存储桶数量 * 数组元素
= 10 0.78 *
= 7.8
因此,元素 0.78 将存储在 bucket[floor(7.8)] 或 bucket[7] 中。
二)0.17处
bucket_index = no_of_buckets * 数组元素
= 10 0.17 *
= 1.7
数组元素 0.17 将存储在 bucket[floor(1.7)] 或 bucket[1] 中。
C)0.39
bucket_index = no_of_buckets * 数组元素
= 10 * 0.39
= 3.9
0.39 将存储在 bucket[floor(3.9)] 或 bucket[3] 中。
迭代完所有数组元素后,存储桶将如下所示:
步骤3) 然后,使用插入排序对每个桶进行排序。排序操作后,输出为:
步骤4) 在最后一步中,这些桶将被连接成一个数组。该数组将是输入的排序结果。
每个 bucket 将被连接到输出数组。例如,第二个 bucket 元素的连接:
最后一个 bucket 元素的连接如下:
连接后,得到的数组将是所需的排序数组。
C/ 中的桶排序程序C++
输入:
//Bucket Sort Program in C/C++ //For not having integer parts #include <bits/stdc++.h> #define BUCKET_SIZE 10 using namespace std; void bucketSort(float input[], int array_size) { vector <float>bucket[BUCKET_SIZE]; for (int i = 0; i < array_size; i++) { int index = BUCKET_SIZE*input[i]; bucket[index].push_back(input[i]); } for (int i = 0; i < BUCKET_SIZE; i++) sort(bucket[i].begin(), bucket[i].end()); int out_index = 0; for (int i = 0; i < BUCKET_SIZE; i++) for (int j = 0; j < bucket[i].size(); j++) input[out_index++] = bucket[i][j]; } int main() { float input[]={0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.69}; int array_size = sizeof(input)/sizeof(input[0]); bucketSort(input, array_size); cout <<"Sorted Output: \n"; for (int i = 0; i< array_size; i++) cout<<input[i]<<" "; return 0; }
输出:
Sorted Output: 0.12 0.17 0.21 0.23 0.26 0.39 0.69 0.72 0.78 0.94
桶排序程序 Python
输入:
# Bucket Sort Program in Python # For not having integer parts def bucketSort(input): output = [] bucket_size = 10 for bucket in range(bucket_size): output.append([]) for element in input: index = int(bucket_size * element) output[index].append(element) for bucket in range(bucket_size): output[bucket] = sorted(output[bucket]) out_index = 0 for bucket in range(bucket_size): for element in range(len(output[bucket])): input[out_index] = output[bucket][element] out_index += 1 return input input = [0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12, 0.23, 0.69] print("Sorted Output:") print(bucketSort(input))
输出:
Sorted Output: [0.12, 0.17, 0.21, 0.23, 0.26, 0.39, 0.69, 0.72, 0.78, 0.94]
桶排序 Java
输入:
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class BucketSort { private static final int BUCKET_SIZE = 10; public static void bucketSort(float[] input, int arraySize) { List < Float > [] bucket = new ArrayList[BUCKET_SIZE]; for (int i = 0; i < arraySize; i++) { int index = (int)(BUCKET_SIZE * input[i]); if (bucket[index] == null) { bucket[index] = new ArrayList < > (); } bucket[index].add(input[i]); } for (int i = 0; i < BUCKET_SIZE; i++) { if (bucket[i] != null) { Collections.sort(bucket[i]); } } int outIndex = 0; for (int i = 0; i < BUCKET_SIZE; i++) { if (bucket[i] != null) { for (float value: bucket[i]) { input[outIndex++] = value; } } } } public static void main(String[] args) { float[] input = {0.78f,0.17f,0.39f,0.26f,0.72f,0.94f,0.21f,0.12f,0.23f,0.69f}; int arraySize = input.length; bucketSort(input, arraySize); System.out.println("Sorted Output:"); for (int i = 0; i < arraySize; i++) { System.out.print(input[i]+" "); } } }
输出:
Sorted Output: 0.12 0.17 0.21 0.23 0.26 0.39 0.69 0.72 0.78 0.94
方法 2:整数元素的桶排序算法
对于包含超出范围 [0.0, 1.0] 的数字的输入,桶排序算法与之前的算法略有不同 算法。本案所需步骤如下:
步骤1) 找出最大和最小元素。
步骤2) 选择桶的数量 n,并将这些桶初始化为空。
步骤3) 使用以下公式计算每个桶的范围或跨度:
span = (maximum - minimum)/n
步骤4) 对于每个数组元素:
-
1.计算桶索引:
bucket_index = (element - minimum)/span
-
2.将元素插入到bucket[bucket_index]中
步骤5) 使用插入排序对每个桶进行排序。
步骤6) 将所有存储桶连接成一个数组。
让我们看一个桶排序算法的例子。在这个例子中,我们将使用桶排序算法对以下数组进行排序-
步骤1) 第一步,需要找到给定数组的最大和最小元素。对于此示例,最大值为 24,最小值是 1。
步骤2) 现在,我们必须选择一定数量的空桶,n。在此示例中,我们将取 5 个桶。然后我们将它们初始化为空。
步骤3) 每个桶的跨度需要按照以下公式计算:
span = (maximum-minimum)/n = (24-1)/5 = 4
;
因此,第一个存储桶将包含 [0, 5) 范围内的数字。第二个存储桶将包含 [5, 10) 范围内的数字,依此类推。
步骤4) 对于每个数组元素,我们将计算存储桶索引并将元素放入该存储桶中。存储桶索引可以使用以下公式计算:
bucket_index = (element - minimum)/span
桶索引计算:
-
a)11bucket_index = (元素 - 最小值)/跨度
=(11-1)/4
=2
因此,元素 11 将存储在 bucket[2] 中。
-
二)9处
bucket_index = (元素 - 最小值)/跨度
=(9-1)/4
=2
请注意: 由于 9 是 bucket[1] 的边界元素,因此需要将其附加到 bucket[1] 中,而不是附加到前一个元素的同一个 bucket 中。
对每个元素执行完操作后,存储桶将如下所示:
步骤5) 现在,每个桶将使用插入排序进行排序。排序后的桶-
步骤6) 在最后一步中,这些桶将被连接成一个数组。 排列 将是输入的排序结果。
C/ 中的桶排序程序C++
输入:
#include<bits/stdc++.h> using namespace std; void bucketSort(vector < double > & input, int No_Of_Buckets) { double max_value = * max_element(input.begin(), input.end()); double min_value = * min_element(input.begin(), input.end()); double span = (max_value - min_value) / No_Of_Buckets; vector<vector <double>> output; for (int i = 0; i < No_Of_Buckets; i++) output.push_back(vector <double> ()); for (int i = 0; i < input.size(); i++) { double difference = (input[i] - min_value) / span - int((input[i] - min_value) / span); if (difference == 0 && input[i] != min_value) output[int((input[i] - min_value) / span) - 1] .push_back(input[i]); else output[int((input[i] - min_value) / span)].push_back( input[i]); } for (int i = 0; i < output.size(); i++) { if (!output[i].empty()) sort(output[i].begin(), output[i].end()); } int index = 0; for (vector <double> & bucket: output) { if (!bucket.empty()) { for (double i: bucket) { input[index] = i; index++; } } } } int main() { vector <double> input ={11,9,21,8,17,19,13,1,24,12 }; int No_Of_Buckets = 5; bucketSort(input, No_Of_Buckets); cout<< "Sorted Output:"; for (int i; i < input.size(); i++) cout <<input[i]<<" "; return 0; }
输出:
Sorted Output:1 8 9 11 12 13 17 19 21 24
桶排序程序 Python
输入:
def bucketSort(input, No_Of_Buckets): max_element = max(input) min_element = min(input) span = (max_element - min_element) / No_Of_Buckets output = [] for bucket in range(No_Of_Buckets): output.append([]) for element in range(len(input)): diff = (input[element] - min_element) / span - int( (input[element] - min_element) / span ) if diff == 0 and input[element] != min_element: output[int((input[element] - min_element) / span) - 1].append( input[element] ) else: output[int((input[element] - min_element) / span)].append(input[element]) for bucket in range(len(output)): if len(output[bucket]) != 0: output[bucket].sort() index = 0 for bucket in output: if bucket: for element in bucket: input[index] = element index = index + 1 input = [11, 9, 21, 8, 17, 19, 13, 1, 24, 12] No_Of_Buckets = 5 bucketSort(input, No_Of_Buckets) print("Sorted Output:\n", input)
输出:
Sorted Output: [1, 8, 9, 11, 12, 13, 17, 19, 21, 24]
桶排序 Java
输入:
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class BucketSort { public static void bucketSort(List < Double > input, int No_Of_Buckets) { double max_value = Collections.max(input); double min_value = Collections.min(input); double span =(max_value - min_value) / No_Of_Buckets; List < List < Double > > output = new ArrayList < > (); for (int i = 0; i < No_Of_Buckets; i++) { output.add(new ArrayList < > ()); } for (Double value: input) { double difference = (value - min_value) / span - ((value - min_value) / span); if (difference == 0 && value != min_value) { output.get((int)((value - min_value) / span) - 1).add(value); } else { output.get((int)((value - min_value) / span)).add(value); } } for (List <Double> bucket: output) { if (!bucket.isEmpty()) { Collections.sort(bucket); } } int index = 0; for (List <Double> bucket: output) { if (!bucket.isEmpty()) { for (Double value: bucket) { input.set(index,value); index++; } } } } public static void main(String[] args) { List <Double> input = new ArrayList <> (); input.add(11.0); input.add(9.0); input.add(21.0); input.add(8.0); input.add(17.0); input.add(19.0); input.add(13.0); input.add(1.0); input.add(24.0); input.add(12.0); int No_Of_Buckets = 5; bucketSort(input, No_Of_Buckets); System.out.println("Sorted Output:"); for (Double value: input) { System.out.print(value + " "); } } }
输出:
Sorted Output: 1.0 8.0 9.0 11.0 12.0 13.0 17.0 19.0 21.0 24.0
赞成&反对
优点 | 缺点 |
---|---|
执行更快的计算 | 与其他算法相比,消耗更多空间 |
它可以用作外部排序方法 | 当数据分布不均匀时,性能不佳 |
桶可以独立处理 |
桶排序复杂度分析
桶排序的时间复杂度
- 最佳情况复杂度:如果所有数组元素都是均匀分布的,并且事先已排序,则将元素分散到相应的存储桶中需要 O(n) 时间。然后使用 插入排序 花费 O(k)。因此总体复杂度为 O(n+k)。
- 平均案例复杂度:对于一般情况,我们假设输入是均匀分布的。因此,桶排序算法实现了线性时间复杂度 O(n+k)。这里需要 O(n) 时间来分散元素,使用插入排序对这些元素进行排序需要 O(k) 时间。
- 最坏情况复杂度:在最坏的情况下,元素不会均匀分布,并集中在一个或两个特定的桶上。在这种情况下,桶排序将充当 冒泡排序算法。 因此,在最坏的情况下,桶排序的时间复杂度为 O(n^2)。
桶排序的空间复杂度
桶排序的空间复杂度为O(n*k)。其中n是元素的数量,k是所需的桶的数量。