线性时间排序

 

  各种排序算法总结已经介绍了几种能在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. ASP.NET页面传值的几种方式

    页面传值是学习asp.net初期都会面临的一个问题,总的来说有页面传值. 存储对象传值.ajax.类.model.表单等!下面欧柏泰克和大家一起来看看asp.net页面传值方式一般有哪些?常用的较简单 ...

  2. CSS中overflow:hidden

    CSS中,overfllow:hidden的作用是隐藏溢出 比如:<div style="width:300px;overflow:hidden" id=1><d ...

  3. [置顶] 关于CSDN2013博客之星的一些看法

    最近一个周,最火的话题当然要数CSDN2013博客之星拉票了. 实话实说,从12月14日开始,我连续5天拉票. 通过QQ群.QQ好友.CSDN文章.给CSDN粉丝发私信等多种方式拉票,真是累死我了. ...

  4. LNMP一键安装包sh脚本

    Xshell 5 (Build 0719) Copyright (c) 2002-2015 NetSarang Computer, Inc. All rights reserved. Type `he ...

  5. Nginx阅读笔记(三)之proxy_pass用法

    在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走,如果没有/,则会把匹配的路径部分也给代理走. 假设访问 ...

  6. maven安装jar到本地仓库

    class12.jar这个东西在中央仓库里没有,所以,cmd到oracle\product\10.2.0\db_1\jdbc\lib路径下,mvn install 就好了(发布第三方jar到本地库) ...

  7. c显示数字的LED(数字转LED)

    实现这么一个函数:传入一个int值,在屏幕输出类似LED显示屏效果的字母拼图,例如: 输入1234567890,输出: 请注意每个字符的固定宽度和高度,两个数字间保留一个空格. 函数名:void LE ...

  8. 基于visual Studio2013解决C语言竞赛题之0409 100以内素数

       题目 解决代码及点评 在已经知道素数是怎么判断的基础上,增加循环,可以判断出100以内的素数 /******************************************* ...

  9. prim模板

    ]; int n; ][]; ]; int prim(){ int i,j,mi,v; ;i<n;i++){ d[i]=map[][i]; vis[i]=; } ;i<=n;i++){ m ...

  10. [置顶] NGINX原理分析之SLAB分配机制

    一.基础概述 如果使用伙伴系统分配和释放算法,不仅会造成大量的内存碎片,同时处理效率也比较低.SLAB是一种内存管理机制,其核心思想是预分配.SLAB是将空间按照SIZE对内存进行分类管理的,当申请一 ...