线性时间排序

 

  各种排序算法总结已经介绍了几种能在O(n*log(n))时间内培训n个数的算法。归并排序和堆排序达到了最坏情况下的上界;快速排序在平均情况下达到该上界。这些算法都有一个有趣的性质:在排序的最终结果中,各元素的次序依赖于它们之间的比较。这类算法为比较算法,还有一类算法是线性时间复杂度的排序算法,有计数排序、基数排序和桶排序,当然,这些算法使用运算而不是比较来确定排序顺序的。

1 计数排序

  计数排序假设n个输入元素中的每一个都是0到n区间的一个整数,其中n是某个整数。计数排序的思想是:对每一个输入元素x,确定小于x的元素个数,利用这里信息可以直接把x放到它在输出数组中的位置了。例如,如果有5个元素小于x,则x最后应该放在第6个输出位置上(也就是下标为5)。当几个元素相同时,这一方案要修改一下,因为不能将相同的元素放到一个输出位置上。

  计数排序是稳定的,即具有相同元素值的元素在数组中的先后位置在排序前后不发生改变。计数排序通常被用作基数排序的一个子过程。以下代码是计数排序的Java实现。

// 排序区间范围是[0, MAX)
private final static int MAX = 100; public void countSort(int[] arr) {
// 临时存放排序的输出
int[] aux = new int[arr.length];
// 提供临时存储空间
int[] count = new int[MAX + 1]; // 1.频率统计
for (int i = 0; i < arr.length; i++) {
count[arr[i] + 1]++;
}
//2.频率转换为索引
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// 3.将元素分类
for (int i = 0; i < arr.length; i++) {
aux[count[arr[i]]++] = arr[i];
}
// 4.回写
for (int i = 0; i < arr.length; i++) {
arr[i] = aux[i];
}
}

2 基数排序

  基数排序(radix sorting)将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。 然后从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

  基数排序的方式可以采用LSD(Least sgnificant digital)或MSD(Most sgnificant digital),低位优先的字符串排序(LSD)依赖于键索引计数法,相当于从右到左对字符串中每一个字符进行键索引排序,最后整个字符串数组也就排好序了。而MSD则相反,由键值的最左边开始。以下代码是基数排序的Java实现。

public void radixSortInternal(String[] arr, int index) {
String[] aux = new String[arr.length];
int[] count = new int[26 + 1]; // 1.频率统计
for (int i = 0; i < arr.length; i++) {
count[arr[i].charAt(index) - 'a' + 1]++;
}
//2.频率转换为索引
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// 3.将元素分类
for (int i = 0; i < arr.length; i++) {
aux[count[arr[i].charAt(index) - 'a']++] = arr[i];
}
// 4.回写
for (int i = 0; i < arr.length; i++) {
arr[i] = aux[i];
}
} public void radixSort(String[] arr) {
for (int i = arr[0].length() - 1; i >= 0; i--) {
radixSortInternal(arr, i);
}
}

3 桶排序

  桶排序假设输入数据服从平均分配,平均情况下代价为O(n)。与计数排序类似,因为对输入数据做了假设,所以其速度也很快。具体来说,计数排序假设输入数据都属于一个小区间内的整数,而桶排序则假设输入数据是由一个随机过程产生,该过程将元素均匀独立分布在[0, 1)(假设的)区间上。桶排序将[0, 1)区间划分为几个相同大小的子区间,或称为桶。因为数据量是随机独立分布在[0, 1)上的,所以一般不会出现一个桶内元素过多情况。为了得出排序结果,对每个桶中元素排序,然后遍历整每个桶就得到了排序后的元素。下图是排序过程图,以下代码是Java实现。

// 排序区间范围是[0, MAX)
private final static int MAX = 100; public void bucketSort(int[] arr) {
// 桶大小为10
TreeSet<Integer>[] bucket = new TreeSet[10];
for (int i = 0; i < 10; i++) {
bucket[i] = new TreeSet();
} for (int i = 0; i < arr.length; i++) {
bucket[arr[i] / 10].add(arr[i]);
} for (int i = 0, k = 0; i < 10; i++) {
for (Integer x : bucket[i]) {
arr[k++] = x;
}
}
}

参考资料:

  1、《算法导论》8章-线性时间排序

  2、luoxn28/algorithm_data_structure

  3、各种排序算法总结

 

几种能在O(n*log(n))时间排序的更多相关文章

  1. MySQL四种类型日志:Error Log、General Query Log、Binary Log、Slow Query Log

    MySQL Server 有四种类型的日志——Error Log.General Query Log.Binary Log 和 Slow Query Log. 第一个是错误日志,记录mysqld的一些 ...

  2. 7.5 Point-in-Time (Incremental) Recovery Using the Binary Log 使用binay log 基于时间点恢复

    7.5 Point-in-Time (Incremental) Recovery Using the Binary Log 使用binay log 基于时间点恢复 7.5.1 Point-in-Tim ...

  3. Nginx修改access.log日志时间格式

    一.修改原因 因为要获取nginx访问信息,作为开发的数据使用,但是nginx的access.log文件中的默认的时间格式是这样的: [02/Nov/2017:20:48:25 +0800] 而要求的 ...

  4. java 23种设计模式及具体例子 收藏有时间慢慢看

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...

  5. Timewarp 一种生成当中帧技术,异步时间扭曲(Asynchronous Timewarp)

    翻译: https://www.oculus.com/blog/asynchronous-timewarp/    异步时间扭曲(Asynchronous Timewarp 时间扭曲,即调整时长) 关 ...

  6. svn查看日志(show log)显示时间为1970的解决方法

    问题: 在修改文件后show log无法显示日志,上面的时间会自动在2016年和1970年间跳,而且设置不了时间.解决方法:1.编辑svnserve.conf,设置“anon-access=none” ...

  7. MVC web api 返回JSON的几种方式,Newtonsoft.Json序列化日期时间去T的几种方式。

    原文链接:https://www.muhanxue.com/essays/2015/01/8623699.html MVC web api 返回JSON的几种方式 1.在WebApiConfig的Re ...

  8. 五种C语言非数值计算的常用经典排序算法

    摘要:排序是计算机的一种操作方法,其目的是将一组"无序"的记录序列调整为"有序"的记录序列,主要分为内部排序和外部排序. 排序 排序是计算机的一种操作方法,其目 ...

  9. 一种时间复杂度为O(n)的排序方法(转载)

    原文地址:http://my.oschina.net/u/158457/blog/28536 排序的方法很特别,有点类似插入排序的味道 先看下代码 public class Sort { privat ...

随机推荐

  1. Android调用系统关机与重启功能

    我是在android源码里编译的package/apps/,因为需要调用的关机接口是不对上层开放的,在eclipse里面不能调用. 我主要是介绍调用android的关机功能,因为在调试过程中,关机的一 ...

  2. Aop编程--注解与xml的实现

    一.注解方式 1.首先引入spring对于aop编程的jar支持包,spring框架没有的包请自行在网上下载. aopalliance-alpha1.jar aspectjrt.jar aspectj ...

  3. s3c2440栈分配情况(fl2440裸机 stack)

    //2440INIT.S ;The location of stacks UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~ SVCStac ...

  4. PHP学习建议(来自老手)

    框架太多了,有一个用着,先用熟练,因为框架思想区别不大. 用熟悉一个,再看其他,就容易多.看那么多,没有一个熟悉的,还是什么也不知道. 框架还是要用熟悉才行,然后才是产品如何设计,mysql性能真的有 ...

  5. cocos2d-x游戏开发系列教程-超级玛丽07-CMGameMap(二)

    在了解地图的初始化和加载之前,我们先了解下mario的地图. 用tiled工具打开mario地图 从地图中可以看到,mario的地图有很多层构成: objects层:怪物,会动的怪物 coin层:金币 ...

  6. Selenium2使用vncserver启动firefox

    web自动化测试使用Selenium2使用vncserver启动firefox 1st startup vncserver(e.g. vncserver :1). 2nd set DISPLAY(e. ...

  7. oracle误删的表恢复

    flashback table lip_organization to before drop;

  8. H-JATG:NAND_FLASH的参数设置

    JATG:NAND_FLASH     不同的cpu同一款flash:         相同的cpu不同的flash:     相同的cpu不同厂家的的flash:

  9. 实战nginx 基础知识总结(一)1.1

    squid Squid是一个缓存Internet数据的软件,其接收用户的下载申请,并自动处理所下载的数据.当一个用户想要下载一个主页时,可以向Squid发出一个申请,要Squid代替其进行下载,然后S ...

  10. Memcache 查看列出所有key方法

    参考博文: Memcache 查看列出所有key方法 1. cmd上登录memcache telnet 127.0.0.1 11211  2. 列出所有keys stats items // 这条是命 ...