线性时间排序

 

  各种排序算法总结已经介绍了几种能在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. java键盘录入

    System.out:标准输出设备(默认是:控制台) System.in:标准输入设备(默认是:键盘) --------------------- InputStream in = System.in ...

  2. Python网络编程——编写一个简单的回显客户端/服务器应用

    今天将python中socket模块的基本API学习完后,照着书上的实例编写一个套接字服务器和客户端.采用python3.5版本,在注释中会标明python2和python3的不同之处. 1.代码 ( ...

  3. Python网络编程——通过指定的端口和协议找到服务名

    1.通过指定的端口和协议找到对应的服务名,采用socket中getservbyprot()函数实现. import socket def find_service_name(): protocolna ...

  4. dzz使用总结(添加云盘,好用的Web文件管理器,网络播放器)

    dzz添加云盘: http://www.lebook.me/book/22822#fid_3990471 呆萌http://pan.diemoe.net/s/GcdFI4 网络播放器 mediaele ...

  5. java学习之网络编程之echo程序

    服务端的实现 package com.gh.echo; import java.io.*; import java.net.*; /** * echo服务器程序 * 实现 不断接收字符串 ,然后返回一 ...

  6. Surround the Trees(凸包求周长)

    Surround the Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  7. linux搭建java环境

    建议使用EXCEL查看 准备文件 apache-tomcat-7.0.57.tar tomcat web容器 server-jre-7u76-linux-x64.tar  java jdk java执 ...

  8. 打印NSLog分类 Foundation+Log.m

    #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @implementation UIView(Log) + ...

  9. BZOJ 1006: [HNOI2008]神奇的国度( MCS )

    弦图最小染色...先用MCS求出完美消除序列然后再暴力染色... ------------------------------------------------------------------- ...

  10. BZOJ 1103: [POI2007]大都市meg( 树链剖分 )

    早上数学考挂了...欲哭无泪啊下午去写半个小时政治然后就又可以来刷题了.. 树链剖分 , 为什么跑得这么慢... ------------------------------------------- ...