基数排序(radix sort)又称“桶子法”,在对多个正整数进行排序时可以使用。它的灵感来自于队列(Queue),它最独特的地方在于利用了数字的有穷性(阿拉伯数字只有0到9的10个)。

  基数排序使用11个动态数组实现排序算法,一个主队列(下文都将使用的动态数组称为队列)存储未排序的数据(最后排序完成也仍然可以用它存储,或者如果希望保存原来的数据位置则可能需要增加一个队列);10个子队列用于排序过程中动态存放数值,在排序开始前和结束后可以清空。

  我们使用LinkedList类来实现基数排序,其实整个类很简单,我先贴出全部代码然后再细细解释:

  1 package ahe.sort;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.util.LinkedList;
7
8 /**
9 * 基数排序算法
10 *
11 * @author Johness
12 *
13 */
14 public class RadixSort {
15
16 /** 主队列 */
17 private LinkedList<Integer> mainQueue;
18 /** 子队列 */
19 private LinkedList<Integer>[] subQueues;
20 /** 子队列个数,作用不大 */
21 private final int SIZE = 10;
22 /** 当前容器(主队列)中存储数值的最大位数 */
23 private int maxDigits;
24
25 /** 构造函数 */
26 public RadixSort() {
27 mainQueue = new LinkedList<Integer>();
28 subQueues = new LinkedList[SIZE];
29 for(int i = 0; i < SIZE; ++i)
30 subQueues[i] = new LinkedList<Integer>();
31 maxDigits = 0;
32 }
33
34 /** 向容器中(主队列)添加一个数值 */
35 public void add(Integer num) {
36 int digits = String.valueOf(num).length();
37 if (digits > maxDigits)
38 maxDigits = digits;
39 mainQueue.add(num);
40 }
41
42 /** 排序 */
43 public void sort() {
44 for (int i = 1; i <= maxDigits; ++i) {
45 while (mainQueue.size() > 0) {
46 Integer element = (Integer) mainQueue.pop();
47 String elementTmpStr = String.valueOf(element);
48 if (elementTmpStr.length() < i) {
49 subQueues[0].add(element);
50 continue;
51 }
52 int digit = elementTmpStr.charAt(elementTmpStr.length() - i) - '0';
53 subQueues[digit].add(element);
54 }
55 //listSubQueues();
56 for (int j = 0; j < SIZE; ++j) {
57 mainQueue.addAll(subQueues[j]);
58 subQueues[j].clear();
59 }
60 //listMainQueue();
61 }
62 }
63
64 /*==============================================================================================*/
65 // 以下方法为测试方法(以下方法来自于Arizona State University学校课后作业,本人只做翻译,如该资源侵犯了您的权益,请及时联系我)
66 // 您可以访问
67 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Assignment11.java
68 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Sorting.java
69 // 查看本文参考内容
70 // 本文输入输出对照表可从该课后作业中获得
71 // 输入表
72 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input1.txt
73 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input2.txt
74 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input3.txt
75 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input4.txt
76 // 输出表
77 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output1.txt
78 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output2.txt
79 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output3.txt
80 // https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output4.txt
81 /*==============================================================================================*/
82 /**
83 * 列举(输出)主队列数据
84 */
85 public void listMainQueue() {
86 System.out.println("mainQueue = " + listQueue(mainQueue) + "\n");
87 }
88
89 /**
90 * 列举(输出)子队列数据
91 */
92 public void listSubQueues() {
93 String result = "";
94 for (int i = 0; i < SIZE; i++) {
95 result += "subQueue[" + i + "]:";
96 result += listQueue(subQueues[i]);
97 result += "\n";
98 }
99 System.out.println(result);
100 }
101
102 /**
103 * 列举某队列中数据项
104 *
105 * 方法使用了一个临时队列来完成数据轮循
106 * 先从目标队列中逐个取出(采用取出并删除的方式)放入临时队列并做列举操作(连接到返回字符串)
107 * 待轮循完成后再将临时队列中的数据存入回目标队列
108 *
109 * @param queue 目标队列
110 * @return 包含目标队列中所有数据的字符串
111 */
112 private String listQueue(LinkedList<Integer> queue) {
113 LinkedList<Integer> temp = new LinkedList<Integer>();
114 String result = "{ ";
115
116 while (!queue.isEmpty()) {
117 Integer removed = queue.remove();
118 result += removed + " ";
119 temp.offer(removed);
120 }
121 result += "}\n";
122
123 while (!temp.isEmpty()) {
124 Integer removed2 = temp.remove();
125 queue.offer(removed2);
126 }
127 return result;
128 }
129
130 public static void main(String[] args) {
131 char input1;
132 String inputInfo = new String();
133 String line = new String();
134
135 RadixSort sort1 = new RadixSort();
136
137 try {
138 // 打印菜单
139 printMenu();
140
141 // 创建流读取器读取用户输入
142 InputStreamReader isr = new InputStreamReader(System.in);
143 BufferedReader stdin = new BufferedReader(isr);
144
145 do {
146 System.out.print("你想进行什么操作?\n");
147 line = stdin.readLine().trim(); // 读取一行
148 input1 = line.charAt(0);
149 input1 = Character.toUpperCase(input1);
150
151 if (line.length() == 1) // 检查输入指令是否为单个
152 // 字符
153 {
154 switch (input1) {
155 case 'A': // 添加一个数值
156 System.out.print("请输入要添加的数值:\n");
157 inputInfo = stdin.readLine().trim();
158 int num = Integer.parseInt(inputInfo);
159 sort1.add(num);
160 System.out.print("数值添加成功\n");
161 break;
162 case 'L': // 列举数值
163 sort1.listMainQueue();
164 break;
165 case 'Q': // 退出
166 break;
167 case 'S': // 排序
168 sort1.sort();
169 System.out.print("排序完成\n");
170 break;
171 case '?': // 显示帮助
172 printMenu();
173 break;
174 default:
175 System.out.print("未知指令\n");
176 break;
177 }
178 } else {
179 System.out.print("未知指令\n");
180 }
181 } while (input1 != 'Q' || line.length() != 1);
182 } catch (IOException exception) {
183 System.out.print("IO Exception\n");
184 }
185 }
186
187 /** 打印控制台界面(菜单) */
188 public static void printMenu() {
189 System.out.print("选项\t\t动作\n" + "------\t\t------\n"
190 + "A\t\t添加一个数值\n" + "L\t\t列举队列\n"
191 + "Q\t\t退出\n" + "S\t\t排序数据\n"
192 + "?\t\t显示帮助\n\n");
193 }
194 }

  我们直接看sort方法(行43至62),在略去了每次排序数据从子队列存回主队列的代码(行56至59)后我们的排序算法主要分为两层。

  外层一共需要循环最大数值位数次,内层(每次)则是需要循环数值个数次。以{1,22,333,4444}为例,外层为4次循环(最大数4444为4位数),内层为4次循环(共有4个元素需要排序)。

  我们把排序过程中列举队列的代码取消注释(行55和60),我们使用输入表1进行输入:

a
539
a
264
a
372
a
424
a
419
a
129
a
322
a
544
a
367
l
s
l
q

  对应输出表则应该如下(部分空白我去除了):

 1 选项        动作
2 ------ ------
3 A 添加一个数值
4 L 列举队列
5 Q 退出
6 S 排序数据
7 ? 显示帮助
8
9 你想进行什么操作?
10 a
11 请输入要添加的数值:
12 539
13 数值添加成功
14 你想进行什么操作?
15 a
16 请输入要添加的数值:
17 264
18 数值添加成功
19 你想进行什么操作?
20 a
21 请输入要添加的数值:
22 372
23 数值添加成功
24 你想进行什么操作?
25 a
26 请输入要添加的数值:
27 424
28 数值添加成功
29 你想进行什么操作?
30 a
31 请输入要添加的数值:
32 419
33 数值添加成功
34 你想进行什么操作?
35 a
36 请输入要添加的数值:
37 129
38 数值添加成功
39 你想进行什么操作?
40 a
41 请输入要添加的数值:
42 322
43 数值添加成功
44 你想进行什么操作?
45 a
46 请输入要添加的数值:
47 544
48 数值添加成功
49 你想进行什么操作?
50 a
51 请输入要添加的数值:
52 367
53 数值添加成功
54 你想进行什么操作?
55 l
56 mainQueue = { 539 264 372 424 419 129 322 544 367 }
57 你想进行什么操作?
58 s
59 subQueue[0]:{ }
60 subQueue[1]:{ }
61 subQueue[2]:{ 372 322 }
62 subQueue[3]:{ }
63 subQueue[4]:{ 264 424 544 }
64 subQueue[5]:{ }
65 subQueue[6]:{ }
66 subQueue[7]:{ 367 }
67 subQueue[8]:{ }
68 subQueue[9]:{ 539 419 129 }
69 mainQueue = { 372 322 264 424 544 367 539 419 129 }
70 subQueue[0]:{ }
71 subQueue[1]:{ 419 }
72 subQueue[2]:{ 322 424 129 }
73 subQueue[3]:{ 539 }
74 subQueue[4]:{ 544 }
75 subQueue[5]:{ }
76 subQueue[6]:{ 264 367 }
77 subQueue[7]:{ 372 }
78 subQueue[8]:{ }
79 subQueue[9]:{ }
80 mainQueue = { 419 322 424 129 539 544 264 367 372 }
81 subQueue[0]:{ }
82 subQueue[1]:{ 129 }
83 subQueue[2]:{ 264 }
84 subQueue[3]:{ 322 367 372 }
85 subQueue[4]:{ 419 424 }
86 subQueue[5]:{ 539 544 }
87 subQueue[6]:{ }
88 subQueue[7]:{ }
89 subQueue[8]:{ }
90 subQueue[9]:{ }
91 mainQueue = { 129 264 322 367 372 419 424 539 544 }
92 排序完成
93 你想进行什么操作?
94 l
95 mainQueue = { 129 264 322 367 372 419 424 539 544 }
96 你想进行什么操作?
97 q

  (你可以将列举子队列的语句行55放入输出更频繁的地方如原行49后和52后,这样更加能直观地看到效果)

  从上面的输出表可以看出,排序轮循一共进行了3次(外层,因为数值最大位数为3)。

基数排序简单Java实现的更多相关文章

  1. 数据结构与算法——基数排序简单Java实现

    基数排序(radix sort)又称“桶子法”,在对多个正整数进行排序时可以使用.它的灵感来自于队列(Queue),它最独特的地方在于利用了数字的有穷性(阿拉伯数字只有0到9的10个). 基数排序使用 ...

  2. 程序员必知的8大排序(四)-------归并排序,基数排序(java实现)

    程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...

  3. 简单java在线测评程序

    简单java程序在线测评程序 一.前言 大家过年好!今年的第一篇博客啊!家里没有网,到处蹭无线!日子过得真纠结!因为毕设的需求,简单写了一个java程序在线测评程序,当然也可以在本地测试. 二.思路 ...

  4. 输出多行字符的一个简单JAVA小程序

    public class JAVA { public static void main(String[] args) { System.out.println("-------------- ...

  5. Java基础_0311: 数据表与简单Java类映射

    数据表与简单Java类映射 现在假设有如下的关系表,现在要求实现如下的数据关联操作: 一个部门有多个雇员: 一个雇员有一个或零个领导 代码实现 class Dept { private int dep ...

  6. Java基础_0305:简单Java类

    简单Java类 简单Java类是一种在实际开发之中使用最多的类的定义形式,在简单Java类中包含有类.对象.构造方法.private封装等核心概念的使用,而对于简单Java类首先给出如下的基本开发要求 ...

  7. JAVA基础学习之路(四)定义简单java类

    简单java类开发一般原则: 类名称必须有意义,再怎么说,要让人家看的明白吧 类之中所有属性必须使用private封装,并提供setter,getter方法 类之中可以有多个构造方法,但是必须保留有一 ...

  8. Ant—使用Ant构建简单Java项目(三)

    博客<Ant-使用Ant构建简单Java项目(二)>我们简化了运行Test类中main方法须要运行的命令,本博客来介绍一下如何使build.xml文件和当中使用property标签定义的属 ...

  9. JAVA 基础开发环境 vscode 搭建 Windows下VSCode编译运行简单java

    JAVA 基础开发环境 vscode 搭建 来源 https://www.cnblogs.com/freewsf/p/7744728.html 对于使用 Visual Studio Code 的 Ja ...

随机推荐

  1. Java File文件操作 创建文件\目录,删除文件\目录

    Java手册 java.io 类 File java.lang.Object java.io.File 所有已实现的接口: Serializable, Comparable<File> p ...

  2. PHP CRC16 校验码的算法怎么使用

    PHP CRC16 校验码的算法如何使用最近用到CRC16, 我现在就是要把 010301180001 算出CRC16的校验码,通过其他工具,可以得到 校验码是 05F1 最后完整的代码就是 0103 ...

  3. C++ sort使用自定义函数的一些坑

    先看代码: 解释:使用自定义比较函数时,如果用了返回值恒为$true$或者恒为$false$的比较函数,就会这样子. 原因: https://stackoverflow.com/questions/4 ...

  4. Java前期(静态)绑定和后期(动态)绑定

    Java前期(静态)绑定和后期(动态)绑定 程序绑定的概念:绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定. 静态绑 ...

  5. Raspberry Pi 安装FTP(Pure-FTP)

    Raspbian版本: 安装: 因为使用的是默认的pi用户,所以下面的命令都带着sudo. 安装Pure-FTP sudo apt-get install pure-ftpd 2. 创建用户组ftpg ...

  6. hive基本结构与数据存储

    一.Hive简介 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能.还可以将 SQL 语句转换为 MapReduce 任务进行运行,通过自 ...

  7. 常用的ubantu操作命令

    Ubuntu软件操作的相关命令 sudo apt-get update 更新源 sudo apt-get install package 安装包 sudo apt-get remove package ...

  8. android手机 ping 虚拟机ubuntu的ip地址

    今天使用android手机往虚拟机上ubuntu 上搭建的nginx 和rtmp服务器推送东西的时候,怎么都推不上去. 后来在windows下的cmd里: # adb shell # ping 192 ...

  9. arcgis mpk 打包地图 (数据管理)

    摘要 来自:http://help.arcgis.com/zh-cn/arcgisdesktop/10.0/help/index.html#/na/0017000000q5000000/ 对地图文档以 ...

  10. Linux命令之sed批量替换字符串操作

    使用sed命令可以进行字符串的批量替换操作,以节省大量的时间及人力: 使用的格式如下: sed -i "s/oldstring/newstring/g" `grep oldstri ...