如果已知N个关键字的取值范围是在0到M-1之间,而M比N小得多,
则桶排序算法将为关键字的每个可能取值建立一个“桶”,即建立M个桶;在扫描N个关键字时,将每个关键字放入相应的桶中,然后按桶的顺序收集一遍就自然有序了。
所以桶排序效率比一般的排序算法高,当然需要的额外条件是已知关键字的范围,并且关键字在此范围内是可列的,个数还不能超过内存空间所能承受的限度。
比如对学校内学生的分数排序,假设满分为100分就可以用到桶排序。
算法实现(C#):
// 桶节点
private class BucketNode
{
public int Key { get; set; }
public BucketNode Next { get; set; }
}
// 桶头节点
private class HeadBucketNode
{
public BucketNode Head { get; set; }
public BucketNode Tail { get; set; }
}
// 桶的最大个数,适用于关键词
private static int MaxBucketsCount = 101;
// 桶排序
public static void BucketSort(int[] arr)
{
BucketNode head = null;
BucketNode tmp = null;
int key = 0;
HeadBucketNode[] buckets = new HeadBucketNode[MaxBucketsCount];
// 初始化桶
for (int i = 0; i < buckets.Length; i++)
{
buckets[i] = new HeadBucketNode()
{
Head = null,
Tail = null
};
}
// 分配-遍历序列将每个元素按关键词放入指定的桶
for (int i = 0; i < arr.Length; i++)
{
key = arr[i];
tmp = new BucketNode();
tmp.Key = key;
tmp.Next = null;
if (buckets[key].Head == null)
{
buckets[key].Head = tmp;
buckets[key].Tail = tmp;
}
else
{
buckets[key].Tail.Next = tmp;
buckets[key].Tail = tmp;
}
}
// 收集-将桶中元素收集回链表
head = null;
for (key = MaxBucketsCount - 1; key >= 0; key--)
{
if (buckets[key].Head != null)
{
buckets[key].Tail.Next = head;
head = buckets[key].Head;
buckets[key].Head = null;
buckets[key].Tail = null;
}
}
// 将链表复制回数组
for (int i = 0; i < arr.Length; i++)
{
arr[i] = head.Key;
head = head.Next;
}
}
通过代码可以看出桶排序时间复杂度为O(N+M),M为桶的个数,特别当M=O(N)时,这个复杂度是线性的。
桶排序空间复杂度为O(N)。