基排序 / 桶排序 / 数字排序

# 原理

需要频繁进行分组重排,(类似于归并)适用于链表

可分为两种:

  • MSD,最高位优先 (Most Significant Digit first)

  • LSD,最低位优先 (Least Significant Digit first)

# 代码

c++
//Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};
c++
class Solution {
public:
    ListNode* sortList(ListNode* head)
    {
        ListNode* dummyhead=new ListNode(0,head);
        ListNode* p=dummyhead;
        while(p->next!=nullptr)
        {
            p->next->val+=100000;
            p=p->next;
        }
        vector<queue<ListNode*>>vec(10); // 按 0~9 分组
        for(int i=1;i<=100000;i*=10) // 这里是 6 位数,共 6 趟
        {
            int flag=0;
            while(dummyhead->next!=nullptr)
            {
                if(dummyhead->next->val/(i*10)!=0)
                    flag=1;
                vec[dummyhead->next->val/i%10].push(dummyhead->next);
                dummyhead->next=dummyhead->next->next;
            }
            ListNode* p=dummyhead;
            for(int j=0;j<10;++j) // 将每个组节点连接起来
            {
                while(!vec[j].empty())
                {
                    vec[j].front()->next=p->next;
                    p->next=vec[j].front();
                    p=p->next;
                    vec[j].pop();
                }
            }
            if(flag==0)
                break;
        }
        p=dummyhead;
        while(p->next!=nullptr)
        {
            p->next->val-=100000;
            p=p->next;
        }
        ListNode* ret=dummyhead->next;
        delete dummyhead;
        return ret;
    }
};

# 复杂度

设有nn 个待排序记录,关键字位数为dd,每位有rr 种取值。则排序的趟数是dd; 在每一趟中:

  • 链表初始化的时间复杂度:O(r)O(r);
  • 分配的时间复杂度:O(n)O(n);
  • 分配后收集的时间复杂度:O(r)O(r);

则链式基数排序的时间复杂度为: O(d(n+r))O(d\cdot (n+r))

在排序过程中使用的辅助空间是:2r2r 个链表指针,nn 个指针域空间,
实际应用中rr 远小于nn,可以得到时间复杂度为:O(dn)O(dn)

则空间复杂度为:O(n+r)O(n+r)

  • 当 n 很大,d 比较小小,基数排序可以比归并、快排性能更好

  • 基排序是稳定排序。