倒霉的菜鸟

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

先复习一些基本知识

链式存储的特点:用一组任意的存储单元(可以连续,也可以不连续)存储线性表的数据元素。

链式存储中每一个元素都是一个节点,每个节点中包含了数据域和指针域

相对数组存储来说,其优点是插入删除速度快,缺点是不支持随机访问,查询速度慢

什么是基数排序? 看看百度百科的定义:

基数排序(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         }

代码逻辑和第一次排序类似, 看下最终运行结果

 

 

链式基数排序适用于数据量在二三十个左右的排序

 

posted on 2021-10-05 01:17  倒霉的菜鸟  阅读(164)  评论(0编辑  收藏  举报