1. 引言
在本文中,我们将深入探讨桶排序算法。 我们将从一些快速的理论开始,然后进行 Java 实现和单元测试我们的解决方案。最后,我们将了解存储桶排序的时间复杂度。
2. 斗式分拣理论
桶分拣,有时也称为箱分拣,是一种特定的分拣算法。排序的工作原理是将我们想要排序的元素分布到几个单独排序的存储桶中。通过这样做,我们可以减少元素之间的比较次数,并帮助缩短排序时间。
让我们快速看一下执行桶排序所需的步骤:
- 设置我们最初为空的存储桶的数组
- 将我们的元素分配到相应的存储桶中
- 对每个存储桶进行排序
- 将排序的存储桶连接在一起以重新创建完整列表
3.Java 实现
虽然这个算法不是特定于语言的,但我们将在 Java 中实现排序。让我们一步一步地浏览上面的列表,并编写代码来对整数列表进行排序。
3.1. 桶设置
首先,我们需要确定一种哈希算法,以决定将哪些元素放入哪个桶中:
private int hash(int i, int max, int numberOfBuckets) {
return (int) ((double) i / max * (numberOfBuckets - 1));
}
定义哈希方法后,我们现在可以将条柱数指定为输入列表大小的平方根:
final int numberOfBuckets = (int) Math.sqrt(initialList.size());
List<List<Integer>> buckets = new ArrayList<>(numberOfBuckets);
for(int i = 0; i < numberOfBuckets; i++) {
buckets.add(new ArrayList<>());
}
最后,我们需要一个简短的方法来确定输入列表中的最大整数:
private int findMax(List<Integer> input) {
int m = Integer.MIN_VALUE;
for (int i : input) {
m = Math.max(i, m);
}
return m;
}
3.2. 分发元素
现在我们已经定义了桶,我们可以使用 hash 方法将输入列表的每个元素分发到其相关存储桶中:
int max = findMax(initialList);
for (int i : initialList) {
buckets.get(hash(i, max, numberOfBuckets)).add(i);
}
3.3. 对各个存储桶进行排序
定义存储桶并充满整数后,让我们使用 Comparator 对它们进行排序:
Comparator comparator = Comparator.naturalOrder();
for(List<Integer> bucket : buckets){
bucket.sort(comparator);
}
3.4. 连接我们的存储桶
最后,我们需要将存储桶组合在一起以重新创建单个列表。由于我们的存储桶是排序的,因此我们只需要遍历每个存储桶一次,并将元素附加到主列表中:
List<Integer> sortedArray = new LinkedList<>();
for(List<Integer> bucket : buckets) {
sortedArray.addAll(bucket);
}
return sortedArray;
4. 测试我们的代码
完成实现后,让我们编写一个快速的单元测试,以确保它按预期工作:
BucketSorter sorter = new IntegerBucketSorter();
List<Integer> unsorted = Arrays.asList(80,50,60,30,20,10,70,0,40,500,600,602,200,15);
List<Integer> expected = Arrays.asList(0,10,15,20,30,40,50,60,70,80,200,500,600,602);
List<Integer> sorted = sorter.sort(unsorted);
assertEquals(expected, sorted);
5. 时间复杂度
接下来,让我们快速看一下执行存储桶排序的时间复杂度。
5.1. 最坏情况
在最坏的情况下,我们会在**同一个存储桶中以相反的顺序找到所有元素。**当这种情况发生时,我们将存储桶排序简化为简单排序,其中每个元素都与其他元素进行比较,从而产生 O(n²) 的时间复杂度。
5.2. 平均案例场景
在我们的平均案例中,我们发现元素在输入存储桶中相对均匀地分布。由于我们的每个步骤只需要通过输入存储桶进行一次迭代,因此我们发现存储桶排序在 O(n) 时间内完成。
6. 结论
在本文中,我们了解了如何在 Java 中实现存储桶排序。我们还研究了存储桶排序算法的时间复杂度。