先复习一些基本知识
链式存储的特点:用一组任意的存储单元(可以连续,也可以不连续)存储线性表的数据元素。
链式存储中每一个元素都是一个节点,每个节点中包含了数据域和指针域
相对数组存储来说,其优点是插入删除速度快,缺点是不支持随机访问,查询速度慢
什么是基数排序? 看看百度百科的定义:
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。 通俗来说就是采用 “分配” 和 “收集”, 用对单关键码进行排序的方法,来实现对多关键码的排序
想要详细了解的可以看下这篇: 漫画:什么是基数排序?_程序员小灰的博客-CSDN博客
那么什么是链式基数排序呢?
所谓链式基数排序,就是实现基数排序时,因为有比较多的插入操作,应采用链表作存储结构
链式的基数排序算法解法思路(默认从小到大):
1、以静态链表存储待排记录,并令表头指针指向第一个记录;
2、“分配” 时,按当前“关键字位”所取值,将记录分配到不同的 “链队列” 中,每个队列中记录的 “关键字位” 相同;
3、“收集”时,按当前关键字位取值从小到大将各队列首尾相链成一个链表;
4、对每个关键字位均重复 2 和 3 两步。
来看今天的问题, 我们观察到,玩手机麻将的时候, 系统最初发给我们的牌是无序的, 像下面这样
这时候一般牌会翻过去一下,再翻回来的时候就已经做好排序了:
那么这是怎么实现的呢?
答案就是链式基数排序,思路如下:
第一次处理, 我们使用9个链表来收集1-9的点数, 遍历接收到的数据,把对应的点数放进对应的链表里
代码实现:
1, 创建麻将类, (原谅我蹩脚的英文)
1 public class MaJiang { 2 3 int count;//点数 1-9 4 int suit;//花色, 万--1, 条--2, 筒--3 5 6 public MaJiang(int count, int suit) { 7 this.count = count; 8 this.suit = suit; 9 } 10 }
2, 第一次排序,这里我们先按点数排序, 也可以第一次按花色,第二次按点数
1 public static void radixSort(LinkedList<MaJiang> list) { 2 //定义一个长度为9的数组, 包含了9个链表,用来存放排序之后的数据 3 LinkedList[] countLists =new LinkedList[9]; 4 5 //创建9个链表,放到数组中 6 for (int i = 0; i < countLists.length; i++) { 7 countLists[i] = new LinkedList<MaJiang>(); 8 } 9 //遍历从服务器传回来的数据 10 while (list.size() > 0) { 11 //从list中取一个 12 //remove()方法会移除List中的第一个元素,并返回该元素 13 MaJiang temp = list.remove(); 14 //根据该元素的点数,确定将其放在哪个链表中 15 countLists[temp.count-1].add(temp); 16 } 17 //while循环执行完后,list变成一个空List 18 //这时我们把完成第一轮排序后的数据依次加到list里,形成一个新的链表 19 for (int i = 0; i < countLists.length; i++) { 20 list.addAll(countLists[i]); 21 } 22 }
1 public static void main(String[] args) { 2 LinkedList<MaJiang> list = new LinkedList<MaJiang>(); 3 list.add(new MaJiang(7, 1)); 4 list.add(new MaJiang(9, 1)); 5 list.add(new MaJiang(9, 3)); 6 list.add(new MaJiang(6, 3)); 7 list.add(new MaJiang(9, 2)); 8 list.add(new MaJiang(1, 3)); 9 list.add(new MaJiang(4, 1)); 10 list.add(new MaJiang(2, 1)); 11 list.add(new MaJiang(1, 1)); 12 list.add(new MaJiang(3, 1)); 13 list.add(new MaJiang(9, 3)); 14 list.add(new MaJiang(5, 3)); 15 list.add(new MaJiang(6, 2)); 16 list.add(new MaJiang(8, 2)); 17 list.add(new MaJiang(9, 3)); 18 19 System.out.println(list); 20 radixSort(list); 21 System.out.println(list); 22 } 23 24 }
第一次排序执行完后,我们将得到点数从小到大以此排列的新链表
程序运行结果如下:(第一行为排序前,第二行为排序后)
接下来我们再对第一次排序得到的结果进行第二次排序
原理和第一次排序相同,建3个链表分别存储万条筒,然后把对应的花色放进去
1 //接下来我们进行第二次排序 2 LinkedList[] suitLists =new LinkedList[3]; 3 for (int i = 0; i < suitLists.length; i++) { 4 suitLists[i] = new LinkedList<MaJiang>(); 5 } 6 while (list.size() > 0) { 7 //从list中取一个 8 MaJiang temp = list.remove(); 9 //根据该元素的点数,确定将其放在哪个链表中 10 suitLists[temp.suit-1].add(temp); 11 } 12 for (int i = 0; i < suitLists.length; i++) { 13 list.addAll(suitLists[i]); 14 }
代码逻辑和第一次排序类似, 看下最终运行结果
链式基数排序适用于数据量在二三十个左右的排序