数据结构里面的“基数排序”到底是啥

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 以获取这些对象的多个实例。

【讨论】:

以上是关于数据结构里面的“基数排序”到底是啥的主要内容,如果未能解决你的问题,请参考以下文章

桶排序基数排序

桶排序基数排序

桶排序基数排序

❤️数据结构入门❤️(4 - 7)- 基数排序

小白初识 - 基数排序(RadixSort)

数据结构Java版之基数排序