基数排序 顺序实现与链式实现

最近数据结构刚刚讲完了基数排序,以下我的一些见解:

大多数的排序都是通过比较数据大小的方法对待排数据序列进行排序整理过程。

而基数排序却很另类,那么,基数排序是采用怎样的策略进行排序的呢?

简要概括一下:基数排序是通过“分配”和“收集”两个过程来实现排序的。

而这个思想该如何理解呢?请看以下例子:

(1)有以下待排序列

309 385 867 183 341 605 385

(2)第一次分配和收集:

首先按照各个数据的个位数字(即按照9,5,7,3,1,5,5)分配到0-9的10个区间内

结果如下:

分配结束后。接下来将所有空间中的数据按照序号由小到大依次重新收集起来,得到如下仍然无序的数据序列:

(3)第二次分配和收集:

 这次按照十位数字进行分配,步骤同上

结果如下:

分配结束后。接下来将所有空间中的数据按照序号由小到大依次再次收集起来,得到如下仍然无序的数据序列:

 

(4)第三次分配和收集:

 这次按照百位数字进行分配,步骤同上

结果如下:

分配结束后。接下来将所有空间中的数据按照序号由小到大依次再次收集起来;

哎?!停一下!奇怪,数据竟然有序了!

当然,数据分别按照个,十,百位依次排序后自然是有序的,至于为什么,我相信细心的读者已经想明白了。

 

下面介绍一下对上面所说的基数排序算法做一些补充:

(1)如果数据大小更大,则需按照上面的思路继续排序(比如排序到千位,万位.....),排序的次数就是待排数据中最大数字的位数;

(2)上面的分析是说的数字的排序,如果要对等长的字符串集合排序,则各个空间的关键字由0-9变为‘a’-‘z’;

(3)基数排序是稳定的,而且看起来似乎在时间代价上很好,但实际并非如此,它在记录数较关键字大得多的情况下比较有效,还有一个缺点是:它对一些数据类型来说是难于实现的,如对实型或不等长的字串。

下面再思考一个问题:既然我们可以从最低位到最高位进行如此的分配收集,那么是否可以由最高位到最低位依次操作呢? 答案是完全可以的。

基于两种不同的排序顺序,我们将基数排序分为LSD(Least significant digital)或MSD(Most significant digital),

LSD的排序方式由数值的最右边(低位)开始,而MSD则相反,由数值的最左边(高位)开始。

注意一点:LSD的基数排序适用于位数少的数列,如果位数多的话,使用MSD的效率会比较好。

下面给出算法实现代码:

链式实现:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 const int maxn=100000+10;
 5 const int Radix=20;
 6 typedef struct
 7 {
 8     int next;
 9     int key;
10 }SLNode;
11 typedef struct
12 {
13     SLNode r[maxn];
14     int length;
15 }SLList;
16 typedef int ArrType[Radix];
17 ArrType f,e;
18 int Ord(int k,int j)
19 {
20     for(int i=1;i<j;i++)
21         k/=10;
22     k%=10;
23     return k+10;
24 }
25 void Print_L(SLList L)
26 {
27     int mrk=0;
28     for(int p=L.r[0].next;p;p=L.r[p].next)
29     {
30         if(mrk)
31             printf(" ");
32         printf("%d",L.r[p].key);
33         mrk=1;
34     }
35     printf("\n");
36 }
37 void Distribute(SLList &L,int i,ArrType &f,ArrType &e)
38 {
39     //printf("i=%d\n",i);
40     for(int i=0;i<Radix;i++)
41         f[i]=0;
42     //for(int p=L.r[0].next;p!=0;p=L.r[p].next)
43     for(int p=L.r[0].next;p;p=L.r[p].next)
44     {
45         int k=Ord(L.r[p].key,i);
46         //printf("%d\n",k);
47         if(f[k]==0)
48         {
49             f[k]=e[k]=p;
50         }
51         else
52         {
53             L.r[e[k]].next=p;
54             e[k]=p;
55         }
56     }
57 }
58 void Collect(SLList &L,int i,ArrType &f,ArrType &e)
59 {
60     int j=0;
61     while(f[j]==0)
62         j++;
63     L.r[0].next=f[j];
64     int tail=e[j];
65     while(j<Radix)
66     {
67         j++;
68         while(j<Radix&&f[j]==0)
69             j++;
70         L.r[tail].next=f[j];
71         tail=e[j];
72     }
73 }
74 void RadixSort(SLList &L)
75 {
76     for(int i=1;i<=6;i++)//待排数据中最大值的位数,可根据实际需要变化
77     {
78         Distribute(L,i,f,e);
79         Collect(L,i,f,e);
80     }
81 }
82 
83 int main()
84 {
85     int n;
86     scanf("%d",&n);
87     SLList L;
88     L.length=n;
89     L.r[0].next=1;
90     for(int i=1;i<=n;i++)
91     {
92         scanf("%d",&L.r[i].key);
93         L.r[i].next=i+1;
94     }
95     L.r[n].next=0;
96     RadixSort(L);
97     Print_L(L);
98     return 0;
99 }
View Code

链式时间复杂度: 

顺序实现:

  1 //库函数头文件包含
  2 #include<stdio.h>
  3 #include<malloc.h>
  4 #include<stdlib.h>
  5 
  6 
  7 //函数状态码定义
  8 #define TRUE        1
  9 #define FALSE       0
 10 #define OK          1
 11 #define ERROR       0
 12 #define INFEASIBLE -1
 13 #define OVERFLOW   -2
 14 #define Radix      10
 15 #define maxn       100010
 16 typedef int  Status;
 17 typedef int QElemType;
 18 
 19 typedef struct QNode
 20 {
 21     QElemType data;
 22     struct QNode *next;
 23 }QNode, *QueuePtr;
 24 
 25 typedef struct
 26 {
 27     QueuePtr front;
 28     QueuePtr rear;
 29 }LinkQueue;
 30 
 31 Status InitQueue(LinkQueue &Q)
 32 {
 33     Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
 34     if(!Q.front)
 35         exit(OVERFLOW);
 36     Q.front->next=NULL;
 37     return OK;
 38 }
 39 Status DestroyQueue(LinkQueue &Q)
 40 {
 41     while(Q.front)
 42     {
 43         Q.rear=Q.front->next;
 44         free(Q.front);
 45         Q.front=Q.rear;
 46     }
 47     return OK;
 48 }
 49 Status EnQueue(LinkQueue &Q,QElemType e)
 50 {
 51     QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
 52     if(!p)
 53         exit(OVERFLOW);
 54     p->data=e;
 55     p->next=NULL;
 56     Q.rear->next=p;
 57     Q.rear=p;
 58     return OK;
 59 }
 60 Status DeQueue(LinkQueue &Q,QElemType &e)
 61 {
 62     if(Q.front==Q.rear)
 63         return ERROR;
 64     QueuePtr p=Q.front->next;
 65     e=p->data;
 66     Q.front->next=p->next;
 67     if(Q.rear==p)
 68         Q.rear=Q.front;
 69     free(p);
 70     return OK;
 71 }
 72 Status QueueEmpty(LinkQueue Q)
 73 {
 74     if(Q.front==Q.rear)
 75         return TRUE;
 76     else
 77         return FALSE;
 78 }
 79 typedef struct
 80 {
 81     int key;
 82 }SLNode;
 83 typedef struct
 84 {
 85     SLNode r[maxn];
 86     int length;
 87 }SLList;
 88 LinkQueue B[Radix];
 89 int Ord(int k,int j)
 90 {
 91     for(int i=1;i<j;i++)
 92         k/=10;
 93     k%=10;
 94     return k;
 95 }
 96 void Print_L(SLList L)
 97 {
 98     int mrk=0;
 99     for(int p=1;p<=L.length;p++)
100     {
101         if(mrk)
102             printf(" ");
103         printf("%d",L.r[p].key);
104         mrk=1;
105     }
106     printf("\n");
107 }
108 void Distribute(SLList &L,int i)
109 {
110     for(int j=1;j<=L.length;j++)
111     {
112         int k=Ord(L.r[j].key,i);
113         EnQueue(B[k],L.r[j].key);
114     }
115 }
116 void Collect(SLList &L)
117 {
118     int i=1;
119     for(int j=1;j<Radix;j++)
120     {
121         while(!QueueEmpty(B[j]))
122             DeQueue(B[j],L.r[i++].key);
123     }
124 }
125 void RadixSort(SLList &L)
126 {
127     for(int i=0;i<Radix;i++)
128     {
129         InitQueue(B[i]);
130     }
131     for(int i=1;i<=6;i++)   //最高位数为6,可根据实际变化
132     {
133         Distribute(L,i);
134         Collect(L);
135     }
136 }
137 int main()
138 {
139     int n;
140     scanf("%d",&n);
141     SLList L;
142     L.length=n;
143     for(int i=1;i<=n;i++)
144     {
145         scanf("%d",&L.r[i].key);
146     }
147     RadixSort(L);
148     Print_L(L);
149     return 0;
150 }
View Code

顺序时间复杂度:

 

(由于我们所用教材为严蔚敏老师编写的,所以代码风格接近,也易于读懂。

 

坚持不懈地努力才能成为大神!

posted @ 2017-11-30 22:34  己平事  阅读(4200)  评论(1编辑  收藏  举报