排序问题思考(要求时间和空间复杂度尽可能的低)【Part 2】
继上篇博文,今天我将先介绍一下什么是计数排序,将计数排序描述清楚后,再进行后续的桶排序方法解决这个问题。
通常情况下,一提到排序,大家第一反应就是比较,其实,今天我要说的这个计数排序,不是基于比较的排序算法。
计数排序的主要思路(精髓):
针对给定的一组整数数据,在其中任意选取一个数X,统计出这组数中不比X大的所有数据的个数n,那么,此时,X的大小次序就应该在这组数的n+1的位置了。
针对这个思想,有几点要注意:
1. 给定的数组A的数据,必须都是整数
2. 给定的数据比较稀疏的情况下,效率(空间)比较差
计数排序的处理逻辑,分为下面几步:
1. 找出输入数组A中的最小值min,以及最大值max,求出数组A的元素最大距离k = max - min + 1;
2. 初始化计数数组C,其数组长度为K;
3. 统计数组A中每个元素A[i]与最小值min的差值作为C数组的下标对应的元素的个数;
4. 计算出C数组中每个元素C[j]及其之前所有元素的和作为当前元素C[j]的新值;
5. 初始化输出数组B,其长度和输入数组A的长度一样;
6. 对数组A进行倒序的方式,将数组A的元素基于其元素的个数排位,进行对输出数组赋值,其中,考虑输入元素中有重复元素的情况;
理论比较的晦涩吧,那么先上代码吧,下面是JAVA代码实现的计数排序:
/**
* @author "shihuc"
* @date 2017年1月16日
*/
package jishuSort; import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Scanner; /**
* @author chengsh05
*
*/
class InnerMaxMin {
int max;
int min;
/**
* @return the max
*/
public int getMax() {
return max;
}
/**
* @param max the max to set
*/
public void setMax(int max) {
this.max = max;
}
/**
* @return the min
*/
public int getMin() {
return min;
}
/**
* @param min the min to set
*/
public void setMin(int min) {
this.min = min;
}
}
public class CountSortDemo { /**
* @param args
*/
public static void main(String[] args) {
File file = new File("./src/jishuSort/sampleCount.txt");
Scanner sc = null;
try {
sc = new Scanner(file);
int N = sc.nextInt();
for(int i=; i<N; i++){
int S = sc.nextInt();
int A[] = new int[S];
for(int j=; j<S; j++){
A[j] = sc.nextInt();
}
int B[] = countSortResult(A);
printResult(B);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if(sc != null){
sc.close();
}
}
} /**
* 在时间复杂度为O(n)情况下,计算出最大值与最小值
*
* @param da
* @return
*/
public static InnerMaxMin getMaxMin(int da[]){
InnerMaxMin mm = new InnerMaxMin();
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i=; i<da.length; i++){
if(da[i] > max){
max = da[i];
}
if(da[i] < min){
min = da[i];
}
} mm.setMax(max);
mm.setMin(min);
return mm;
} /**
* 获取最大值与最小值之间的距离 k
* 计算逻辑步骤1
*
* @param mm
* @return k
*/
public static int getDistance(InnerMaxMin mm){
return mm.getMax() - mm.getMin() + ;
} /**
* 获取转换后的计数数组C,然后将转换后的计数数组C进行计数。 此步骤的好处,是可以减少计数数组的空间开销,掐头和掐尾。
*
*
* @param A 原数组
* @param mm 最大最小值对象
* @return 差值数组
*/
public static int[] getCountArray(int A[], InnerMaxMin mm){
int K = getDistance(mm);
int min = mm.getMin(); /*
* 初始化计数数组C。
* 计算逻辑步骤2
*/
int C[] = new int[K];
Arrays.fill(C, ); /*
* 计算出每个输入数组A中的元素自生的个数,主要考虑的是有重复的情况,所以先单独计算出每个元素自己一共出现了多少次。
* 计算逻辑步骤3
*/
for(int i=; i<A.length; i++){
int n = A[i];
C[n - min]++;
} /*
* 用到了最简单的动态规划思路,统计原始输入数组A中比X元素小的所有元素的个数之和
* 计算逻辑步骤4
*/
for(int j=; j<C.length; j++){
C[j] = C[j] + C[j - ];
} return C;
} /**
* 计数排序的总入口函数
*
* @param A
* @return
*/
public static int[] countSortResult(int A[]){
/*
* 初始化计数数组的输出数组B。
* 计算逻辑步骤5
*/
int B[] = new int[A.length];
InnerMaxMin mm = getMaxMin(A);
int C[] = getCountArray(A, mm);
int min = mm.getMin(); /*
* 将输入元素基于其每个元素对应的计数个数排序操作,映射到相应的输出数组B的位置上。
* (对于输入数组元素中不比X元素大的元素的个数为n,那么X在排序后的输出数组中的位置为n+1)
* 计算逻辑步骤6
*/
for(int i = A.length - ; i>=; i--){
B[C[A[i] - min] - ] = A[i];
C[A[i] - min]--;
}
return B;
} /**
* 显示最终排序后的结果
*
* @param B
*/
public static void printResult(int B[]){
for(int i=; i<B.length; i++){
System.out.print(B[i] + " ");
}
System.out.println();
} }
下面也附带上我的测试数据:
也附带上测试后的结果:
这个算法,是稳定的算法,性能往往比常规的比较排序要好,但是使用场景也是受限的,即参与排序的元素必须是整数,且最好不要是稀疏数组。另外,计数排序的空间消耗,相比比较排序要高。 理解计数排序的核心思想中的计算的精髓,那么这个算法就理解了。结合代码,进行理解,还是不那么难的。
排序问题思考(要求时间和空间复杂度尽可能的低)【Part 2】的更多相关文章
- 栈(stack)、递归(八皇后问题)、排序算法分类,时间和空间复杂度简介
一.栈的介绍: 1)栈的英文为(stack)2)栈是一个先入后出(FILO-First In Last Out)的有序列表.3)栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的 ...
- 原生select默认显示为空胡fish覅神农大丰今年圣诞节奋笔疾书发撒可交付你说的尽快发那段时间南方大厦尽可能放你的所发生的你富家大室耐腐蚀的看法呢尽快发你上课积啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊撒啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊分你束带结发你看
下拉框默认为空: <select> <option value="" class="blank"></option> < ...
- CDQ分治学习思考
先挂上个大佬讲解,sunyutian1998学长给我推荐的mlystdcall大佬的[教程]简易CDQ分治教程&学习笔记 还有个B站小姐姐讲解的概念https://www.bilibili.c ...
- leetcode -- 二进制
leetcode -- 二进制 在学习编程语言的运算符时,大部分语言都会有与,或等二进制运算符,我在初期学习这些运算符的时候,并没有重点留意这些运算符,并且在后续的业务代码中也没有频繁的使用过,直到后 ...
- MySQL应用优化
MySQL应用优化 目录 MySQL应用优化 1.数据库连接池 2.减少对MySQL的访问 3.负载均衡 4.MySQL查询缓存优化 5.MySQL如何使用缓存 6.MySQL内存管理以及优化 原则 ...
- LoadRunner 思考时间与事务响应时间的区别与关系
LoadRunner 思考时间与事务响应时间的区别与关系 思考时间lr_think_time 就是一个事务要开始时思考的时间;比如 你要点击一个 登录按钮 我们都要点击这个按钮要先思考下 就是人为 ...
- LoadRunner ---思考时间设置
用户访问某个网站或软件,一般不会不停地做个各种操作,例如一次查询,用户需要时间查看查询的结果是否是自己想要的.例如一次订单提交,用户需要时间核对自己填写的信息是否正确等. 也就是说用户在做某些操作时, ...
- LoadRunner 技巧之 思考时间设置
LoadRunner 技巧之 思考时间设置 用户访问某个网站或软件,一般不会不停地做个各种操作,例如一次查询,用户需要时间查看查询的结果是否是自己想要的.例如一次订单提交,用户需要时间核对自己填写的信 ...
- 算法时间复杂度、空间复杂度(大O表示法)
什么是算法? 计算机是人的大脑的延伸,它的存在主要是为了帮助我们解决问题. 而算法在计算机领域中就是为了解决问题而指定的一系列简单的指令集合.不同的算法需要不同的资源,例如:执行时间或消耗内存. 如果 ...
随机推荐
- Cells Not Under Attack
Cells Not Under Attack Vasya has the square chessboard of size n × n and m rooks. Initially the ches ...
- Android EditText的设置(转)
1.输入法Enter键图标的设置: 软件盘的界面替换只有一个属性android:imeOptions,这个属性的可以取的值有normal,actionUnspecified,actionNone,ac ...
- 转:web_reg_save_param的使用详解
[摘要]利用实际案例说明如何使用Mercury LoadRunner提取包含在 HTML 页内的动态信息并创建参数. [关键词]性能测试,压力测试,Mercury LoadRunner 应用范围 在使 ...
- PhoneGap学习(一)
1. 配置要求 Eclipse 3.4+ 这里提供一个不需要Eclipse的Terminal版本教程 2. 安装 SDK + PhoneGap 下载安装Eclipse Classic 下载安装 And ...
- Cannot find PHPUnit in include path phpstorm
This is the way to do it without using composer, and using your global phpunit.Phpunit now comes wit ...
- ASP.NET MVC---自定义HtmlHelper方法
HtmlHelper方法是ASP.NET MVC中非常强大的特性,有了这个特性,我们就能更加随心所欲的定制自己的页面. 自定义自己的HtmlHelper方法通常有三种, 像是: 一.Razor语法 采 ...
- 过实现鹰眼图这个功能来进一步学习MapControl控件
我们通过实现鹰眼图这个功能来进一步学习MapControl控件.在实现鹰眼图之前,我们需 要接口有更深入的了解. 变主动为被动-出接口(OutBound interface) COM编程类似客户端和服 ...
- Java——类谜题
1.令人混淆的构造器 代码如下格式: public class Confusing { private Confusing(Object o) { System.out.println("O ...
- [iOS]C语言技术视频-10-指针变量
下载地址: 链接: http://pan.baidu.com/s/1jGjbaXg 密码: u2t9
- tooltip 鼠标移动上去出现图片或文字与title大同小异
代码如下: <script type="text/javascript" src="jquery-1.3.2.min.js"></script ...