一、问题描述
利用桶排序算法对整形数组排序。
二、问题分析
假设数组元素最大值和最小值分别为max和min,则桶的个数为max - min + 1,也即数组区间[min, max]每个元素和桶下标区间[0,max - min + 1]中每个元素一一对应,这也是桶排序的核心思想。
(1)数组元素与桶下标对应关系
元素arr[i]------>桶下标arr[i] - min
例如:
数组元素为:-1 ,-3 ,0 ,2 ,4 ,4 ,3 ,6 ,9
对应桶下标:2 , 0 ,3 ,5 ,7 ,7 ,6 ,9 ,12
(2)数组元素arr[i]在排序后的序列中的下标为bucket[arr[i] - min]
分析如下:
假设数组元素为:-1 ,-3 ,0 ,2 ,4 ,4 ,3 ,6 ,9,请注意下面三行中相同位置的元素对应关系
遍历一次数组后,可以得到(1)中各元素对应的桶下标,可以得到桶元素为: [1, 0, 1, 1, 0, 1, 1, 2, 0, 1, 0, 0, 1]
其中,桶中非0元素对应数组元素情况为: -3 -1 0 2 3 4 6 9
再处理一次桶中元素使bucket[i] = bucket[i] + bucket[i - 1],操作后桶元素为: [1, 1, 2, 3, 3, 4, 5, 7, 7, 8, 8, 8, 9]
处理之后,桶中i位置元素值即为落入桶i中数组元素在排序后的序列中的下标值。
因为此时桶中i位置元素值为所有小于落入桶i位置数组元素的数组元素个数总和。
三、算法代码
public static void bucketSort(int [] arr){
System.out.println("排序前数组:" + Arrays.toString(arr));
System.out.println();
//寻找数组中min,max,用于建桶
int min = 0, max = 0;
for(int i = 0; i <= arr.length - 1; i++){
if(arr[i] < min){
min = arr[i];
}
if(arr[i] > max){
max = arr[i];
}
}
System.out.println("预处理信息:" + "min:" + min + " " + "max:" + max);
System.out.println();
//开始建桶,注意桶的数量等于max - min + 1
System.out.println("排序过程中桶状态:");
int bucketCount = max - min + 1;
System.out.println("桶个数:" + bucketCount + ",桶下标范围0~" + (bucketCount - 1));
int[] bucket = new int[bucketCount];
for(int i = 0; i <= arr.length - 1; i++){
bucket[arr[i] - min]++;
}
System.out.println(Arrays.toString(bucket));
for(int i = 1; i < bucketCount; i++){
bucket[i] = bucket[i] + bucket[i - 1];
}
System.out.println(Arrays.toString(bucket));
System.out.println();
//开始排序
int [] copy = new int[arr.length];
System.arraycopy(arr, 0, copy, 0, arr.length);
//从后往前排序,保持元素相对位置,保证算法稳定性。
for(int i = arr.length - 1; i >= 0; i--){
arr[--bucket[copy[i] - min]] = copy[i];
}
//若从前往后排序,虽然排序结果相同,但会破坏元素相对位置和算法稳定性
// for(int i = 0; i <= arr.length - 1; i++){
// arr[--bucket[copy[i] - min]] = copy[i];
// }
System.out.println("排序后数组:" + Arrays.toString(arr));
}
四、完整测试代码
import java.util.Arrays;
public class BucketSort {
public static void main(String[] args) {
int [] arr = {-1,-3,0,2,4,4,3,6,9};
bucketSort(arr);
}
public static void bucketSort(int [] arr){
System.out.println("排序前数组:" + Arrays.toString(arr));
System.out.println();
//寻找数组中min,max,用于建桶
int min = 0, max = 0;
for(int i = 0; i <= arr.length - 1; i++){
if(arr[i] < min){
min = arr[i];
}
if(arr[i] > max){
max = arr[i];
}
}
System.out.println("预处理信息:" + "min:" + min + " " + "max:" + max);
System.out.println();
//开始建桶,注意桶的数量等于max - min + 1
System.out.println("排序过程中桶状态:");
int bucketCount = max - min + 1;
System.out.println("桶个数:" + bucketCount + ",桶下标范围0~" + (bucketCount - 1));
int[] bucket = new int[bucketCount];
for(int i = 0; i <= arr.length - 1; i++){
bucket[arr[i] - min]++;
}
System.out.println(Arrays.toString(bucket));
for(int i = 1; i < bucketCount; i++){
bucket[i] = bucket[i] + bucket[i - 1];
}
System.out.println(Arrays.toString(bucket));
System.out.println();
//开始排序
int [] copy = new int[arr.length];
System.arraycopy(arr, 0, copy, 0, arr.length);
//从后往前排序,保持元素相对位置,保证算法稳定性。
for(int i = arr.length - 1; i >= 0; i--){
arr[--bucket[copy[i] - min]] = copy[i];
}
//若从前往后排序,虽然排序结果相同,但会破坏元素相对位置和算法稳定性
// for(int i = 0; i <= arr.length - 1; i++){
// arr[--bucket[copy[i] - min]] = copy[i];
// }
System.out.println("排序后数组:" + Arrays.toString(arr));
}
}
五、运行结果
排序前数组:[-1, -3, 0, 2, 4, 4, 3, 6, 9]
预处理信息:min:-3 max:9
排序过程中桶状态:
桶个数:13,桶下标范围0~12
[1, 0, 1, 1, 0, 1, 1, 2, 0, 1, 0, 0, 1]
[1, 1, 2, 3, 3, 4, 5, 7, 7, 8, 8, 8, 9]
排序后数组:[-3, -1, 0, 2, 3, 4, 4, 6, 9]