十大排序算法 之 计数排序

77 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

计数排序: 计数排序属于非比较类型的排序算法。

它的排序思想是申请一个额外的空间保存待排序序列的数值(最大最小值)可容纳的空间,待排序序列一一对应到这个空间中,将值转换为空间的索引值,也就是说待排序的对象值只能是整数,且有确定范围。它的时间复杂度比较小,O(n+k),空间复杂度占用的比较大为O(n+k)。

排序流程:

  1. 扫描得到待排序序列中的最大最小值 :m M,然后申请M-m+1大小的一个空间C;
  2. 把待排序序列的值对应到C相应的位置中,同时进行计数,直至完成待排序序列的全部对象;
  3. 再把c中数值返回交换到原空间中去,排序完成。

代码实例:

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

#define SWAP(a1, a2, type) do {type tempNoI = a1; a1 = a2; a2 = tempNoI;} while(0)



int ArrCnt = 0;
int NumArr[200] = {0};

void PrintNums()
{
    for(int i = 0;i < ArrCnt;i++){
        fprintf(stdout," %d-",NumArr[i]);
    }
}

//升序排序
int CountSort(int Cnt,int* ArrPtr)
{
    int i = 0;
    int MinVal = ArrPtr[0];
    int MaxVal = ArrPtr[0];

    for(i = 1;i < Cnt;i++){
        if(ArrPtr[i] < MinVal) MinVal= ArrPtr[i];
        if(MaxVal < ArrPtr[i]) MaxVal= ArrPtr[i];
    }
    fprintf(stderr,"申请额外空间大小:%d\n",MaxVal - MinVal+1);
    int  *C = (int*)malloc(4*(MaxVal-MinVal+1));
    memset(C,0,4*(MaxVal-MinVal+1));
    for(i = 0;i < Cnt;i++){
        C[ArrPtr[i] -MinVal]++;
        fprintf(stderr,"space [%d]=[%d]\n",ArrPtr[i] -MinVal,C[ArrPtr[i] -MinVal]);
    }
    int Js = 0;
    for(i = 0;i < Cnt;i++){
        while(C[Js] == 0){
            Js++;
        }
        if(C[Js] > 0) {
            ArrPtr[i] = MinVal+Js;
            C[Js]--;
        }
    }

    return 0;
}
int main(int argc, char** argv)
{
    if(argc == 1) {
        fprintf(stderr,"%s:need a some arg\n",argv[0]);
        exit(1);
    }
    int CntTemp = ArrCnt = argc -1;

    for(int i = 0;i < ArrCnt;i++){
        NumArr[i] = atoi(argv[i+1]);
    }
   
    fprintf(stdout,"\t\t\t\t[Heap Sort]inputNum:");
    PrintNums();
    fprintf(stdout,"\n");

    CountSort(ArrCnt,NumArr);

    fprintf(stdout,"\n\t\t\t\tresult:");
    PrintNums();
    fprintf(stdout,"\n");
    return 0;

}

测试结果如下:

image.png

计数排序比较简单粗暴,效率较快,额外占用空间较大,可排序的数据类型受限制。小范围数据排序使用比较好一点,不会造成较大的系统内存增长。