首页 > 代码库 > 计数排序(C语言版)

计数排序(C语言版)

先说说计数排序的思想

计数排序假定待排序的所有元素都是介于0到K之间的整数;计数排序使用一个额外的数组countArray,其中第i个元素是待排序数组array中值等于i的元素的个数。然后根据数组countArray来将array中的元素排到正确的位置。

 算法的步骤如下:

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组countArray的第i
  3. 对所有的计数累加(从countArray中的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第countArray[i]项,每放一个元素就将countArray[i]减去1

稳定性和复杂度:

计数排序是稳定的排序算法;平局时间复杂度、最优时间复杂度和最差时间复杂度都为O(n+k),空间复杂度为O(n+k),其中,n为待排元素个数,k为待排元素的范围(0~k)。

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

#define RANDMAX 10000

void getRandArray(int array[], int size);
void countSort(int array[], int size);
void isSorted(int array[], int size);

int main(int argc, char const *argv[])
{
    int size = 0;
    scanf("%d", &size);
    assert(size > 0);

    int *array = (int *)calloc(size, sizeof(int));
    getRandArray(array, size);

    clock_t begin;
    clock_t end;

    begin = clock();
    countSort(array, size);
    end = clock();
    //打印排序所花费的时间,在linux下单位为ms
    printf("%ld\n", (end - begin) / 1000);
    
    isSorted(array, size);
    free(array);

    return 0;
}


//利用伪随机数填充数组array
void getRandArray(int array[], int size)
{
    assert(array != NULL && size > 0);

    srand((unsigned) time(NULL));
    int i = 0;
    for (i = 0; i < size; ++i) {
        //产生RANDMAX以内的伪随机数
        array[i] = rand() % RANDMAX;
    }
}

//从小到大进行排序
void countSort(int array[], int size)
{
    assert(array != NULL && size > 0);

    //计数数组,用于统计数组array中各个不同数出现的次数
    //由于数组array中的数属于0...RANDMAX-1之间,所以countArray的大小要够容纳RANDMAX个int型的值
    int *countArray = (int *) calloc(RANDMAX, sizeof(int));
    //用于存放已经有序的数列
    int *sortedArray = (int *) calloc(size, sizeof(int));

    //统计数组array中各个不同数出现的次数,循环结束后countArray[i]表示数值i在array中出现的次数
    int index = 0;
    for (index = 0; index < size; ++index) {
        countArray[array[index]]++;
    }

    //统计数值比index小的数的个数,循环结束之后countArray[i]表示array中小于等于数值i的元素个数
    for (index = 1; index < RANDMAX; ++index) {
        countArray[index] += countArray[index - 1];
    }

    for (index = size - 1; index >= 0; --index) {
        //因为数组的起始下标为0,所以要减一
        sortedArray[countArray[array[index]] - 1] = array[index];
        //这里减一是为了保证当有多个值为array[index]的元素时,后出现的值为array[index]的元素
        //放在后面,也就是为了保证排序的稳定性
        --countArray[array[index]];
    }

    memcpy(array, sortedArray, size * sizeof(int));
    free(sortedArray);
    free(countArray);
}

//判断数组array是否已经是有序的
void isSorted(int array[], int size)
{
    assert(array != NULL && size > 0);

    int unsorted = 0;
    int i = 0;
    for (i = 1; i < size; ++i) {
        if (array[i] < array[i - 1]) {
            unsorted = 1;
            break;
        }
    }

    if (unsorted) {
        printf("the array is unsorted!\n");
    } else {
        printf("the array is sorted!\n");
    }
}
计数排序是非比较的排序算法,据说其排序速度要快于任何的比较排序算法(我还未验证,但是在排序100000000个10000以内的数时花费为606毫秒,而C语言的qsort函数则为10802毫秒,由此可见一斑),由于计数排序需要一个计数数组以及一个存放有序数列的数组,故计数排序对内存的要求比较高。

计数排序(C语言版)