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

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

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

 package ahe.sort;

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList; /**
* 基数排序算法
*
* @author Johness
*
*/
public class RadixSort { /** 主队列 */
private LinkedList<Integer> mainQueue;
/** 子队列 */
private LinkedList<Integer>[] subQueues;
/** 子队列个数,作用不大 */
private final int SIZE = 10;
/** 当前容器(主队列)中存储数值的最大位数 */
private int maxDigits; /** 构造函数 */
public RadixSort() {
mainQueue = new LinkedList<Integer>();
subQueues = new LinkedList[SIZE];
for(int i = 0; i < SIZE; ++i)
subQueues[i] = new LinkedList<Integer>();
maxDigits = 0;
} /** 向容器中(主队列)添加一个数值 */
public void add(Integer num) {
int digits = String.valueOf(num).length();
if (digits > maxDigits)
maxDigits = digits;
mainQueue.add(num);
} /** 排序 */
public void sort() {
for (int i = 1; i <= maxDigits; ++i) {
while (mainQueue.size() > 0) {
Integer element = (Integer) mainQueue.pop();
String elementTmpStr = String.valueOf(element);
if (elementTmpStr.length() < i) {
subQueues[0].add(element);
continue;
}
int digit = elementTmpStr.charAt(elementTmpStr.length() - i) - '0';
subQueues[digit].add(element);
}
//listSubQueues();
for (int j = 0; j < SIZE; ++j) {
mainQueue.addAll(subQueues[j]);
subQueues[j].clear();
}
//listMainQueue();
}
} /*==============================================================================================*/
// 以下方法为测试方法(以下方法来自于Arizona State University学校课后作业,本人只做翻译,如该资源侵犯了您的权益,请及时联系我)
// 您可以访问
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Assignment11.java
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/Sorting.java
// 查看本文参考内容
// 本文输入输出对照表可从该课后作业中获得
// 输入表
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input1.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input2.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input3.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/input4.txt
// 输出表
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output1.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output2.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output3.txt
// https://courses.eas.asu.edu/cse205/current/assignments/assignment11/output4.txt
/*==============================================================================================*/
/**
* 列举(输出)主队列数据
*/
public void listMainQueue() {
System.out.println("mainQueue = " + listQueue(mainQueue) + "\n");
} /**
* 列举(输出)子队列数据
*/
public void listSubQueues() {
String result = "";
for (int i = 0; i < SIZE; i++) {
result += "subQueue[" + i + "]:";
result += listQueue(subQueues[i]);
result += "\n";
}
System.out.println(result);
} /**
* 列举某队列中数据项
*
* 方法使用了一个临时队列来完成数据轮循
* 先从目标队列中逐个取出(采用取出并删除的方式)放入临时队列并做列举操作(连接到返回字符串)
* 待轮循完成后再将临时队列中的数据存入回目标队列
*
* @param queue 目标队列
* @return 包含目标队列中所有数据的字符串
*/
private String listQueue(LinkedList<Integer> queue) {
LinkedList<Integer> temp = new LinkedList<Integer>();
String result = "{ "; while (!queue.isEmpty()) {
Integer removed = queue.remove();
result += removed + " ";
temp.offer(removed);
}
result += "}\n"; while (!temp.isEmpty()) {
Integer removed2 = temp.remove();
queue.offer(removed2);
}
return result;
} public static void main(String[] args) {
char input1;
String inputInfo = new String();
String line = new String(); RadixSort sort1 = new RadixSort(); try {
// 打印菜单
printMenu(); // 创建流读取器读取用户输入
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader stdin = new BufferedReader(isr); do {
System.out.print("你想进行什么操作?\n");
line = stdin.readLine().trim(); // 读取一行
input1 = line.charAt(0);
input1 = Character.toUpperCase(input1); if (line.length() == 1) // 检查输入指令是否为单个
// 字符
{
switch (input1) {
case 'A': // 添加一个数值
System.out.print("请输入要添加的数值:\n");
inputInfo = stdin.readLine().trim();
int num = Integer.parseInt(inputInfo);
sort1.add(num);
System.out.print("数值添加成功\n");
break;
case 'L': // 列举数值
sort1.listMainQueue();
break;
case 'Q': // 退出
break;
case 'S': // 排序
sort1.sort();
System.out.print("排序完成\n");
break;
case '?': // 显示帮助
printMenu();
break;
default:
System.out.print("未知指令\n");
break;
}
} else {
System.out.print("未知指令\n");
}
} while (input1 != 'Q' || line.length() != 1);
} catch (IOException exception) {
System.out.print("IO Exception\n");
}
} /** 打印控制台界面(菜单) */
public static void printMenu() {
System.out.print("选项\t\t动作\n" + "------\t\t------\n"
+ "A\t\t添加一个数值\n" + "L\t\t列举队列\n"
+ "Q\t\t退出\n" + "S\t\t排序数据\n"
+ "?\t\t显示帮助\n\n");
}
}

  我们直接看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

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

 选项        动作
------ ------
A 添加一个数值
L 列举队列
Q 退出
S 排序数据
? 显示帮助 你想进行什么操作?
a
请输入要添加的数值:
539
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
264
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
372
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
424
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
419
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
129
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
322
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
544
数值添加成功
你想进行什么操作?
a
请输入要添加的数值:
367
数值添加成功
你想进行什么操作?
l
mainQueue = { 539 264 372 424 419 129 322 544 367 }
你想进行什么操作?
s
subQueue[0]:{ }
subQueue[1]:{ }
subQueue[2]:{ 372 322 }
subQueue[3]:{ }
subQueue[4]:{ 264 424 544 }
subQueue[5]:{ }
subQueue[6]:{ }
subQueue[7]:{ 367 }
subQueue[8]:{ }
subQueue[9]:{ 539 419 129 }
mainQueue = { 372 322 264 424 544 367 539 419 129 }
subQueue[0]:{ }
subQueue[1]:{ 419 }
subQueue[2]:{ 322 424 129 }
subQueue[3]:{ 539 }
subQueue[4]:{ 544 }
subQueue[5]:{ }
subQueue[6]:{ 264 367 }
subQueue[7]:{ 372 }
subQueue[8]:{ }
subQueue[9]:{ }
mainQueue = { 419 322 424 129 539 544 264 367 372 }
subQueue[0]:{ }
subQueue[1]:{ 129 }
subQueue[2]:{ 264 }
subQueue[3]:{ 322 367 372 }
subQueue[4]:{ 419 424 }
subQueue[5]:{ 539 544 }
subQueue[6]:{ }
subQueue[7]:{ }
subQueue[8]:{ }
subQueue[9]:{ }
mainQueue = { 129 264 322 367 372 419 424 539 544 }
排序完成
你想进行什么操作?
l
mainQueue = { 129 264 322 367 372 419 424 539 544 }
你想进行什么操作?
q

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

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

  好,不多说了,大家领会精神。

欢迎您移步我们的交流群,无聊的时候大家一起打发时间:

或者通过QQ与我联系:

(最后编辑时间2013-11-22 22:38:04)

数据结构与算法——基数排序简单Java实现的更多相关文章

  1. 大公司面试经典数据结构与算法题C#/Java解答

    几个大公司(IBM.MicroSoft and so on)面试经典数据结构与算法题C#解答 1.链表反转 我想到了两种比较简单的方法 第一种是需要开一个新的链表,将原链表的元素从后到前的插入到新链表 ...

  2. 【Java数据结构与算法】简单排序、二分查找和异或运算

    简单排序 选择排序 概念 首先,找到数组中最小的那个元素,其次,把它和数组的第一个元素交换位置(如果第一个元素就是最小的元素那么它就和自己交换).再次,在剩下的元素中找到最小的元素,将它与数组的第二个 ...

  3. 基数排序简单Java实现

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

  4. 排序算法-基数排序(Java)

    package com.rao.sort; import java.util.*; /** * @author Srao * @className RadioSort * @date 2019/12/ ...

  5. 数据结构与算法笔记(java)目录

    数据结构: 一个动态可视化数据结构的网站 线性结构 数组 动态数组 链表 单向链表 双向链表 单向循环链表 双向循环链表 栈 栈 队列 队列 双端队列 哈希表 树形结构 二叉树 二叉树 二叉搜索树 A ...

  6. Java数据结构和算法(六)--二叉树

    什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...

  7. java数据结构和算法01(数组的简单使用)

    一直都对这一块没有什么想法,加上不怎么理解,只是懂个大概:最近突然感觉对数据结构和算法这块有点儿兴趣,决定还是尽量详细的看看这些结构和算法: 话说什么事数据结构和算法呢?现在我也说不上来,等我学的差不 ...

  8. Java数据结构和算法 - 简单排序

    Q: 冒泡排序? A: 1) 比较相邻的元素.如果第一个比第二个大,就交换它们两个; 2) 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数; 3) 针 ...

  9. Java数据结构和算法 - 高级排序

    希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...

随机推荐

  1. 谈一下Docker与Kubernetes集群的日志和日志管理

    本文的测试环境为CentOS 7.3,Kubernetes集群为1.11.2,安装步骤参见kubeadm安装kubernetes V1.11.1 集群 日志对于我们管理Kubernetes集群及其上的 ...

  2. Implement strStr() leetcode java

    题目: Implement strStr(). Returns a pointer to the first occurrence of needle in haystack, or null if ...

  3. Android典型界面设计(5)——使用SlidingMenu和DrawerLayout分别实现左右侧边栏

    一.问题描述 侧边栏是Android应用中十分常见的界面效果,可随主屏在左侧或右侧联动,是特别适应手机等小屏幕特性的典型界面设计方案之一,常用作应用的操作菜单,如图所示 实现侧边栏可以使用第三方组件s ...

  4. Spark2.2(三十三):Spark Streaming和Spark Structured Streaming更新broadcast总结(一)

    背景: 需要在spark2.2.0更新broadcast中的内容,网上也搜索了不少文章,都在讲解spark streaming中如何更新,但没有spark structured streaming更新 ...

  5. vue Object.defineProperty Proxy 数据双向绑定

    Object.defineProperty 虽然已经能够实现双向绑定了,但是他还是有缺陷的. 只能对属性进行数据劫持,所以需要深度遍历整个对象 对于数组不能监听到数据的变化 虽然 Vue 中确实能检测 ...

  6. java 除法运算只保留整数位的3种方式

      1.情景展示 根据提供的毫秒数进行除法运算,如果将毫秒数转换成小时,小时数不为0,则只取整数位,依此类推... 2.情况分析 可以使用3个函数实现 Math.floor(num)  只保留整数位 ...

  7. sublime text 3-right click context menu

    dd a system wide windows explorer button " Edit with Sublime" similar to how Notepad++ doe ...

  8. Swift 柯里化

    前言 由于柯里化在业务层的应用较少,所以从 Swift 3.0 开始移除了柯里化的用法,但是 Swift 的很多底层特性是使用柯里化来表达的. 1.柯里化 1.1 柯里化简介 柯里化(Currying ...

  9. java Serializable和Externalizable序列化反序列化详解(转载)

    一.什么是序列化? “对象序列化”(Object Serialization)是 Java1.1就开始有的特性. 简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存 ...

  10. [Aaronyang] 写给自己的WPF4.5 笔记11[自定义控件-AyImageButton的过程 1/4]

    我的文章一定要对读者负责-否则不是好文章  ----       www.ayjs.net  aaronyang技术分享 文章导航: 介绍vs2013 WPF开发,属性代码相关技巧 实战AyImage ...