基数排序简单Java实现

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

时间: 2024-08-24 02:24:39

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

RabbitMQ学习及实践2---介绍及简单Java实现

一,基本概念 MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息.MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品. RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协

Ant——使用Ant构建简单Java项目(二)

博客<Ant--使用Ant构建简单Java项目(一)>演示了使用Ant工具构建简单的Java项目,接着这个例子来进一步学习Ant: 上面例子执行build.xml文件脚本比较繁杂,能不能简化执行的脚本呢?答案是肯定的,可以将build.xml文件中的脚本改成下面的脚本: <?xml version="1.0" encoding="UTF-8"?> <project name="test" default="

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

1 public class JAVA 2 { 3 public static void main(String[] args) 4 { 5 System.out.println("----------------------"); 6 System.out.println("|| 我要学会 ||"); 7 System.out.println("|| JAVA语言 ||"); 8 System.out.println("-------

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

博客<Ant--使用Ant构建简单Java项目(二)>我们简化了执行Test类中main方法需要执行的命令,本博客来介绍一下如何使build.xml文件和其中使用property标签定义的属性分离: 1.在test文件夹中新建名为build.properties的文件,文件中以"key=value"的形式输入原来在build.xml文件中定义的属性及其属性值如下: src=src lib=build/lib dest=build/classes np_jar=build/l

_00019 Storm的体系结构介绍以及Storm入门案例(官网上的简单Java案例)

博文作者:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前,妳却感觉不到我的存在 技术方向:Flume+Kafka+Storm+Redis/Hbase+Hadoop+Hive+Mahout+Spark ... 云计算技术 转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作! qq交流群:214293307  (期待与你一起学习,共同进步) # Storm

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

博客<Ant-使用Ant构建简单Java项目(二)>我们简化了运行Test类中main方法须要运行的命令,本博客来介绍一下如何使build.xml文件和当中使用property标签定义的属性分离: 1.在test目录中新建名为build.properties的文件,文件里以"key=value"的形式输入原来在build.xml文件里定义的属性及其属性值例如以下: src=src lib=build/lib dest=build/classes np_jar=build/l

Java基础_3.5:简单Java类

简单Java类 简单Java类是一种在实际开发之中使用最多的类的定义形式,在简单Java类中包含有类.对象.构造方法.private封装等核心概念的使用,而对于简单Java类首先给出如下的基本开发要求: 类名称必须存在有意义,例如:Book.Emp: 类之中所有的属性必须private封装,封装后的属性必须提供有setter.getter: 类之中可以提供有任意多个构造方法,但是必须保留有一个无参构造方法: 类之中不允许出现任何的输出语句,所有信息输出必须交给被调用处输出: 类之中需要提供有一个

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

简单java类开发一般原则: 类名称必须有意义,再怎么说,要让人家看的明白吧 类之中所有属性必须使用private封装,并提供setter,getter方法 类之中可以有多个构造方法,但是必须保留有一个无参数构造方法 类之中不允许出现任何输出语句,所有输出必须交给被调用处 类之中需要有一个可以取得对象完整信息的方法,一般叫做getInfo(),返回String型数据 class Book { private String name; private int price; private int

java反射(四)--反射与简单java类

一.传统简单java类 简单的java类主要是由属性所组成,并且提供有相应的setter以及getter的处理方法,同时简单java类最大的特征就是通过对象保存相应的类的属性内容,但是如果使用传统的简单java类的开发,那么也会面临非常麻烦的困难: 1 class Emp{ 2 private String ename; 3 private String job; 4 5 public void setEname(String ename) { 6 this.ename = ename; 7 }