10种排序算法总结(五)

2014-11-24 02:47:46 · 作者: · 浏览: 80
文件
TournamentSort(num);//锦标赛排序
printf("CompareNum=%d\nExchangeNum=%d\n",CompareNum,ExchangeNum);
return 0;
}
------------------------------------------Code-------------------------------------


十、基数排序
基数排序又被称为桶排序。与前面介绍的几种排序方法相比较,基数排序和它们有明显的不同。
前面所介绍的排序方法都是建立在对数据元素关键字进行比较的基础上,所以可以称为基于比较的排序;
而基数排序首先将待排序数据元素依次“分配”到不同的桶里,然后再把各桶中的数据元素“收集”到一起。
通过使用对多关键字进行排序的这种“分配”和“收集”的方法,基数排序实现了对多关键字进行排序。
———————————————————————————————————————
例:
每张扑克牌有两个“关键字”:花色和面值。其大小顺序为:
花色:§<¨< <
面值:2<3<……<K<A
扑克牌的大小先根据花色比较,花色大的牌比花色小的牌大;花色一样的牌再根据面值比较大小。所以,将扑克牌按从小到大的次序排列,可得到以下序列:
§2,…,§A,¨2,…,¨A, 2,…, A, 2,…, A
这种排序相当于有两个关键字的排序,一般有两种方法实现。
其一:可以先按花色分成四堆(每一堆牌具有相同的花色),然后在每一堆牌里再按面值从小到大的次序排序,最后把已排好序的四堆牌按花色从小到大次序叠放在一起就得到排序的结果。
其二:可以先按面值排序分成十三堆(每一堆牌具有相同的面值),然后将这十三堆牌按面值从小到大的顺序叠放在一起,再把整副牌按顺序根据花色再分成四堆(每一堆牌已按面值从小到大的顺序有序),最后将这四堆牌按花色从小到大合在一起就得到排序的结果。
———————————————————————————————————————
实现方法:
  最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
  最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
---------------------------------Code in 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
  }
  }
  //得到最大元素的位数
  private static int GetMaxLength(int[] arr)
  {
  int iMaxNumber = Int32.MinValue;
  foreach (int i in arr)//遍历得到最大值
  {
  if (i > iMaxNumber)
  iMaxNumber = i;
  }
  return iMaxNumber.ToString().Length;//这样获得最大元素的位数是不是有点投机取巧了..