数据结构与算法——基数排序简单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: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...
随机推荐
- 生成springboot docker镜像 并上传到阿里云镜像厂库
1 mvn package 2 创建Dockerfile ----------------------------------------------------------------------- ...
- Duplicate复制数据库并创建物理StandBy(spfile+不同实例名)
过程和Duplicate复制数据库并创建物理StandBy类似,只是不需要重启数据库. 目的:创建standby,不重启源数据库 1设定环境如下: Primary数据库 IP 172.17.22.16 ...
- 手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis
在写代码之前我们先了解一下这三个框架分别是干什么的? 相信大以前也看过不少这些概念,我这就用大白话来讲,如果之前有了解过可以跳过这一大段,直接看代码! SpringMVC:它用于web层,相当于con ...
- ASP.NET MVC 一款可预览、裁剪头像上传组件
今天介绍一款Web上常用的头像上传组件,常用于头像上传时对用户上传的图片进行裁剪并实时预览,最终效果如下: 源代码结构: Github地址: https://github.com/FrankFan/A ...
- 如何修改mac的root密码
mac如果密码忘了,可以同过几个命令重置root密码.前提是你有执行sudo权限的用户: jackdeMacBook-Air:~ jack$ sudo bash jackdeMacBook-Air:~ ...
- 第三部分:Android 应用程序接口指南---第四节:动画和图形---第一章 属性动画及动画与图形概述
第1章 属性动画及动画与图形概述 Android提供了一系列强大的API来把动画加到UI元素中,以及绘制自定义的2D和3D图像中去.下面的几节将综述这些可用的API以及系统的功能,同时帮你做出最优的选 ...
- [svc]openssl对称非对称加密实战
OpenSSL进行aes加密解密-对称加密(symmetry) 建立文件test.txt, 特意写入中英文 # cd /tmp # echo "test测试" > test. ...
- Egret里用矢量挖圆形的洞
项目里需要用到,但是不是用在新手引导上,下面的代码可以绘制一个圆的四分之一,用四个即可拼出一个圆. private createShape(): egret.Shape { let magicNum ...
- argparse - 命令行选项与参数解析
argparse模块作为optparse的一个替代被添加到Python2.7.argparse的实现支持一些不易于添加到optparse以及要求向后不兼容API变化的特性,因此以一个新模块添加到标准库 ...
- 【iCore4 双核心板_ARM】例程五:SYSTICK定时器 实验——定时点亮LED
实验原理: 通过STM32的三个GPIO口驱动三色LED的三个通道,设定GPIO为推挽输出模式,采 用灌电流方式与LED连接,输出高电平LED灭,输出低电平LED亮,通过系统定时器实现 1s定时,每秒 ...