基数排序(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. HDU 1969 Pie(二分,注意精度)

    Pie Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  2. js复制URL链接

    html: <div style="height:0px; text-indent:-10000px;"><span id="hdcopyurl&quo ...

  3. Repeater使用技巧

    一.在ItemDataBound事件里面动态改变Repeater控件里面的html元素 如: <asp:Repeater ID="Repeater1" runat=" ...

  4. Java 8 : Stream API 练习

    //店铺属性类 public class Property { String name; // 距离,单位:米 Integer distance; // 销量,月售 Integer sales; // ...

  5. uwsgi的python2+3多版本共存实操使用virtualenv

    1首先,机器需要有python2和python3的可执行环境.确保pip和pip3命令可用.原理就是在哪个环境下安装uwsgi.uwsgi启动的时候,就用的哪个python版本 2安装virtuale ...

  6. 【CentOS 6.5】QtCreator启动时关于dbus-1的错误解决方法

    关于上篇文章留下的启动QtCreator提示:dbus_connection_can_send_type的错误,解决办法: 更新dbus版本来解决.. 首先去 http://dbus.freedesk ...

  7. c++ new 与malloc有什么区别

    前言 几个星期前去面试C++研发的实习岗位,面试官问了个问题: new与malloc有什么区别? 这是个老生常谈的问题.当时我回答new从自由存储区上分配内存,malloc从堆上分配内存:new/de ...

  8. 关于使用testng的retry问题

    总体是利用TestNG里面的IRetryAnalyzer.TestListenerAdapter接口来实现相关问题 1.定义一个自己的retryanalyzer import org.testng.I ...

  9. Hadoop之MapReduce学习笔记(二)

    主要内容: mapreduce编程模型再解释: ob提交方式: windows->yarn windows->local : linux->local linux->yarn: ...

  10. C#泛型序列化困境

    [C#泛型序列化困境] 问题的起因是这样,有一个需求,将JsonArray转化为List,JsonArray中的元素均是string,此string可被转化为int.float.或维持string.我 ...