代码改变世界

基数排序

2013-09-01 20:48  youxin  阅读(1841)  评论(0编辑  收藏  举报

基数排序英语Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼打孔卡片制表机(Tabulation Machine)上的贡献[1]

它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

wikipedia百科定义:

Each key is first figuratively dropped into one level of buckets corresponding to the value of the rightmost digit. Each bucket preserves the original order of the keys as the keys are dropped into the bucket. There is a one-to-one correspondence between the number of buckets and the number of values that can be represented by a digit. Then, the process repeats with the next neighboring digit until there are no more digits to process. In other words:

  1. Take the least significant digit (or group of bits, both being examples of radices) of each key.
  2. Group the keys based on that digit, but otherwise keep the original order of keys. (This is what makes the LSD radix sort a stable sort).
  3. Repeat the grouping process with each more significant digit.

The sort in step 2 is usually done using bucket sort or counting sort, which are efficient in this case since there are usually only a small number of digits.

http://en.wikipedia.org/wiki/Radix_sort

 

(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。

第一步

以LSD为例,假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39

第二步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93

第三步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。
 

对于这个算法最重要的是按位排序时要稳定。如果不稳定会导致,本来低一位的顺序已经排好,但是因为按位排序不稳定,使得对于同一位理,相同的值原来的按低一位的顺序改了,导致不正确。

证明:给定n个d位数,每一位数有k种可能性。如果一次稳定排序需要Θ(n+k)时间,那么总的时间就为Θ(d(n+k))。

基数排序的时间代价分析取决于稳定的中间排序算法。当每一位数字都介于0到k-1之间,而且k不大的时候,可以选择计数排序。n个d位数每一次中间排序的时间为Θ(n+k),总共有d次,总运行时间为Θ(d(n+k))。

当d为常数,k = O(n)时,基数排序有线性运行时间。

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

void radix_sort(int A[], int d, int length);

int get_d(int x);

int main(){
    int num, i;
    printf("Input the number:\n");
    scanf("%d", &num);
    int *array =(int *) malloc((num + 1) * sizeof(int));
    int d = 0; 
    printf("Input the element:");
    for(i = 1; i <= num; i++){
        scanf("%d", &array[i]);
        if(d < get_d(array[i]))
            d = get_d(array[i]);
    }

    radix_sort(array, d, num);
    for(i = 1; i <= num; i++)
        printf("%d ", array[i]);
    printf("\n");
    return 0;
}

int get_d(int x){
    int count = 0;
    while(x / 10 != 0 || x % 10 != 0){
        x /= 10;
        count++;
    }
    return count;
}

void radix_sort(int A[], int d, int length){
    int *B = (int *)malloc((length + 1) * sizeof(int));
    int *C = (int *)malloc(10 * sizeof(int));

    int i, j, k, temp;
    int radix = 1;
    for(i = 1; i <= d; i++){
            for(j = 0; j < 10; j++)
                C[j] = 0;
            for(k = 1; k <= length; k++){
                temp = (A[k] / radix) % 10;
                C[temp]++;
            }

            for(j = 1; j < 10; j++)
                C[j] += C[j-1];
            
            for(k = length; k >= 1; k--){
                temp = (A[k] / radix) % 10;
                B[C[temp]] = A[k];
                C[temp]--;
            }
            radix *= 10;
            memcpy(A, B, (length + 1) * sizeof(int));
               
    }
}

更多:http://www.cnblogs.com/lpshou/archive/2012/06/18/2553370.html