基数排序(桶排序) 不同方法
Posted congmingyige
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基数排序(桶排序) 不同方法相关的知识,希望对你有一定的参考价值。
详细解释:算法导论/数据结构书
1.链式基数排序
//n个数,每个数有g个关键字
//排序:从最后的关键字开始到最前的关键字
//分配+收集
//每个关键字分配+收集需要n+n时间,而共有g个关键字,时间复杂度为O(2ng),效率很高。
//如果用数组,数据集中在一个区间,则区间的长度很长,另外的区间的内存浪费了。
//用链表可以解决这个问题,且数据不需要先后顺序,所以无必要非要用数组
1 #include <stdio.h> 2 #include <stdlib.h> 3 //个数 4 #define maxn 1000 5 //数的范围 x~y 6 #define x 0 7 #define y 9 8 //关键字个数 9 #define g 3 10 11 //n个数,每个数有g个关键字 12 //排序:从最后的关键字开始到最前的关键字 13 //分配+收集 14 //每个关键字分配+收集需要n+n时间,而共有g个关键字,时间复杂度为O(2ng),效率很高。 15 //如果用数组,数据集中在一个区间,则区间的长度很长,另外的区间的内存浪费了。 16 //用链表可以解决这个问题,且数据不需要先后顺序,所以无必要非要用数组 17 18 struct node 19 { 20 //关键字的值 21 long key[g+1]; 22 }data[maxn+1]; 23 //next:下一个数的编号 24 //front,rear:一个链表的首,尾数据的编号 25 long next[maxn+1],front[y-x+1],rear[y-x+1]; 26 27 int main() 28 { 29 long n,i,j,head,pos,value,t; 30 scanf("%ld",&n); 31 for (i=1;i<=n;i++) 32 for (j=1;j<=g;j++) 33 scanf("%ld",&data[i].key[j]); 34 for (i=1;i<n;i++) 35 next[i]=i+1; 36 next[n]=0; 37 head=1; 38 //key i 39 for (i=g;i>=1;i--) 40 { 41 //值为j的链表的首地址,0代表j链表没有元素 42 for (j=x;j<=y;j++) 43 front[j]=0; 44 pos=head; 45 ///分配 46 while (pos) 47 { 48 //把一个数添加到value链表的末尾 49 value=data[pos].key[i]; 50 //如果原来value链表有元素,则原来value链表的末尾元素的后继为第pos个数 51 //如果原来value链表没有元素,则value链表的起始元素为第pos个数 52 if (front[value]!=0) 53 next[rear[value]]=pos; 54 else 55 front[value]=pos; 56 //当前value链表的末尾元素为第pos个数 57 rear[value]=pos; 58 pos=next[pos]; 59 } 60 ///收集 61 //把x链表,x+1链表,……,y链表 连接起来,而k链表的最后一个元素的后继为k+1链表的第一个元素 62 value=x; 63 while (front[value]==0) 64 value++; 65 head=front[value]; 66 while (value<=y) 67 { 68 t=value+1; 69 while (front[t]==0 && t<=y) 70 t++; 71 if (t==y+1) 72 break; 73 next[rear[value]]=front[t]; 74 value=t; 75 } 76 next[rear[value]]=0; 77 } 78 printf("\n"); 79 pos=head; 80 while (pos) 81 { 82 for (i=1;i<=g;i++) 83 printf("%ld ",data[pos].key[i]); 84 printf("\n"); 85 pos=next[pos]; 86 } 87 return 0; 88 } 89 /* 90 input: 91 10 92 1 1 2 93 9 7 9 94 3 8 5 95 1 3 3 96 5 4 3 97 6 8 5 98 2 1 3 99 1 4 5 100 9 1 1 101 5 1 3 102 output: 103 1 1 2 104 1 3 3 105 1 4 5 106 2 1 3 107 3 8 5 108 5 1 3 109 5 4 3 110 6 8 5 111 9 1 1 112 9 7 9 113 */
2.基数排序+排序
//n个数,每个数有g个关键字
//可以在一次基数排序(桶排序)后,结合其它排序
//适用于:2~3个关键字,第一个关键字的范围较大,且分布较为分散,
//通过第一个关键字把数分成若干个区间后,区间的大小较小,从而每个区间的排序时间也较小
1 #include <stdio.h> 2 #include <stdlib.h> 3 //个数 4 #define maxn 1000 5 //数的范围 x~y 6 #define x 0 7 #define y 9 8 //关键字个数 9 #define g 3 10 11 //n个数,每个数有g个关键字 12 //可以在一次基数排序(桶排序)后,结合其它排序 13 //适用于:2~3个关键字,第一个关键字的范围较大,且分布较为分散, 14 //通过第一个关键字把数分成若干个区间后,区间的大小较小,从而每个区间的排序时间也较小 15 16 struct node 17 { 18 //关键字的值 19 long key[g+1]; 20 }data[maxn+1],f[maxn+1]; 21 //next:下一个数的编号 22 //front,rear:一个链表的首,尾数据的编号 23 long next[maxn+1],front[y-x+1],rear[y-x+1]; 24 25 void qsort_(long l,long r) 26 { 27 long i,j,p,q; 28 struct node t; 29 i=l; j=r; p=f[(l+r)>>1].key[2]; q=f[(l+r)>>1].key[3]; 30 while (i<=j) 31 { 32 while (f[i].key[2]<p || (f[i].key[2]==p && f[i].key[3]<q)) i++; 33 while (f[j].key[2]>p || (f[j].key[2]==p && f[j].key[3]>q)) j--; 34 if (i<=j) 35 { 36 t=f[i]; 37 f[i]=f[j]; 38 f[j]=t; 39 i++; 40 j--; 41 } 42 } 43 if (i<r) qsort_(i,r); 44 if (j>l) qsort_(l,j); 45 } 46 47 int main() 48 { 49 long n,i,j,head,pos,value,b; 50 scanf("%ld",&n); 51 for (i=1;i<=n;i++) 52 for (j=1;j<=g;j++) 53 scanf("%ld",&data[i].key[j]); 54 for (i=1;i<n;i++) 55 next[i]=i+1; 56 next[n]=0; 57 head=1; 58 ///key 1 59 60 //值为j的链表的首地址,0代表j链表没有元素 61 for (j=x;j<=y;j++) 62 front[j]=0; 63 pos=head; 64 ///分配 65 while (pos) 66 { 67 //把一个数添加到value链表的末尾 68 value=data[pos].key[1]; 69 //如果原来value链表有元素,则原来value链表的末尾元素的后继为第pos个数 70 //如果原来value链表没有元素,则value链表的起始元素为第pos个数 71 if (front[value]!=0) 72 next[rear[value]]=pos; 73 else 74 front[value]=pos; 75 //当前value链表的末尾元素为第pos个数 76 rear[value]=pos; 77 pos=next[pos]; 78 } 79 ///收集 80 printf("\n"); 81 j=0; 82 for (i=x;i<=y;i++) 83 if (front[i]!=0) 84 { 85 b=j+1; 86 pos=front[i]; 87 while (pos!=rear[i]) 88 { 89 j++; 90 f[j]=data[pos]; 91 pos=next[pos]; 92 } 93 j++; 94 f[j]=data[pos]; 95 qsort_(b,j); 96 } 97 for (i=1;i<=n;i++) 98 { 99 for (j=1;j<=g;j++) 100 printf("%ld ",f[i].key[j]); 101 printf("\n"); 102 } 103 return 0; 104 } 105 /* 106 input: 107 10 108 1 1 2 109 9 7 9 110 3 8 5 111 1 3 3 112 5 4 3 113 6 8 5 114 2 1 3 115 1 4 5 116 9 1 1 117 5 1 3 118 output: 119 1 1 2 120 1 3 3 121 1 4 5 122 2 1 3 123 3 8 5 124 5 1 3 125 5 4 3 126 6 8 5 127 9 1 1 128 9 7 9 129 */
3.从前到后依次对关键字排序(不推荐)
//n个数,每个数有g个关键字
//如果从最前的关键字开始到最后的关键字排序,则需要sort(p,q,w) data[x]~data[y]排第w个关键字,
//然后延伸出sort(s,t,w+1) [p<=s<=t<=q]
//该方法耗费大量时间和内存,不推荐
1 #include <stdio.h> 2 #include <stdlib.h> 3 //个数 4 #define maxn 1000 5 //数的范围 x~y 6 #define x 0 7 #define y 9 8 //关键字个数 9 #define g 3 10 11 //n个数,每个数有g个关键字 12 //如果从最前的关键字开始到最后的关键字排序,则需要sort(p,q,w) data[x]~data[y]排第w个关键字, 13 //然后延伸出sort(s,t,w+1) [p<=s<=t<=q] 14 //该方法耗费大量时间和内存,不推荐 15 16 struct node 17 { 18 //关键字的值 19 long key[g+1]; 20 }data[maxn+1],f[maxn+1]; 21 //next:下一个数的编号 22 //front,rear:一个链表的首,尾数据的编号 23 24 void sort(long p,long q,long w) 25 { 26 long i,j,head,pos,value,next[maxn+1],front[y-x+1],rear[y-x+1],b[y+1],e[y+1]; 27 for (i=p;i<q;i++) 28 next[i]=i+1; 29 next[q]=0; 30 head=p; 31 //值为j的链表的首地址,0代表j链表没有元素 32 for (j=x;j<=y;j++) 33 front[j]=0; 34 pos=head; 35 ///分配 36 while (pos) 37 { 38 //把一个数添加到value链表的末尾 39 value=data[pos].key[w]; 40 //如果原来value链表有元素,则原来value链表的末尾元素的后继为第pos个数 41 //如果原来value链表没有元素,则value链表的起始元素为第pos个数 42 if (front[value]!=0) 43 next[rear[value]]=pos; 44 else 45 front[value]=pos; 46 //当前value链表的末尾元素为第pos个数 47 rear[value]=pos; 48 pos=next[pos]; 49 } 50 ///收集 51 for (i=p;i<=q;i++) 52 f[i]=data[i]; 53 j=p-1; 54 for (i=x;i<=y;i++) 55 if (front[i]!=0) 56 { 57 b[i]=j+1; 58 pos=front[i]; 59 while (pos!=rear[i]) 60 { 61 j++; 62 data[j]=f[pos]; 63 pos=next[pos]; 64 } 65 j++; 66 data[j]=f[pos]; 67 e[i]=j; 68 } 69 if (w!=g) 70 { 71 for (i=x;i<=y;i++) 72 //没有数或者只有1个数就不用排了 73 if (front[i]!=0 && b[i]!=e[i]) 74 sort(b[i],e[i],w+1); 75 } 76 } 77 78 int main() 79 { 80 long i,j,n; 81 scanf("%ld",&n); 82 for (i=1;i<=n;i++) 83 for (j=1;j<=g;j++) 84 scanf("%ld",&data[i].key[j]); 85 sort(1,n,1); 86 printf("\n"); 87 for (i=1;i<=n;i++) 88 { 89 for (j=1;j<=g;j++) 90 printf("%ld ",data[i].key[j]); 91 printf("\n"); 92 } 93 return 0; 94 } 95 /* 96 input: 97 10 98 1 1 2 99 9 7 9 100 3 8 5 101 1 3 3 102 5 4 3 103 6 8 5 104 2 1 3 105 1 4 5 106 9 1 1 107 5 1 3 108 output: 109 1 1 2 110 1 3 3 111 1 4 5 112 2 1 3 113 3 8 5 114 5 1 3 115 5 4 3 116 6 8 5 117 9 1 1 118 9 7 9 119 */
题目:
题目13基数排序的实现(学时:3)
A为每个关键字不超过3位的十进制整数关键字集合,试编写一个采用静态链表组织模式实现的基数排序程序将A进行由小到大的排序。
1 #include <stdio.h> 2 #include <stdlib.h> 3 //个数 4 #define maxn 1000 5 //数的范围 x~y 6 #define x 0 7 #define y 9 8 //关键字个数 9 #define g 3 10 11 //n个数,每个数有g个关键字 12 //排序:从最后的关键字开始到最前的关键字 13 //分配+收集 14 //每个关键字分配+收集需要n+n时间,而共有g个关键字,时间复杂度为O(2ng)。 15 //如果用数组,数据集中在一个区间,则区间的长度很长,另外的区间的内存浪费了。 16 //用链表可以解决这个问题,且数据不需要先后顺序,所以无必要非要用数组 17 18 struct node 19 { 20 //关键字的值 21 long key[g+1]; 22 }data[maxn+1]; 23 //next:下一个数的编号 24 //front,rear:一个链表的首,尾数据的编号 25 long next[maxn+1],front[y-x+1],rear[y-x+1]; 26 27 int main() 28 { 29 char c; 30 long n,i,j,head,pos,value,t; 31 scanf("%ld",&n); 32 for (i=1;i<=n;i++) 33 { 34 c=getchar(); 35 for (j=1;j<=g;j++) 36 { 37 c=getchar(); 38 data[i].key[j]=c-48; 39 } 40 41 } 42 for (i=1;i<n;i++) 43 next[i]=i+1; 44 next[n]=0; 45 head=1; 46 //key i 47 for (i=g;i>=1;i--) 48 { 49 //值为j的链表的首地址,0代表j链表没有元素 50 for (j=x;j<=y;j++) 51 front[j]=0; 52 pos=head; 53 ///分配 54 while (pos) 55 { 56 //把一个数添加到value链表的末尾 57 value=data[pos].key[i]; 58 //如果原来value链表有元素,则原来value链表的末尾元素的后继为第pos个数 59 //如果原来value链表没有元素,则value链表的起始元素为第pos个数 60 if (front[value]!=0) 61 next[rear[value]]=pos; 62 else 63 front[value]=pos; 64 //当前value链表的末尾元素为第pos个数 65 rear[value]=pos; 66 pos=next[pos]; 67 } 68 ///收集 69 //把x链表,x+1链表,……,y链表 连接起来,而k链表的最后一个元素的后继为k+1链表的第一个元素 70 value=x; 71 while (front[value]==0) 72 value++; 73 head=front[value]; 74 while (value<=y) 75 { 76 t=value+1; 77 while (front[t]==0 && t<=y) 78 t++; 79 if (t==y+1) 80 break; 81 next[rear[value]]=front[t]; 82 value=t; 83 } 84 next[rear[value]]=0; 85 } 86 printf("\n"); 87 pos=head; 88 while (pos) 89 { 90 for (i=1;i<=g;i++) 91 printf("%ld",data[pos].key[i]); 92 printf("\n"); 93 pos=next[pos]; 94 } 95 return 0; 96 } 97 /* 98 input: 99 10 100 112 101 979 102 385 103 133 104 543 105 685 106 213 107 145 108 911 109 513 110 output: 111 112 112 133 113 145 114 213 115 385 116 513 117 543 118 685 119 911 120 979 121 */
以上是关于基数排序(桶排序) 不同方法的主要内容,如果未能解决你的问题,请参考以下文章