内部排序->基数排序->链式基数排序

文字描述

  基数排序是和前面各类排序方法完全不相同,前面几篇文章介绍的排序算法的实现主要是通过关键字间的比较和移动记录这两种操作,而实现基数排序不需要进行记录关键字间的比较。基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法。先介绍下什么是多关键字排序,以引入链式基数排序算法。

  先介绍什么是多关键字排序:

  比如,对扑克牌进行排序,每张扑克牌有两个“关键字”:花色(梅花<方块<红桃<黑桃)和面值(2<3<,…,A),且“花色”的地位高于”面值”, 那么对扑克牌排序有两种方法:

  方法1:先按不同“花色”分成有次序的4堆,每一堆的”花色”相同; 然后分别对每一堆内部按”面值”大小整理有序。这种先对主键字字进行排序,再对次关键字排序的方法叫最高位优先法(简称MSD: Most Significant first)

  方法2:先按不同”面值”分成13堆,然后将13堆自小到大叠在一起(“3”在”2”之上,”4”在”3”之上,…,最上面的是4张”A”),然后将这幅牌整个颠倒过来再重新按不同花色分成4堆,最后将这4堆按自小到的次序合在一起(梅花在最下面,黑桃在最上面)。这种先对次键字字进行排序,再对主关键字排序的方法叫最低位优先法(简称LSD: Least Significant first)

  采用第二种方法LSD法对多关键字进行排序时,也可以不采用之前介绍的各种通过关键字间的比较来实现排序的方法,而是通过若干次“分配”和“收集”来实现排序。

  关于链式基数排序的介绍:

  采用多关键字排序中的LSD方法,先对低优先级关键字排序,再按照高点的优先级关键字排序,不过基数排序在排序过程中不需要经过关键字的比较,而是借助“分配”和“收集”两种操作对单逻辑关键字进行排序的一种内部排序方法。

  比如,若关键字是十进制表示的数字,且范围在[0,999]内,则可以把每一个十进制数字看成由三个关键字组成(K0, K1, K2),其中K0是百位数,K1是十位数,K2是个位数。基RADIX的取值为10; 按LSD进行排序,从最低位关键字起,按关键字的不同值将序列中记录“分配”到RADIX个队列中后再“收集”之,如此重复d次。按这种方法实现的排序称之为基数排序,以链表作存储结构的基数排序叫链式基数排序。

示意图

算法分析

  对n个记录(假设每个记录含d个关键字,每个关键字的取值范围为rd个值)进行链式基数排序的时间复杂度为d*(n+rd),其中每一躺分配的时间复杂度为n,每一躺收集的时间复杂度为rd,整个排序需进行d躺分配和收集。

  所需辅助空间为2*rd个队列指针,由于采用链表作存储结构,相对于其他采用顺序存储结构的排序方法而言,还增加了n个指针域的空间。

  链式基数排序是稳定的排序。

代码实现

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4
  5 #define DEBUG
  6
  7 #define EQ(a, b) ((a) == (b))
  8 #define LT(a, b) ((a) <  (b))
  9 #define LQ(a, b) ((a) <= (b))
 10
 11 //关键字项数的最大个数
 12 #define MAX_NUM_OF_KEY    8
 13 //关键字基数,此时是十进制整数的基数就是10
 14 #define RADIX            10
 15 //静态链表的最大长度
 16 #define MAX_SPACE        10000
 17
 18 //定义结点中的关键字类型为int
 19 typedef int KeyType;
 20 //定义结点中除关键字外的附件信息为char
 21 typedef char InfoType;
 22
 23 //静态链表的结点类型
 24 typedef struct{
 25     //关键字
 26     KeyType    keys[MAX_NUM_OF_KEY];
 27     //除关键字外的其他数据项
 28     InfoType otheritems;
 29     int next;
 30 }SLCell;
 31
 32 //静态链表类型
 33 typedef struct{
 34     //静态链表的可利用空间,r[0]为头结点
 35     SLCell r[MAX_SPACE];
 36     //每个记录的关键字个数
 37     int keynum;
 38     //静态链表的当前长度
 39     int recnum;
 40 }SLList;
 41
 42 //指针数组类型
 43 typedef int ArrType[RADIX];
 44
 45 void PrintSList(SLList L)
 46 {
 47     int i = 0;
 48     printf("下标值 ");
 49     for(i=0; i<=L.recnum; i++){
 50         printf(" %-6d", i);
 51     }
 52     printf("\n关键字 ");
 53     for(i=0; i<=L.recnum; i++){
 54         printf(" %-1d%-1d%-1d,%-2c", L.r[i].keys[2], L.r[i].keys[1], L.r[i].keys[0], L.r[i].otheritems);
 55     }
 56 //    printf("\n其他值 ");
 57 //    for(i=0; i<=L.recnum; i++){
 58 //        printf(" %-5c", L.r[i].otheritems);
 59 //    }
 60     printf("\n下一项 ");
 61     for(i=0; i<=L.recnum; i++){
 62         printf(" %-6d", L.r[i].next);
 63     }
 64     printf("\n");
 65     return;
 66 }
 67
 68 void PrintArr(ArrType arr, int size)
 69 {
 70     int i = 0;
 71     for(i=0; i<size; i++){
 72         printf("[%d]%-2d ", i, arr[i]);
 73     }
 74     printf("\n");
 75 }
 76
 77 /*
 78  *静态链表L的r域中记录已按(key[0],...,key[i-1])有序
 79  *本算法按第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的keys[i]相同。
 80  *f[0,...,RADIX-1]和e[0,...,RADIX-1]分别指向各子表中的第一个记录和最后一个记录。
 81  */
 82 void Distribute(SLCell *r, int i, ArrType f, ArrType e)
 83 {
 84     int j = 0;
 85     //各子表初始化为空
 86     for(j=0; j<RADIX; j++)
 87         f[j] = e[j] = 0;
 88
 89     int p = 0;
 90     for(p=r[0].next; p; p=r[p].next){
 91         j = r[p].keys[i];
 92         if(!f[j])
 93             f[j] = p;
 94         else
 95             r[e[j]].next = p;
 96         //将p所指的结点插入第j个字表中
 97         e[j] = p;
 98     }
 99 }
100
101 /*
102  * 本算法按keys[i]自小到大地将f[0,...,RADIX-1]所指各子表依次链接成一个链表
103  * e[0,...,RADIX-1]为各子表的尾指针
104  */
105 void Collect(SLCell *r, int i, ArrType f, ArrType e){
106     int j = 0, t = 0;
107     //找到第一个非空子表,
108     for(j=0; !f[j]; j++);
109     //r[0].next指向第一个非空子表的第一个结点
110     r[0].next = f[j];
111     //t指向第一个非空子表的最后结点
112     t = e[j];
113     while(j<RADIX){
114         //找下一个非空子表
115         for(j+=1; !f[j]; j++);
116         //链接两个非空子表
117         if(j<RADIX && f[j]){
118             r[t].next = f[j];
119             t = e[j];
120         }
121     }
122     //t指向最后一个非空子表中的最后一个结点
123     r[t].next = 0;
124 }
125
126 /*
127  * L是采用静态链表表示的顺序表。
128  * 对L作基数排序,使得L成为按关键字自小到大的有效静态链表,L->r[0]为头结点
129  */
130 void RadixSort(SLList *L)
131 {
132     int i = 0;
133     //将L改造成静态链表
134     for(i=0; i<L->recnum; i++)
135         L->r[i].next = i+1;
136     L->r[L->recnum].next = 0;
137 #ifdef DEBUG
138     printf("将L改造成静态链表\n");
139     PrintSList(*L);
140 #endif
141
142     ArrType f, e;
143     //按最低位优先依次对各关键字进行分配和收集
144     for(i=0; i<L->keynum; i++){
145         //第i趟分配
146         Distribute(L->r, i, f, e);
147 #ifdef DEBUG
148         printf("第%d趟分配---------------------------------------\n");
149         PrintSList(*L);
150         printf("头指针队列:");
151         PrintArr(f, RADIX);
152         printf("尾指针队列:");
153         PrintArr(e, RADIX);
154 #endif
155         //第i躺收集
156         Collect(L->r, i, f, e);
157 #ifdef DEBUG
158         printf("第%d趟收集----\n");
159         PrintSList(*L);
160         printf("按next打印:");
161         int p = 0;
162         for(p=L->r[0].next; p; p=L->r[p].next){
163             printf("%d%d%d ", L->r[p].keys[2], L->r[p].keys[1], L->r[p].keys[0]);
164         }
165         printf("\n");
166 #endif
167     }
168 }
169
170 int getRedFromStr(char str[], int i, SLCell *result)
171 {
172     int key = atoi(str);
173     if(key<0 || key >999){
174         printf("Error:too big!\n");
175         return -1;
176     }
177     int units = 0, tens = 0, huns = 0;
178     //百位
179     huns = key/100;
180     //十位
181     tens = (key-100*huns)/10;
182     //个位
183     units = (key-100*huns-10*tens)/1;
184     result->keys[0] = units;
185     result->keys[1] = tens;
186     result->keys[2] = huns;
187     result->otheritems = ‘a‘+i-1;
188     return 0;
189 }
190
191
192 int main(int argc, char *argv[])
193 {
194     SLList L;
195     int i = 0;
196     for(i=1; i<argc; i++){
197         if(i>MAX_SPACE)
198             break;
199         if(getRedFromStr(argv[i], i, &L.r[i]) < 0){
200             printf("Error:only 0-999!\n");
201             return -1;
202         }
203     }
204     L.keynum = 3;
205     L.recnum = i-1;
206     L.r[0].next = 0;
207     L.r[0].otheritems = ‘0‘;
208     RadixSort(&L);
209     return 0;
210 }

链式基数排序

运行

原文地址:https://www.cnblogs.com/aimmiao/p/9397464.html

时间: 2024-11-09 00:51:04

内部排序->基数排序->链式基数排序的相关文章

内部排序(五)基数排序

基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法.实现的过程不需要之前的所有排序所需要的记录关键字比较,移动等操作. 多关键字排序: 多关键字排序通常有两种方法: 1.MSD(Most Significant Digit)法,最高为优先法 2.LSD(Least Significant Digit)法,最低位优先法 过程借助分配,收集两种操作. 数组基数排序: 过程演示: 第一步 以LSD为例,假设原来有一串数值如下所示: 73, 22, 93, 43, 55, 14, 28,

链式基数排序收集的顺序有什么规律

okkq8b室瘴颊蕾簇恐<http://weibo.com/p209p688p/230927983167992529424384?yv20180413> 39798z裁橙僦庇剿料<http://weibo.com/p402p589p/230927983211814600839168?jy20180413> eaj76c猩莆税诶放吮<http://weibo.com/pnwp/230927983045771983069184> gs54z3放撼涡窘赐淘<http:/

10-12-顺序表地址排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第10章  内部排序 - 顺序表地址排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? SequenceListType.c        相关测试数据下载  链

算法 - 内部排序方法总结

各种排序方法的性能比较 排序方法 最好时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性 直接插入排序 O(n) O(n2) O(n2) O(1) 稳定 简单选择排序 O(n2) O(n2) O(n2) O(1) 不稳定 冒泡排序 O(n) O(n2) O(n2) O(1) 稳定 希尔排序 - O(n1.25) - O(1) 不稳定 快速排序 O(nlog2n) O(nlog2n) O(n2) O(log2n)~O(n) 不稳定 堆排序 O(nlog2n) O(nlog2n) O(n

10-11-基数排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第10章  内部排序 - 基数排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c        相关测试数据下载  链接? 数据

排序---内部排序算法(快排、希尔排序、归并排序、基数排序、冒泡、选择排序)比较

1.内部排序的复杂度总结 1)时间复杂度 4种排序的平均时间复杂度是O(nlog2n),"快些以nlog2n的速度归队"(快排.希尔排序.归并.堆排序) 最坏情况下,快排的时间复杂度为O(n*n) 2)空间复杂度 O(log2n)快排 O(n)归并 O(rd)基数 其他都是O(1) 3)稳定性 不稳定的:"考研复习痛苦啊,情绪不稳定,快些选一堆好友来聊天吧"(快排.希尔.简单选择排序.堆排序) 其他都是稳定的. 4)一趟排序,保证一个关键字到达最终位置 交换类(起泡

排序算法大全之基数排序

排序算法大全之--基数排序 基数排序是一种分配式排序,又成为桶子法排序 LSD(我们以最低位优先) 第一步:假设原有一串数字如下: 23,45,12,32,43 遍历这些数的个位数字,将他们分别装进编号为0到9的桶中 桶  0:为空,因为这些数中没有个位数为0的 桶  1:空 桶  2:12,32 桶  3:23,43 桶  4:空 桶  5:45 桶  6:空 桶  7:空 桶  8:空 桶  9:空 第二步 接下来将这些桶中的数据依次串起来,排成一排: 12,32,23,43,45 接下来,

排序算法七:基数排序(Radix sort)

上一篇提到了计数排序,它在输入序列元素的取值范围较小时,表现不俗.但是,现实生活中不总是满足这个条件,比如最大整形数据可以达到231-1,这样就存在2个问题: 1)因为m的值很大,不再满足m=O(n),计数排序的时间复杂也就不再是线性的: 2)当m很大时,为计数数组申请的内存空间会很大: 为解决这两个问题,本篇讨论基数排序(Radix sort),基数排列的思想是: 1)将先按照某个基数将输入序列的每个元素划分成若干部分,每个部分对排序结果的影响是有优先级的: 2)先按低优先级排序,再按高优先级

HDU3342 Legal or Not【拓扑排序】【链式前向星】

Legal or Not Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4633    Accepted Submission(s): 2115 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is