在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
今天在头条看一个很有意思的排序算法【基数排序】,以前所学习的排序算法都是基于数值对比的方式排序的,而这个算法挺有意思的非常独特。但从网上看到的例子通常是对个位,十位处理,并转为对应的桶索引的方式实现,这里将此算法用C#实现,并以位运算的新方式实现。 一.代码实现 static void Main(string[] args) { //待排序数组 List<int> arrlist = new List<int>() { 72, 11, 82, 32, 44, 13, 17, 95, 54, 28, 79, 56 }; int Number = 3; //基数 网上教材都是基于个位,十位,百位进行运算,这里通过位数计算 int NumCount = 1 << Number; //桶数 位数是3那么桶数是8, 位数是4那么桶数是16 List<List<int>> intList = new List<List<int>>(); //建立好桶 for (int i = 0; i < NumCount; i++) { intList.Add(new List<int>()); } int LayerCount = 3; //位数划分组数(计算方法:数组最大值为95,对应二进制为:1011111,基数为3的话,可以分为1,011,111; 组数为3) //算法实现-----算法复杂度(nxm) for (int k = 1; k <= LayerCount; k++) //最大整数最高位数划分组数 { intList.ForEach(tt => tt.Clear()); foreach (var item in arrlist) { int index = item & ((1 << k * Number) - 1); //左移加与位运算 求桶索引 index = index >> (k - 1) * Number;//右移加与运算 求桶索引 intList[index].Add(item); } arrlist.Clear(); for (int i = 0; i < NumCount; i++) { for (int j = 0; j <intList[i].Count; j++) { arrlist.Add(intList[i][j]); } } } //输出 arrlist.ForEach(tt=>Console.WriteLine(tt)); Console.ReadKey(); }
二.输出排序结果:
三 .基数排序算法介绍: 基数排序的两个关键要点: (1)基:被排序的元素的“个位”“十位”“百位”,暂且叫“基”,栗子中“基”的个数是2(个位和十位); 画外音:来自野史,大神可帮忙修正。 (2)桶:“基”的每一位,都有一个取值范围,栗子中“基”的取值范围是0-9共10种,所以需要10个桶(bucket),来存放被排序的元素;
基数排序的算法步骤为: FOR (每一个基) { //循环内,以某一个“基”为依据 第一步:遍历数据集arr,将元素放入对应的桶bucket 第二步:遍历桶bucket,将元素放回数据集arr }
更具体的,对应到上面的栗子,“基”有个位和十位,所以,FOR循环会执行两次。
【第一次:以“个位”为依据】 画外音:上图中标红的部分,个位为“基”。 第一步:遍历数据集arr,将元素放入对应的桶bucket;
操作完成之后,各个桶会变成上面这个样子,即:个位数相同的元素,会在同一个桶里。
第二步:遍历桶bucket,将元素放回数据集arr; 画外音:需要注意,先入桶的元素要先出桶。 操作完成之后,数据集会变成上面这个样子,即:整体按照个位数排序了。 画外音:个位数小的在前面,个位数大的在后面。
【第二次:以“十位”为依据】 画外音:上图中标红的部分,十位为“基”。 第一步:依然遍历数据集arr,将元素放入对应的桶bucket; 操作完成之后,各个桶会变成上面这个样子,即:十位数相同的元素,会在同一个桶里。
第二步:依然遍历桶bucket,将元素放回数据集arr; 操作完成之后,数据集会变成上面这个样子,即:整体按照十位数也排序了。 画外音:十位数小的在前面,十位数大的在后面。
首次按照个位从小到大,第二次按照十位从小到大,即:排序结束。
神奇不神奇!!!
几个小点: (1)基的选取,可以先从个位开始,也可以先从十位开始,结果是一样的; (2)基数排序,是一种稳定的排序; (3)时间复杂度,可以认为是线性的O(n);
|
请发表评论