数据结构里面的“基数排序”到底是啥
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构里面的“基数排序”到底是啥相关的知识,希望对你有一定的参考价值。
基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。 以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个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(n),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。
编辑本段实现方法
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。 最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
编辑本段实现
* C
#include <stdio.h> #include <stdlib.h> int main() int data[10]=73,22,93,43,55,14,28,65,39,81; int temp[10][10]=0; 基数排序算法
int order[10]=0; int i,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)%10); temp[lsd][order[lsd]]=data[i]; order[lsd]++; printf("\n重新排列: "); for (i=0;i<10;i++) if(order[i]!=0) for (j=0;j<order[i];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]); return 0;
* Java
public class RadixSort public static void sort(int[] number, int d) int k=0; int n=1; int m=1; int[][] temp = new int[number.length][number.length]; int[] order = new int[number.length]; while(m <= d) for(int i = 0; i < number.length; i++) int lsd = ((number[i] / n) % 10); temp[lsd][order[lsd]] = number[i]; order[lsd]++; for(int i = 0; i < d; i++) if(order[i] != 0) for(int j = 0; j < order[i]; j++) number[k] = temp[i][j]; k++; order[i] = 0; n *= 10; k = 0; m++; public static void main(String[] args) int[] data = 73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100; RadixSort.sort(data, 10); for(int i = 0; i < data.length; i++) System.out.print(data[i] + " ");
* pascal
program jspx; const n=8; type link=^node; node=record data:integer; next:link; end; var i,j,l,m,k:integer; a:array[1..n] of integer; s:string; q,head:array[0..9] of link; p,p1:link; begin writeln('Enter data:'); for i:=1 to n do read(a[i]); for i:=5 downto 1 do begin for j:=0 to 9 do begin new(head[j]); head[j]^.next:=nil; q[j]:=head[j] end; for j:=1 to n do begin str(a[j],s); for k:=1 to 5-length(s) do s:='0'+ s; m:=ord(s[i])-48; new(p); p^.data:=a[j]; p^.next:=nil; q[m]^.next:=p; q[m]:=p; end; l:=0; for j:=0 to 9 do begin p:=head[j]; while p^.next<>nil do begin l:=l+1;p1:=p;p:=p^.next;dispose(p1);a[l]:=p^.data; end; end; end; writeln('Sorted data:'); for i:= 1 to n do write(a[i]:6); end.
编辑本段c++实现基数排序
int maxbit(int data[],int n) //辅助函数,求数据的最大位数 int d = 1; //保存最大的位数 int p =10; for(int i = 0;i < n; ++i) while(data[i] >= p) p *= 10; ++d; return d; void radixsort(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)%10; //统计每个桶中的记录数 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)%10; count[k]--; tmp[count[k]] = data[j]; 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<int> list = new List<int>();//存放每次排序后的元素 List<int>[] listArr = new List<int>[10];//十个桶 char currnetChar;//存放当前的字符 比如说 某个元素123 中的2 string currentItem;//存放当前的元素 比如说 某个元素123 for (int i = 0; i < listArr.Length; i++)//给十个桶分配内存初始化。 listArr[i] = new List<int>(); 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<int>()) list.Add(number); listArr[j].Clear();//清空每个桶 arr = list.ToArray<int>();//arr指向重新排列的元素 //Console.Write("0 times:",i); Print(arr);//输出一次排列的结果 list.Clear();//清空list //得到最大元素的位数 private static int GetMaxLength(int[] arr) int iMaxNumber = Int32.MinValue; foreach (int i in arr)//遍历得到最大值 if (i > iMaxNumber) iMaxNumber = i; return iMaxNumber.ToString().Length;//这样获得最大元素的位数是不是有点投机取巧了... //输出数组元素 public static void Print(int[] arr) foreach (int i in arr) System.Console.Write(i.ToString()+'\t'); System.Console.WriteLine(); //产生随机数组。随机数的范围是0到1000。 参数iLength指产生多少个随机数 public static int[] CreateRandomArray(int iLength) int[] arr = new int[iLength]; Random random = new Random(); for (int i = 0; i < iLength; i++) arr[i] = random.Next(0,1001); return arr; 参考技术A 通俗理解可以这样~
一个元素有多个关键字,定义排序后的“有序”是指依次比较这些关键字,不同的直接按其大小关系,相同的比较后续的关键字,例如字符串与数字。然后,这些关键字都有一些范围。依次选取这些关键字作为依据,进行依次分类,这样,类别之间就有了相对的大小关系。然后,对每个类别进行相同的操作,直至所有关键字都被比较过为止。
例如,对一些三位数进行排序。123、584、546、489、853。先按百位数分类,分成了1、4、5、8四个非空类。然后对现存每个类,再进行分类统计。实际上就是线性扫描每个分类,可理解为递归对下一个关键字作为比较依据进行排序。依此类推至所有关键字,最后再整理一次,即将每个类组合成一个数组。 参考技术B 可以参考以下网址:http://baike.baidu.com/view/1170573.htm
如果你要往里面看,一个 nib 文件到底是啥样子的?
【中文标题】如果你要往里面看,一个 nib 文件到底是啥样子的?【英文标题】:What exactly does a nib file look like if you were to look inside?如果你要往里面看,一个 nib 文件到底是什么样子的? 【发布时间】:2016-11-30 00:57:47 【问题描述】:我只是在学习 nibs 和 swift 并且对某些东西感到好奇。我知道,如果您有一个 main.storyboard 文件,那么首先会在根视图控制器上加载一个 nib,然后对于可能在该视图控制器下分层存在的任何视图,但是......我想知道一些事情。
当他们说 nib 已“加载”时,这是否意味着,根据您在界面构建器中构建的情节提要,单个函数 CALLS 您要加载的 ui 对象的实例?
如果不是,那么看待这个问题的正确方法是什么?我正在尝试收集一个易于理解、准确的心理模型。
谢谢!
【问题讨论】:
developer.apple.com/library/content/documentation/Cocoa/… apeth.com/iOSBook/ch07.html#_nib_loading_and_file_8217_s_owner 我会阅读视图控制器编程指南以更好地理解这一点。 【参考方案1】:如果你要往里面看,nib 文件到底是什么样子的?
往前走,看看里面!它只是一个 XML 文件;人类完全可读。
我知道,如果您有一个 main.storyboard 文件,则首先会在根视图控制器上加载一个 nib,然后再为该视图控制器下分层存在的任何视图加载
正确!更准确地说,故事板中的每个“场景”都包含 两个 nib,一个包含视图控制器,另一个包含其视图、视图的子视图以及构成该场景的所有其他内容。
当他们说 nib 已“加载”时,这是否意味着,根据您在界面构建器中构建的情节提要,单个函数 CALLS 您要加载的 ui 对象的实例?
将笔尖视为一堆潜在的对象实例。加载 nib 会将这些潜在对象变成 实际 实例。因此,加载 nib 只是实例化和配置对象的另一种方式。被“加载”的笔尖仅仅意味着读取笔尖并且它描述的对象被实例化和检索。这就是为什么您可以多次加载同一个 nib 以获取这些对象的多个实例。
【讨论】:
以上是关于数据结构里面的“基数排序”到底是啥的主要内容,如果未能解决你的问题,请参考以下文章