排序系列(八)桶排序

36 阅读1分钟

如果已知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)。