桶排序
桶排序类似计数排序,计数排序需要根据序列范围创建一个统计数组,用来统计每个位置整数出现的次数,每个位置只能统计相同元素。而桶排序每个桶表示一个区间范围,可以包含多个元素。
如何确定桶的范围,根据实际情况适当分配,下面以统计学生数学成绩 (0 - 100 分)为例子
按照每 20分一个桶,则分为五个桶
桶1:[0, 20)
桶1:[20, 40)
桶1:[40, 60)
桶1:[60, 80)
桶1:[80, 100]
假设十个同学成绩如下:{ 73, 30, 90, 89, 78, 10, 93, 60, 79, 98 }
图例如下
代码如下
public void Test()
{
int[] arr = new int[] { 73, 30, 90, 89, 78, 10, 93, 60, 79, 98 };
BucketSortFunc(arr);
LogArr.Log(arr);
}
public void BucketSortFunc(int[] arr)
{
int max = arr[0];
int min = arr[0];
for (int i = 0; i < arr.Length; ++i)
{
if (arr[i] > max)
{
max = arr[i];
}
if (arr[i] < min)
{
min = arr[i];
}
}
//桶数计算: 此处需要根据实际情况设计桶范围划分方法
int bucketNum = (max - min) / arr.Length + 1;
// 创建桶,因为需要空间未知所以用列表作为桶,便于扩展
// 此处使用了 C# 的 List,可以根据自己使用语言修改,亦可自己实现一个链表
List<List<int>> bucketList = new List<List<int>>(bucketNum);
for (int i = 0; i < bucketNum; ++i)
{
bucketList.Add(new List<int>());
}
// 遍历所有元素,将元素放入相应的桶内
for (int i = 0; i < arr.Length; ++i)
{
// 计算元素应该放置的桶位置
// 次数算法必须遵照上方 桶数计算:
int num = (arr[i] - min) / arr.Length;
bucketList[num].Add(arr[i]);
}
// 对每个桶进行排序
for (int i = 0; i < bucketList.Count; ++i)
{
bucketList[i].Sort();
}
int index = 0;
for (int i = 0; i < bucketList.Count; ++i)
{
List<int> dataList = bucketList[i];
for (int j = 0; j < dataList.Count; ++j)
{
arr[index] = dataList[j];
++index;
}
}
}
优点:在处理均匀分布的数据时,桶排序可以达到线性时间复杂度O(n),优于许多比较排序算法
缺点:当数据分布不均匀时,可能会导致某些桶内数据多过,从而造成空间浪费或增加排序时间,此外桶排序的空间复杂度较高,需要额外的空间来存储数据和桶