数据结构与算法——基数排序简单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: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...
随机推荐
- leetcode344 反转字符串 c++实现
编写一个函数,其作用是将输入的字符串反转过来. 示例 1: 输入: "hello" 输出: "olleh" 示例 2: 输入: "A man, a p ...
- Spring MVC 中使用 Google kaptcha 验证码
验证码是抵抗批量操作和恶意登录最有效的方式之一. 验证码从产生到现在已经衍生出了很多分支.方式.google kaptcha 是一个非常实用的验证码生成类库. 通过灵活的配置生成各种样式的验证码,并将 ...
- sublime 3插件推荐
新建文件以及快速注释 1. SublimeTmpl 快速生成文件模板 一直都很奇怪为什么sublime text 3没有新建文件模板的功能,像html头部的DTD声明每次都要复制粘贴.用Subli ...
- A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets(中英双语)
文章标题 A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets 且谈Apache Spark的API三剑客:RDD.Dat ...
- Xilinx 常用模块汇总(verilog)【04】
作者:桂. 时间:2018-05-15 13:07:02 链接:http://www.cnblogs.com/xingshansi/p/9040472.html 前言 Xilinx 常用模块汇总(v ...
- python uuid 介绍
1. 背景知识: UUID: 通用唯一标识符 ( Universally Unique Identifier ), 对于所有的UUID它可以保证在空间和时间上的唯一性. 它是通过MAC地址, 时间戳, ...
- python学习之struct模块
class struct.Struct(format) 返回一个struct对象(结构体,参考C). 该对象可以根据格式化字符串的格式来读写二进制数据. 第一个参数(格式化字符串)可以指定字节的顺序. ...
- JS中的PadLeft、PadRight,位数不足,自动补位,String扩展方法
类似C#中的 PadLeft.PadRight方法 //方法一 function FillZero(p) { return new Array(3 - (p + '').length + 1).joi ...
- 国外程序员整理的C++资源大全
标准库 C++标准库,包括了STL容器,算法和函数等. C++ Standard Library:是一系列类和函数的集合,使用核心语言编写,也是C++ISO自身标准的一部分. Standard Tem ...
- 【Java】浅谈Java IO
注意 本文的代码,为了学习方便,简化代码复杂度,未考虑拆包.粘包等情况的处理.所以仅供学习使用,不能用于实际环境. 阻塞IO,BIO Java1.1发布的IO是BIO.阻塞地连接之后,通过流进行同步阻 ...