算法与数据结构 排序算法-基数排序/桶排序

算法与数据结构 排序算法-基数排序/桶排序

多关键字排序

有时我们需要对多关键字数据进行排序,如扑克牌有花色和数字两个关键字,如果我们对扑克牌排序,假设四种花色为A、B、C、D,要求花色优先级高于数字,有两种方法
1.先按花色分成4堆,然后对每一堆排好序后,将4堆牌按次序放在一起,这种方法是最高位优先法MSD
2.先按数字分成13堆,然后将它们按次序叠在一起,如13在上,1在下,然后再一张一张的按花色分成四堆,因为此时牌已经按照数字牌好了,因此按花色分配时,后来被分配的牌的数字一定比已经分配的小,最终再将4堆牌按次序放在一起,完成排序,这种方法是最低位优先法

可以看出,按MSD排序时,是分成了一个个子序列,对每个子序列排序时可以选各种稳定或不稳定的排序方法
按LSD排序时,每次排序时都是一整个序列,对整个序列按某个关键字排序时,需要采用稳定的排序方法,不然可能第2个关键字排好了,第一个又乱了

桶排序就是一种MSD排序方式,先将数据按照一定范围分为多组,再对每一组进行排序,最后合并

基数排序是一种LSD排序方式,基数指的是关键字的取值范围,如果十进制数进行排序,基数就是10。
最开始基数排序需要基数d*数据长度n的辅助空间,后来用计数代替分配的方式来优化空间使用,此时需要使用d+n的辅助空间,后来提出了链式基础排序,采用链表结构,辅助空间仅需要2*d

对数组进行基于计数排序的基数排序(注意可能有负数)
#include
#include
#include
#define ARRAY_SIZE 9

void radixSort(int *arr, int size)
{
        int max = 0;
        int min = 0;
        int base = 0;
        int i = 0;
        int bucket[10] = {0};
        int *sortedArr = NULL;
        int index = 0;

        if (!arr)
        {
                return;
        }

        /* 保存每次排序完的数据 */
        sortedArr = (int *)malloc(sizeof(int) * size);
        if (!sortedArr)
        {
                return;
        }
        memset(sortedArr, 0, sizeof(int) * size);

        /* 如果有负数,先转成正数 */
        max = arr[i];
        min = arr[i];

        for (i = 0; i < size; i++)
        {
                max = max > arr[i] ? max : arr[i];
                min = min < arr[i] ? min : arr[i];
        }

        if (min < 0)
        {
                for (i = 0; i < size; i++)
                {
                        arr[i] -= min;
                }
        }

        max -= min;
        base = 1;
        /* max是最大的数,也是最长的数,通过类
         * 似二进制右移动的原理来计算位数 */
        while (max / base)
        {
                /* 每次都要先清零,防止上次数据参与进来 */
                memset(bucket, 0, sizeof(int) * 10);

                /* 每次对单个数字进行计数排序 */
                for (i = 0; i < size; i++)
                {
                        bucket[(arr[i] / base) % 10]++;
                }

                for (i = 1; i < 10; i++)
                {
                        bucket[i] += bucket[i - 1];
                }

                for (i = size - 1; i >=0; i--)
                {
                        index = bucket[(arr[i] / base) % 10];
                        sortedArr[index - 1] = arr[i];
                        bucket[(arr[i] / base) % 10]--;
                }

                for (i = 0; i < size; i++)
                {
                        arr[i] = sortedArr[i];
                }

                base *= 10;
        }

        /* 还原数据 */
        if (min < 0)
        {
                for (i  = 0; i < size; i++)
                {
                        arr[i] += min;
                }
        }

        free(sortedArr);
}

int main(void)
{
        int i = 0;
        int array[ARRAY_SIZE] = {38, 22, -3, 1, 29, 4, 58, 352, 6};

        radixSort(array, ARRAY_SIZE);

        for (i = 0; i < ARRAY_SIZE; i++)
        {
                printf("%d ", array[i]);
        }

        puts("");

        return 0;
}
链式基数排序
#include
#include
#include
#define ARRAY_SIZE 9


struct listNode
{
        int val;
        struct listNode *next;
};

/* 分配 */
void distribute(struct listNode *head, int base, struct listNode **radixHead, struct listNode **radixTail)
{
        int index = 0;
        struct listNode *curNode = NULL;

        if (!head || !radixHead || !radixTail)
        {
                return;
        }

        curNode = head;

        while (curNode)
        {
                index = (curNode->val / base) % 10;

                if (!radixHead[index])
                {
                        radixHead[index] = radixTail[index] = curNode;
                }
                else
                {
                        /* 尾插法,稳定排序 */
                        (radixTail[index])->next = curNode;
                        radixTail[index] = curNode;
                }

                curNode = curNode->next;
        }
}

struct listNode *collect(struct listNode **radixHead, struct listNode **radixTail)
{
        struct listNode *head = NULL;
        int i = 0;
        int j = 0;

        if (!radixHead || !radixTail)
        {
                return NULL;
        }

        for (i = 0; i < 10; i++)
        {
                if (radixHead[i])
                {
                        head = radixHead[i];
                        (radixTail[i])->next = NULL;
                        break;
                }
        }

        for (j = i + 1; j < 10; j++)
        {
                if (radixHead[j])
                {
                        (radixTail[i])->next = radixHead[j];
                        /* 不要忘了将最后一个置为空指针 */
                        (radixTail[j])->next = NULL;
                        i = j;
                }
        }

        return head;
}

struct listNode *radixSort(struct listNode *head)
{
        int min = 0;
        int max = 0;
        int base = 0;
        struct listNode *curNode = NULL;

        /* 每个基数链表的头指针 */
        struct listNode *radixHead[10] = {NULL};
        /* 每个基数链表的尾指针 */
        struct listNode *radixTail[10] = {NULL};

        if (!head)
        {
                return NULL;
        }

        curNode = head;
        min = max = curNode->val;

        while (curNode)
        {
                min = min < curNode->val ? min : curNode->val;
                max = max > curNode->val ? max : curNode->val;
                curNode = curNode->next;
        }

        if (min < 0)
        {
                curNode = head;
                while (curNode)
                {
                        curNode->val -= min;
                        curNode = curNode->next;
                }

                max -= min;
        }

        base = 1;

        while (max / base)
        {
                memset(radixHead, 0, sizeof(struct listNode *) * 10);
                memset(radixTail, 0, sizeof(struct listNode *) * 10);

                distribute(head, base, radixHead, radixTail);
                head = collect(radixHead, radixTail);

                base *= 10;
        }
        
        if (min < 0)
        {
                curNode = head;
                while (curNode)
                {
                        curNode->val += min;
                        curNode = curNode->next;
                }

        }
        return head;
}

int main(void)
{
        int i = 0;
        int array[ARRAY_SIZE] = {38, 22, 3, 1, 29, 4, 58, 52, 6};
        struct listNode *list = NULL;

        list = (struct listNode *)malloc(sizeof(struct listNode) * ARRAY_SIZE);
        if (!list)
        {
                return 0;
        }

        memset(list, 0, sizeof(struct listNode) * ARRAY_SIZE);

        for (i = 0; i < ARRAY_SIZE; i++)
        {
                list[i].val = array[i];
                if (i != (ARRAY_SIZE - 1))
                {
                        list[i].next = list + i + 1;
                }
        }

        list = radixSort(list);

//        for (i = 0; i < ARRAY_SIZE; i++)
        while (list)
        {
                printf("%d ", list->val);
                list = list->next;
        }

        puts("");

        return 0;
}
时间复杂度

O(n)

空间复杂度

取决于数据范围

特点

有负数需要先处理一下

你可能感兴趣的:(算法与数据结构,排序算法,算法,数据结构)