十大经典排序(三) —— 计数、桶、基数

本文深入探讨了三种高效排序算法:计数排序、桶排序和基数排序。计数排序通过统计数组中每个元素出现的次数实现排序;桶排序将元素分配到不同桶中分别排序,最后合并;基数排序利用数字的位数,逐位进行排序。这些算法的时间复杂度均为线性或接近线性,且都是稳定的排序方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、计数排序

原理

创建一个长度为 k+1 的数组,每个数组的值对应输入数组中数字出现的次数,通过遍历一次输入数组并统计每个元素出现次数,最后遍历输出

图解

计数排序

代码

void CountSort(int *a, int n) {
    int i;
    int k = 0;
    int minValue = a[0];
    int maxValue = a[0];
    for (i = 0; i < n; i++) {
        if (a[i] < minValue) {
            minValue = a[i];
        }
        if (a[i] > maxValue) {
            maxValue = a[i];
        }
    }
    int count = maxValue - minValue + 1;
    int *b = new int[count];
    memset(b, 0, sizeof(b));
    for (i = 0; i < n; i++) {
        b[a[i] - minValue]++;
    }
    for (i = 0; i < count; i++) {
        while (b[i]--) {
            a[k++] = i + minValue;
        }
    }
    delete[] b;
}

复杂度

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n + k ) O(n+k) O(n+k)

稳定性

计数排序是稳定的

2、桶排序

思想

桶排序就是划分多个范围相同的区间,每个区间各自排序,最后合并。

桶排序相当于是计数排序的扩展版,只不过计数排序是每个区间是长度为1的桶,并且每个桶的只有相同的元素,而桶排序是按区间存储一定范围的元素,元素种类也可以不相同

注:
1、桶排序只适用于非负数数的情况

2、桶排序尽量保证元素均匀分布,若全部集中在一个桶,则排序失效

图解

桶排序

代码

来源于 菜鸟教程——桶排序

struct ListNode {
    int val;
    ListNode *next;
};
//链表的有序插入
ListNode *Insert(ListNode *head, int val) {
    ListNode *dum = new ListNode;
    ListNode *newNode = new ListNode;
    ListNode *pre, *cur;
    newNode->val = val;
    dum->next = head;
    pre = dum;
    cur = head;
    while (cur && cur->val <= val) {
        pre = cur;
        cur = cur->next;
    }
    newNode->next = cur;
    pre->next = newNode;
    return dum->next;
}

//有序链表的合并
ListNode *Merge(ListNode *l1, ListNode *l2) {
    ListNode *dumNode = new ListNode;
    ListNode *dum = dumNode;
    while (l1 && l2) {
        if (l1->val >= l2->val) {
            dum->next = l2;
            l2 = l2->next;
        } else {
            dum->next = l1;
            l1 = l1->next;
        }
        dum = dum->next;
    }
    if (l1) {
        dum->next = l1;
    }
    if (l2) {
        dum->next = l2;
    }
    return dumNode->next;
}
//获取桶的长度
int GetBucketLength(int *a, int n) {
    int max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > max) {
            max = a[i];
        }
    }
    return (int) sqrt(max) + 1;
}
//桶排序
void BucketSort(int *a, int n) {
    int BUCKET_NUM = GetBucketLength(a, n);
    vector<ListNode *> bucket(BUCKET_NUM, (ListNode *) (0));
    for (int i = 0; i < n; i++) {
        int index = a[i] / BUCKET_NUM;
        ListNode *head = bucket.at(index);
        bucket.at(index) = Insert(head, a[i]);
    }
    ListNode *head = bucket.at(0);
    for (int i = 1; i < BUCKET_NUM; i++) {
        head = Merge(head, bucket.at(i));
    }
    for (int i = 0; i < n; i++) {
        a[i] = head->val;
        head = head->next;
    }
}

复杂度

时间复杂度: O ( n + k ) O(n+k) O(n+k)

空间复杂度: O ( n + k ) O(n+k) O(n+k)

稳定性

桶排序是稳定的

3、基数排序

思想

基数排序使用的是桶排序的思想,不过基数排序比桶排序更加灵活,他只需要10个桶,每次只对一位进行排序

首先对个位进行排序,然后对十位、百位…每一步使序列趋近于有序状态,排到最后一位的时候排序完成

图解

基数排序

代码

来源于 菜鸟教程——基数排序

//获取最大元素的位数
int MaxBit(int *a, int n) {
    int max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > max) {
            max = a[i];
        }
    }
    int cnt = 1;
    while (max >= 10) {
        cnt++;
        max /= 10;
    }
    return cnt;
}
//基数排序
void RadixSort(int *a, int n) {
    int NumBit = MaxBit(a, n);
    int tmp[n];
    int count[10];
    int i, j, k;
    int radix = 1;
    for (i = 1; i <= NumBit; i++) {
        memset(count, 0, sizeof(count));
        for (j = 0; j < n; j++) {
            k = (a[j] / radix) % 10;
            count[k]++;
        }
        for (j = 1; j < 10; j++) {
            count[j] += count[j - 1];
        }
        for (j = n - 1; j >= 0; j--) {
            k = (a[j] / radix) % 10;
            tmp[count[k] - 1] = a[j];
            count[k]--;
        }
        for (j = 0; j < n; j++) {
            a[j] = tmp[j];
        }
        radix *= 10;
    }
}

复杂度

时间复杂度: O ( n ∗ k ) O(n*k) O(nk)   k为最大元素的位数

空间复杂度: O ( n + k ) O(n+k) O(n+k)

稳定性

基数排序是稳定的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值