计数排序算法原理和实现(C++)

本文介绍了计数排序的基本原理,该算法通过统计数组中每个元素出现的次数来确定元素的排序位置。在文章中,作者讨论了如何处理重复元素以及如何在C++中实现计数排序。此外,还提出了当数组元素分布较分散时可能存在的空间浪费问题,邀请读者进行讨论。
摘要由CSDN通过智能技术生成

一、什么是计数排序

计数排序的核心思想是——对于数组 array 中的某一个元素 X,倘若我们能统计出数组中小于 X 的元素个数 N。利用这一信息,可以直接把元素 X 放在数组中第 N+1个位置处。

举个例子,假如有一数组:

int array[] = {2,5,3,4,1};

倘若 X = 3,我们可以通过一趟遍历统计出小于 3 的元素一共有 2 个(2和1),立即得数 3 应该放在整个数组的第三位(array[2] = 3),但是这样一来会覆盖原有位置的元素。为了简单起见,初始化一个和 array 同维度的全 0 数组 outputarray (你也可以试着实现原址操作)。通过统计数组中元素出现的频率不难得到:

outputarray[] = { 1,2,3,4,5};

计数排序原理简单易懂,且能够在线性时间内完成排序,但是有一个小问题:如果数组中出现重复元素怎么办?

int array[] = {2,5,3,0,2,3,0,3};

这个问题也不难解决, 只要将计数条件从*“大于 X”* 改为*“大于或等于 X”* 就可以了,每次在outarray中填入一个重复元素 i,就让temp[i] = temp[i] - 1 ,以便下次继续填充。

二、计数排序代码实现

为了方便记数组中各个元素出现的次数,不妨维护一个数组 temp[M] ,temp[i] 表示原数组中小于等于数值 i 的元素出现的个数,其实也就是数值 i 的正确位置。显然,对于非负数组来说, temp 的维度 M 应满足:

M = max(array) + 1; // 因为数组中可能会出现0

具体的数值你可以通过一趟遍历得出。

通过一趟遍历统计出原数组所有元素出现过的次数,就可以根据 temp 数组将原数组中的元素按照顺序赋值到 outarray 中,代码如下:

/* parameters:
    input array:待处理数组
    output array:输出数组
    length:输入数组的维度
    k:数组中所有数值的上限
*/
void Counting_Sort(int* inputarray, int* outputarreay,int length, int k)
{
    int *temp = new int[k]; //临时数组,统计出现次数
    for (int i = 0; i < k; i++) //初始化数组
        temp[i] = 0; //初始化
    for (int j = 0; j < length; j++) //统计元素出现的个数 
        temp[inputarray[j]] += 1;
    for (int l = 1; l < k; l++)//统计小于等于当前值的个数
        temp[l] = temp[l] + temp[l - 1];
    for (int k = length-1; k>-1; k--)//赋值,个数-1,自后向前保持稳定
    {
         outputarreay[temp[inputarray[k]]-1] = inputarray[k];
         temp[inputarray[k]] -= 1;
    }
    delete[]temp;
}

值得注意的一点是,在最后一趟遍历赋值是自后向前的,这样可以让数组中重复元素的相对位置不变,因此快速排序是稳定的。

在主函数中调用跑一下看看结果:

int main()
{
    int array[] = { 2,5,3,0,2,3,0,3,1,2,3 };
    int output[] = { 0,0,0,0,0,0,0,0,0,0,0 };
    int k = 0;
    for (int i : array)
        k = (i > k ? i : k);
    Counting_Sort(array, output, size(array), k + 1);
    for (int i : output)
        cout << i << " ";
    cout << endl;
    return 0;
}

在这里插入图片描述
最后,程序还有可以改进之处——倘若数据中出现负数,如何定义temp?如何得出 outarray?我只想到根据数组元素的下界设置偏移量,达到统计负数出现次数的目的。

思考:倘若数组中的元素相当分散,使用计数排序是否会浪费大量额外的空间?例如

int array[] = {1,5,4,10,100};

此时如何改进呢?欢迎讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值