第5章 排序 —— 5.1 基数排序

来源:互联网 发布:身份证nfc读取 软件 编辑:程序博客网 时间:2024/06/15 13:52

下面代码给出了按次位优先法进行基数排序的算法实现。
这里假设元素最多有MaxDigit个关键字,基数同样是Radix。
我们用桶B承载分配的记录,再用链List进行收集。
函数GetDigit的作用是返回整型关键字X的第D位数字,次位优先从D=1开始。

/* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */#define MaxDigit 4#define Radix 10/* 桶元素结点 */typedef struct Node * PtrToNode;struct Node{    int key;    PtrToNode next;}/* 桶头结点 */struct HeadNode{    PtrToNode head, tail;};typedef struct HeadNode Bucket[Radix];int Getdigit(int X, int D){/* 默认次位D = 1, 主位D <= MaxDigit */    int d, i;    for(i = 1; i <= D; i++){        d = X % Radix;        X /= Radix;    }    return d;}void LSDRadixSort(ElementType A[], int N){/* 基数排序-次位优先 */    int D, Di, i;    Bucket B;    PtrToNode tmp, p, List = NULL;    for(i = 0; i < Radix; i++)/* 初始化每个桶为空链表 */        B[i].head = B[i].tail = NULL;    for(i = 0; i < N; i++){/* 将原始序列逆序存入初始链表List */        tmp = (PtrToNode)malloc(sizeof(struct Node));        tmp->key = A[i];        tmp->next = List;        List = tmp;    }    /* 下面开始排序 */    for(D = 1; D <= MaxDigit; D++){/* 对数据的每一位循环处理 */        /* 下面是分配的过程 */        p = List;        while(p){            Di = Getdigit(p->key, D);/* 获得当前元素的当前位数字 */            /* 从List中摘除 */            tmp = p; p = p->next;            /* 插入B[Di]号桶尾 */            tmp->next = NULL;            if(B[Di].head == NULL)                B[Di].head = B[Di].tail = tmp;            else{                B[Di].tail->next = tmp;                B[Di].tail = tmp;            }        }        /* 下面是收集的过程 */        List = NULL;        for(Di = Radix-1; Di >= 0; Di--){/* 将每个桶的元素顺序收集入List */            if(B[Di].head){/* 如果桶不为空 */                /* 整桶插入List表头 */                B[Di].tail->next = List;                List = B[Di].head;                B[Di].head = B[Di].tail = NULL;/* 清空桶 */            }        }    }    /* 将List倒入A[]并释放空间 */    for(i = 0; i < N; i++){        tmp = List;        List = List->next;        A[i] = tmp->key;        free(tmp);    }}

分析:

  • 时间复杂度:对N个关键字用R个桶进行基数排序时,其时间复杂度为O(D(N+R)),其中D为分配收集的趟数,也就是关键字按基数分解后的位数。
  • 基数排序的好处:用链表实现,不需要将记录进行物理移动,对于大型纪录的排序是有利的,代价是需要O(N)额外空间存放指针。
  • 基数排序的效率与基数的选择密切相关。
  • 基数排序是稳定的排序方法。
原创粉丝点击