基数排序
来源:互联网 发布:看监控的软件 编辑:程序博客网 时间:2024/04/26 04:19
基数排序
(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucketsort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。
解法
基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significantdigital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。 以LSD为例,假设原来有一串数值如下所示: 73,22, 93, 43, 55, 14, 28, 65, 39, 81 首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中: 0 181 222 373 93 43 414 555 65 6 7 828 939 接下来将这些桶子中的数值重新串接起来,成为以下的数列: 81,22, 73, 93, 43, 14, 55, 65, 28, 39 接着再进行一次分配,这次是根据十位数来分配: 0 114 222 28 339 443 555 665 773 881 993 接下来将这些桶子中的数值重新串接起来,成为以下的数列: 14,22, 28, 39, 43, 55, 65, 73, 81, 93 这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。 LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。intorder[10]={0}; inti,j,k,n,lsd; k=0;n=1; printf("\n排序前:"); for(i=0;i<10;i++) printf("%d ",data[i]); putchar('\n'); while(n<=10){ for(i=0;i<10;i++){ lsd=((data[i]/n)); temp[lsd][order[lsd]]=data[i]; order[lsd]++; } printf("\n重新排列:"); for(i=0;i<10;i++){ if(order[i]!=0) for(j=0;j data[k]=temp[i][j]; printf("%d",data[k]); k++; } order[i]=0; } n*=10; k=0; } putchar('\n'); printf("\n排序后:"); for(i=0;i<10;i++) printf("%d ",data[i]); return0; }
编辑本段效率分析
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。编辑本段实现的方法
最高位优先(MostSignificant Digitfirst)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。 最低位优先(LeastSignificant Digitfirst)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。编辑本段实现原理
基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(TabulationMachine)上的贡献。它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。 基数排序的方式可以采用LSD(Leastsignificant digital)或MSD(Most significantdigital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。编辑本段实现
* C
#include #include intmain(){ intdata[10]={73,22,93,43,55,14,28,65,39,81}; inttemp[10][10]={0};
* Java
publicclass RadixSort { publicstatic void sort(int[] number, int d) { intk=0; intn=1; intm=1;//控制键值排序依据在哪一位 int[][]temp = new int[number.length][number.length]; int[]order = new int[number.length]; while(m<= d) { for(inti = 0; i < number.length; i++) { intlsd = ((number[i] / n) % 10); temp[lsd][order[lsd]]= number[i]; order[lsd]++; } for(inti = 0; i < d; i++) { if(order[i]!= 0) for(intj = 0; j < order[i]; j++) { number[k]= temp[i][j]; k++; } order[i]= 0; } n*= 10; k= 0; m++; } } publicstatic void main(String[] args) { int[]data = {73,22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100}; RadixSort.sort(data,10); for(inti = 0; i < data.length; i++) { System.out.print(data[i]+ " "); } }编辑本段c++实现基数排序
intmaxbit(int data[],int n) //辅助函数,求数据的最大位数 { intd = 1; //保存最大的位数 intp =10; for(inti = 0;i < n; ++i) { while(data[i]>= p) { p*= 10; ++d; } } returnd; } voidradixsort(int data[],int n) //基数排序 { int d = maxbit(data,n); int * tmp = new int[n]; int * count = new int[10]; //计数器 int i,j,k; int radix = 1; for(i = 1; i<= d;i++) //进行d次排序 { for(j = 0;j < 10;j++) count[j] = 0; //每次分配前清空计数器 for(j = 0;j < n; j++) { k = (data[j]/radix); //统计每个桶中的记录数 count[k]++; } for(j = 1;j < 10;j++) count[j] = count[j-1] + count[j]; //将tmp中的位置依次分配给每个桶 for(j = n-1;j >= 0;j--) //将所有桶中记录依次收集到tmp中 { k = (data[j]/radix); tmp[count[k]-1] = data[j]; count[k]--; } for(j = 0;j < n;j++) //将临时数组的内容复制到data中 data[j] = tmp[j]; radix = radix*10; } delete [] tmp; delete [] count; } C# 实现基数排序 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LearnSort { class Program { static void Main(string[] args) { int[] arr = CreateRandomArray(10);//产生随机数组 Print(arr);//输出数组 RadixSort(ref arr);//排序 Print(arr);//输出排序后的结果 Console.ReadKey(); } public static void RadixSort(ref int[] arr) { int iMaxLength = GetMaxLength(arr); RadixSort(ref arr, iMaxLength); } //排序 private static void RadixSort(ref int[] arr, int iMaxLength) { List list = new List();//存放每次排序后的元素 List[] listArr = new List[10];//十个桶 char currnetChar;//存放当前的字符 比如说 某个元素123 中的2 string currentItem;//存放当前的元素 比如说 某个元素123 for (int i = 0; i < listArr.Length;i++)//给十个桶分配内存初始化。 listArr[i] = new List(); for (int i = 0; i < iMaxLength;i++)//一共执行iMaxLength次,iMaxLength是元素的最大位数。 { foreach (int number in arr)//分桶 { currentItem = number.ToString();//将当前元素转化成字符串 try { currnetChar = currentItem[currentItem.Length-i-1];}//从个位向高位开始分桶 catch { listArr[0].Add(number); continue;}//如果发生异常,则将该数压入listArr[0]。比如说5是没有十位数的,执行上面的操作肯定会发生越界异常的,这正是期望的行为,我们认为5的十位数是0,所以将它压入listArr[0]的桶里。 switch (currnetChar)//通过currnetChar的值,确定它压人哪个桶中。 { case '0': listArr[0].Add(number); break; case '1': listArr[1].Add(number); break; case '2': listArr[2].Add(number); break; case '3': listArr[3].Add(number); break; case '4': listArr[4].Add(number); break; case '5': listArr[5].Add(number); break; case '6': listArr[6].Add(number); break; case '7': listArr[7].Add(number); break; case '8': listArr[8].Add(number); break; case '9': listArr[9].Add(number); break; default: throw new Exception("unknow error"); } } for (int j = 0; j < listArr.Length;j++)//将十个桶里的数据重新排列,压入list foreach (int number in listArr[j].ToArray()) { list.Add(number); listArr[j].Clear();//清空每个桶 } arr= list.ToArray();//arr指向重新排列的元素 //Console.Write("{0}times:",i); Print(arr);//输出一次排列的结果 list.Clear();//清空list } } //得到最大元素的位数 privatestatic int GetMaxLength(int[] arr) { intiMaxNumber = Int32.MinValue; foreach(int i in arr)//遍历得到最大值 { if(i > iMaxNumber) iMaxNumber= i; } returniMaxNumber.ToString().Length;//这样获得最大元素的位数是不是有点投机取巧了... } //输出数组元素 publicstatic void Print(int[] arr) { foreach(int i in arr) System.Console.Write(i.ToString()+'\t'); System.Console.WriteLine(); } //产生随机数组。随机数的范围是0到1000。参数iLength指产生多少个随机数 publicstatic int[] CreateRandomArray(int iLength) { int[]arr = new int[iLength]; Randomrandom = new Random(); for(int i = 0; i < iLength; i++) arr[i]= random.Next(0,1001); returnarr; } } }编辑本段AAuto语言实现基数排序
io.open();//打开控制台 //计数排序算法 radix_sort= function( array ,maxlen){ //AAuto在字符串索引越界时,会返回0,这使基数排序的实现更加简单。 //我们首先找出最大的排序长度,然后对于不足此长度的字符串,尾部都假定以0补齐。 //对于超出此长度的位在比较时忽略 if(!maxlen){ maxlen=0; for(i=1;#array;1){ maxlen= math.max(maxlen,#array[i] ) } } //else{ //最大排序长度也可以从参数中传过来,这样就不用遍历所有字符串了 //} //从字符串的最后一位开始,到第一位 for(pos=maxlen;1;-1){ //按当前位的字节码计数排序 vararray_sorted ={}; varcount = {}; for(i=0;256){ count[i]= 0; } varbytecode; for(i=1;#array;1){ //如果pos大于字符串长度,AAuto会返回0,这使基数排序的实现更容易 bytecode= array[i][pos] ; count[bytecode ] ++; //count[n] 包含等于n的个数 } //统计位置 for(i=1;256;1){ count[i]+= count[i-1]; //count[i] 包含小于等于i的个数 } varn; for(i=#array;1;-1){ n= array[i][pos] array_sorted[count[n] ] = array[i]; count[n]--;//防止相同的元素n再次出现,将计数减一 } array= array_sorted; } returnarray } io.print("----------------") io.print("基数排序(线性时间排序 )") io.print("----------------") array={"AAuto is quicker and better,just try it!";"AAutoQuicker";"193";"229";"233";"215";"HelloWord";"abc";"abcd";"xd";"adcd";"eddd";"ah";"ai";"aj";"ajkk"}; //排序 array= radix_sort(array ) //输出结果 for(i=1;#array;1){ io.print(array[i] ) } execute("pause")//按任意键继续 io.close();//关闭控制台- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 120*120 的 ICON 图标命名
- WEB客户端语言与WEB服务端语言
- Linux Shell编程入门
- DROP TABLE ** CAS…
- 关于 hot code replace fail 问题
- 基数排序
- oracle笔记一无限更新(1)
- oracle latch工作原理
- Oracle 联机重做日志文件(ONL…
- B-树
- IDS or IPS
- 集线器,交换机与路由器
- 如何做一名优秀、甚至卓越的WEB前…
- 程序员必知8大排序,成为大牛!