浅谈排序算法实现 (计数排序、基数排序)

  1、   计数排序

      计数排序是一种高效的线性排序,它通过计算一个集合中元素楚翔的次数来确定集合如何排列,计数排序不需要进行数据的比较,所有他的运行效率前面介绍的都高。

      计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组Count_arr,其中第i个元素是待排序数组Arr中值等于i的元素的个数。然后根据数组Count_arr来将Arr中的元素排到正确的位置。

    分为四个步骤:

1.找出待排序的数组中最大和最小的元素

2.统计数组中每个值为i的元素出现的次数,存入数组Count_arr的第i项

3.对所有的计数累加(从Count_arr中的第一个元素开始,每一项和前一项相加)

4.反向遍历原数组:将每个元素i放在新数组的第Count_arr(i)项,每放一个元素就将Count_arr(i)减去1



上面的图不知道大家能看明白不,不过看代码也一样很容易就明白的!(代码已经测试过OK,有问题请留言)

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/**************************************************************
 *计数排序。
 *参数: data : 要排序的数组
 *       size :数组元素的个数
 *       k    :数组中元素数组最大值 +1 (这个需要+1)
 *返回值: 成功0;失败-1.       
 * ************************************************************/
int ctsort(int *data, int size, int k)
{
    int * counts = NULL,/*计数数组*/
        * temp = NULL;/*保存排序后的数组*/
    int i = 0;

    /*申请数组空间*/
    if ((counts = (int *) malloc( k * sizeof(int))) == NULL)
        return -1;
    if ((temp = (int *) malloc( k * sizeof(int))) == NULL)
        return -1;

    /*初始化计数数组*/
    for (i = 0; i < k; i ++)
        counts[i] = 0;
    /*数组中出现的元素,及出现次数记录*/
    for(i = 0; i < size; i++)
        counts[data[i]] += 1;
    /*调整元素计数中,加上前一个数*/
    for (i = 1; i < k; i++)
        counts[i] += counts[i - 1];
    /*使用计数数组中的记录数值,来进行排序,排序后保存的temp*/
    for (i = size -1; i >= 0; i --){
        temp[counts[data[i]] - 1] = data[i];
        counts[data[i]] -= 1;
    }
    

    memcpy(data,temp,size * sizeof(int));
    free(counts);
    free(temp);

    return 0;
}

int main()
{
    int a[8] = {1,0,2,1,4,5,7,4};
    int max = a[0],
        i = 0;

    /*获得数组中中的数值*/
    for ( i = 1; i < 8; i++){
        if (a[i] > max)
            max = a[i];
    }

    ctsort(a,8,max+1);
    for (i = 0;i < 8;i ++)
        printf("%d\n",a[i]);
}

基数排序

     基数排序是另外一种高效的线性排序算法。其方法为将数据按位分开,并从数据的最低有效位到最高的有效位进行比较依次排序,从而得到有序的集合。我们来看一个简单的例子:{15,12,49,16,36,40};

在对个位进行排序之后,其结果是{40,12,15,16,36,49};

在对十位进行排序后,其结果是{12,15,16,36,40,49};

 有一点很重要就是必须保证在对每个位进行排序时,其排序过程必须是稳定的。也就是说,数据在进行较低位排序之后,此数据的位置不应该改变,除非进行较高位比较时需要对它进行调整。也就是例子中,个为排序后是 12 15 16 在进行十位排序时,十位都是1,这时,不应该对其进行调整。下面直接看代码吧,代码中对个位进行排序时,采用的上面的计数排序的算法,保证了排序过程的稳定性。

/*rxsort.c*/

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

/***************************************************************
 *用基数排序对十进制数进行排序
 *参数: data:数组元素  size:数组中元素的个数 
 *       p:元素中最大的位数; k :基数 (十,八,二,16,进制等等)
 *返回值 :成功0,失败-1;
 * 函数有运行结束后,已排序好的序列保存在data中
 **************************************************************/

int rxsort(int *data, int size, int p, int k)
{
    int * counts,/*计数数组*/
        * temp;/*临时保存排序后的数组*/
    int index,
        pval,
        i,
        j,
        n;

    /*申请空间*/
    if ((counts = (int *)malloc(k * sizeof(int))) == NULL)
        return -1;
    if ((temp = (int *)malloc(size * sizeof(int))) == NULL)
        return -1;
    /*从低位到高位分别进行排序*/
    for (n = 0; n < p; n++){
        /*计数数组初始化*/
        for ( i = 0; i < k; i ++)
            counts[i] = 0;
        /*计算当前位的基数*/
        pval = (int) pow((double )k, (double)n);
        

        /*下面的实现参数计数排序部分*/
        for (j = 0; j < size; j ++){
            index = (data[j]/pval)%pval;
            counts[index] += 1;
        }
        for (i = 1; i < k; i ++)
            counts[i] += counts[i - 1];

        for(j = size - 1; j >= 0; j --){
            index = (data[j]/pval)%pval;
            temp[counts[index] - 1] = data[j];
            counts[index] -= 1;
        }

        memcpy(data, temp, size *sizeof(int));
    }

    free(counts);
    free(temp);
    return 0;
}


int main()
{
    int a[20] = {20,300,40,5,80,12,500,43,23,56,121,33,444,555,666,112,456,234,123,124};
    int i = 0;

    rxsort(a,20,3,10);

    for (i = 0; i< 20; i++)
        printf ("a[%d] = %d\n",i,a[i]);
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值