计数排序-Counting Sort

本文介绍了一种不依赖于元素比较的排序算法——计数排序。文章详细解释了计数排序的工作原理,包括如何使用额外数组记录元素出现次数及排序过程,并提供了具体的实现代码。最后分析了计数排序的时间复杂度和稳定性。

计数排序是一种不需要进行元素比较的算法,它是通过数组中元素出现的次数来确定其如何排列的。

以待排数组arr[] = {3,1,3,4,3,5,4,2}为例,对其计数排序的思路是这样的:

  1. 它需要创建两个临时空间,我们以tmp和count来表示,其中tmp临时存放已排好的数据。

  2. count这个数组我们需要用两次,第一次存放待排数组arr各元素出现的次数,count[i]中存元素i出现的次数;第二次count[i]中存放小于等于i的元素的个数,其值可以用第一次存放的count[i] + count[i-1]得出。当然了,count里面的值最终是第二次的值。count的大小由待排数组的最大元素的值决定的。
    这里写图片描述

  3. 然后开始从后往前依次取出待排数组arr中的元素,按照其在count中对应的值在临时数组tmp中对号入座 ,入座后该元素在count中的值应该减1,这样能保证arr中相同元素下一次进入tmp中能放在其前一个位置。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    后面依次存放 ,直到遍历完arr中的元素。

  4. 将tmp中的元素拷到arr中。

代码实现如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//参数分别为待排数组,待排数组的元素个数,和最大元素加1,失败返回0,成功返回1
int ctsort(int* arr,int sz,int k)
{
    int *tmp = NULL;
    int *count = NULL;
    int i;

    if(!(tmp=(int*)malloc(sz*sizeof(int)))) return 0;   
    if(!(count = (int*)malloc(k*sizeof(int)))) return 0;

    for(i=0; i<k; i++)//将count各元素初始化为0
        count[i] = 0;

    for(i=0; i<sz; i++)//统计出各元素出现的次数并将其存放在count中
        count[arr[i]] = count[arr[i]] + 1;

    for(i=1; i<k; i++)//将小于等于各元素的数的个数存放在count中
        count[i] = count[i]+count[i-1];

    for(i=sz-1; i>=0; i--)//从后往前遍历arr,把其中的元素对号入座
    {
        tmp[count[arr[i]] - 1] = arr[i];
        count[arr[i]] = count[arr[i]]-1;
    }

    memcpy(arr,tmp,sz*sizeof(int));//将tmp中的元素拷回arr

    free(tmp);
    free(count);

    return 1;
}

int main()
{
    int i;
    int arr[] = {3,1,3,4,3,5,4,2};
    int sz = sizeof(arr)/sizeof(arr[0]);

    for(i=0; i<sz; i++)
        printf("%d ",arr[i]);

    ctsort(arr,sz,6);

    printf("\n");
    for(i=0; i<sz; i++)
        printf("%d ",arr[i]);
    return 0;
}

结果如下:
这里写图片描述

计数排序的时间复杂度为O(n+k),n为待排数组元素的个数,k为待排数组最大元素值加1。对于空间来说,需要两个n大小的数组,一个k大小的数组。

为了保证计数排序的稳定性,上面是从后往前处理待排数组arr的。

所谓稳定性,就是指如果待排数组arr中,有两个数 a[i] 和 a[j]相等,并且i<j,z在排好序以后,a[i] 仍然在 a[j] 之前。

### Python 计数排序Counting Sort算法实现 计数排序是一种非比较型整数排序算法,适用于数据范围较小的整数排序。该算法通过统计每个值出现的次数来进行排序。 #### 计数排序的核心思想 对于给定的一个数组 `arr` ,找到最大值 `max_val` 并创建一个长度为 `max_val + 1` 的辅助数组 `count` 。这个辅助数组用来记录原数组中各个数值出现的频次。最后再根据频次重构有序的新列表[^1]。 下面是具体的Python代码实现: ```python def counting_sort(arr): if not arr: # 处理空数组的情况 return [] max_val = max(arr) # 获取数组中的最大值 min_val = min(arr) # 获取最小值以便处理负数 offset = -min_val # 偏移量用于支持负数 m = max_val + offset + 1 # 考虑偏移后的大小 count = [0] * m # 初始化频率表 for a in arr: count[a + offset] += 1 # 统计各元素的数量 result = [] # 构建结果集 for i in range(len(count)): while count[i] > 0: # 将相同数量的i加入result result.append(i - offset) count[i] -= 1 return result # 返回已排序的结果 ``` 此版本不仅能够处理正整数还可以处理包含负数的数据集合[^2]。 为了验证上述函数的有效性,可以使用如下测试案例: ```python # 测试用例 test_cases = [ ([1,4,1,2,7,5,2], [1,1,2,2,4,5,7]), ([3,-1,2,-1,0], [-1,-1,0,2,3]) ] for case in test_cases: print(f"原始数组:{case[0]}") print(f"排序结果:{counting_sort(case[0])}") print(f"期望结果:{case[1]}\n") ``` 以上实现了对含有正整数以及含负数两种情况下计数排序的功能展示,并且保持了算法的时间复杂度为线性的特性即O(n)[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值