十大排序算法 之 基数排序

141 阅读2分钟

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

基数排序是一种非基于比较模式下对整数对象的排序算法。

思想:
的数字表达模式,可以按照二进制,十进制或者八进制,叫做基数。按照每一权位的数位,从lsd或者msd方式,分割为不同的区间,循环分割完全部的权位,就可以完成排序。

它的平均最好和最差时间复杂度是O(n*k),空间复杂度为O(k + N)。每个对象都经过分类,按照顺序再次复原,不出现相对对象位置交换的现象,所以算法是稳定的。

流程:
1.按照lsd方式,从最小的权位,按照申请基数申请额外空间,同一数值下可能会有几个待比较对象,此处可以使用链表保存数值。 2.按照1逻辑,比较更高权位。 3.遍历完成所有权位,从额外空间取回对象,排序完成。

代码示例:

#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)

typedef struct LL{
    struct LL *Next;
    int Val;
}NodeList;


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

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


void ClearList(NodeList * NodArr)
{
    NodeList * Temp = NULL;
    NodeList * NodePtr = NULL;
    for(int i = 0;i < 10; i++){
        NodePtr = NodArr[i].Next;
        NodArr[i].Next = NULL;
        while(NodePtr){
            Temp = NodePtr;
            NodePtr = NodePtr->Next;
            free(Temp);
        }
    }
}
int InsertNodeList(int Val,int tt,NodeList *NodePtr)
{
    NodeList * OneNode = (NodeList*)malloc(sizeof(NodeList));
    OneNode->Val = Val;
    OneNode->Next = NULL;
    while(NodePtr){
        if(NodePtr->Next == NULL){
            NodePtr->Next = OneNode;
            break;
        }
        NodePtr= NodePtr->Next;
    }
    return tt == 0?0:1;
}
int RadixSort(int cnt,int *Arr)
{
    fprintf(stdout,"RadixSort cnt:%d-\n",cnt);
    NodeList *Temp = NULL;
    NodeList BtVals[10];
    memset(BtVals,0,sizeof(NodeList)*10);
    int res = 1;
    int arrPos = 0;
    int fac = 1;      //位权
    while(res != 0){
        res = 0;
        for(int a = 0;a <cnt;a++){
            res +=InsertNodeList(Arr[a],Arr[a]/fac,&BtVals[Arr[a]/fac%10]);
        }
        fprintf(stdout," res:%d-\n",res);
        //把缓存数据全部还原去原空间
        arrPos = 0;
        for(int i = 0;i < 10; i++){
            Temp = (&BtVals[i])->Next;
            while(Temp){
                Arr[arrPos] = Temp->Val;
                arrPos++;
                Temp= Temp->Next;
            }
        }
        ClearList(BtVals);
        fac *=10;
    }
    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[Radix Sort]inputNum:");
    PrintNums();
    fprintf(stdout,"\n");

    RadixSort(ArrCnt,NumArr);

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

}

测试结果: image.png

数据结构使用了 桶排序中声明的链表结构,结构简单,使用方便。
接口上声明了两个,一个用来插入对象,一个用来清空申请的空间。并且再每次循环主动记录是否已经解析过全部权位。
使用lsd模式,从低权位遍历查找到高权位。
代码可以直接编译使用,有兴趣可以复制出来,加加日志,感受一下过程。 这个和桶排序思想一致,只是桶的实现方案不一样,写的匆忙,如有错误,请联系我。