数据结构与算法——基数排序简单Java实现
基数排序(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实现的更多相关文章
- 大公司面试经典数据结构与算法题C#/Java解答
几个大公司(IBM.MicroSoft and so on)面试经典数据结构与算法题C#解答 1.链表反转 我想到了两种比较简单的方法 第一种是需要开一个新的链表,将原链表的元素从后到前的插入到新链表 ...
- 【Java数据结构与算法】简单排序、二分查找和异或运算
简单排序 选择排序 概念 首先,找到数组中最小的那个元素,其次,把它和数组的第一个元素交换位置(如果第一个元素就是最小的元素那么它就和自己交换).再次,在剩下的元素中找到最小的元素,将它与数组的第二个 ...
- 基数排序简单Java实现
基数排序(radix sort)又称“桶子法”,在对多个正整数进行排序时可以使用.它的灵感来自于队列(Queue),它最独特的地方在于利用了数字的有穷性(阿拉伯数字只有0到9的10个). 基数排序使用 ...
- 排序算法-基数排序(Java)
package com.rao.sort; import java.util.*; /** * @author Srao * @className RadioSort * @date 2019/12/ ...
- 数据结构与算法笔记(java)目录
数据结构: 一个动态可视化数据结构的网站 线性结构 数组 动态数组 链表 单向链表 双向链表 单向循环链表 双向循环链表 栈 栈 队列 队列 双端队列 哈希表 树形结构 二叉树 二叉树 二叉搜索树 A ...
- Java数据结构和算法(六)--二叉树
什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...
- java数据结构和算法01(数组的简单使用)
一直都对这一块没有什么想法,加上不怎么理解,只是懂个大概:最近突然感觉对数据结构和算法这块有点儿兴趣,决定还是尽量详细的看看这些结构和算法: 话说什么事数据结构和算法呢?现在我也说不上来,等我学的差不 ...
- Java数据结构和算法 - 简单排序
Q: 冒泡排序? A: 1) 比较相邻的元素.如果第一个比第二个大,就交换它们两个; 2) 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数; 3) 针 ...
- Java数据结构和算法 - 高级排序
希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...
随机推荐
- 谈一下Docker与Kubernetes集群的日志和日志管理
本文的测试环境为CentOS 7.3,Kubernetes集群为1.11.2,安装步骤参见kubeadm安装kubernetes V1.11.1 集群 日志对于我们管理Kubernetes集群及其上的 ...
- Implement strStr() leetcode java
题目: Implement strStr(). Returns a pointer to the first occurrence of needle in haystack, or null if ...
- Android典型界面设计(5)——使用SlidingMenu和DrawerLayout分别实现左右侧边栏
一.问题描述 侧边栏是Android应用中十分常见的界面效果,可随主屏在左侧或右侧联动,是特别适应手机等小屏幕特性的典型界面设计方案之一,常用作应用的操作菜单,如图所示 实现侧边栏可以使用第三方组件s ...
- Spark2.2(三十三):Spark Streaming和Spark Structured Streaming更新broadcast总结(一)
背景: 需要在spark2.2.0更新broadcast中的内容,网上也搜索了不少文章,都在讲解spark streaming中如何更新,但没有spark structured streaming更新 ...
- vue Object.defineProperty Proxy 数据双向绑定
Object.defineProperty 虽然已经能够实现双向绑定了,但是他还是有缺陷的. 只能对属性进行数据劫持,所以需要深度遍历整个对象 对于数组不能监听到数据的变化 虽然 Vue 中确实能检测 ...
- java 除法运算只保留整数位的3种方式
1.情景展示 根据提供的毫秒数进行除法运算,如果将毫秒数转换成小时,小时数不为0,则只取整数位,依此类推... 2.情况分析 可以使用3个函数实现 Math.floor(num) 只保留整数位 ...
- sublime text 3-right click context menu
dd a system wide windows explorer button " Edit with Sublime" similar to how Notepad++ doe ...
- Swift 柯里化
前言 由于柯里化在业务层的应用较少,所以从 Swift 3.0 开始移除了柯里化的用法,但是 Swift 的很多底层特性是使用柯里化来表达的. 1.柯里化 1.1 柯里化简介 柯里化(Currying ...
- java Serializable和Externalizable序列化反序列化详解(转载)
一.什么是序列化? “对象序列化”(Object Serialization)是 Java1.1就开始有的特性. 简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存 ...
- [Aaronyang] 写给自己的WPF4.5 笔记11[自定义控件-AyImageButton的过程 1/4]
我的文章一定要对读者负责-否则不是好文章 ---- www.ayjs.net aaronyang技术分享 文章导航: 介绍vs2013 WPF开发,属性代码相关技巧 实战AyImage ...