记数排序 & 桶排序 & 基数排序
为什么要写这样滴一篇博客捏...因为一个新初一问了一道水题,结果就莫名其妙引起了战斗。
然后突然发现之前理解的桶排序并不是真正的桶排序,所以写一篇来区别下这三个十分相似的排序辣。
老年菜兔的觉醒!!!
记数排序
记数排序是一种很快的排序算法,但是要很多的空间。
具体的操作:

比如说给一个这样的数列: 6 9 3 2 3 5
我萌需要一个数组 a[i] 表示 数列中 数值为 i 的有多少个
这样 就可以 O(n) 处理出这个数组
read(x);
a[x]++;
比如辣个栗子的a数组是这样滴
| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| a[i] | 0 | 1 | 2 | 0 | 1 | 1 | 0 | 0 | 1 |
然后这个数组有什么用捏
可以发现,只需要枚举 i (如栗子里是 1≤i≤9 )
然后输出 a[i] 个 i 后就是一个从小到大排序后的数列
for i= to do (通常可以取数列中的最大数max,这里取栗子的9)
for j= to a[i] do
write(i,' ');
这样之后就会输出 2 3 3 5 6 9
这就是记数排序(老年菜兔之前把计数排序误以为是桶排序QAQ)
效率基本为 O(N) 但是有一个缺陷,就是当数列的值十分十分大的时候,数组就开不下了。
这个问题怎么解决好捏,就是桶排序和基数排序辣!
桶排序
桶排序实际上是对计数排序的一些优化,他把时间又换回了一部分空间(计数排序用空间换时间)。
桶排序思想是什么捏?

继续举个栗子呀 6 9 3 2 3 5 (咦好熟悉)
首先我萌要定一个值 m 这个值可以任意定,但会影响到效率。
m是干什么用的?
不如这样理解一下,计数排序实际上就是用了好多好多个桶 总共 max 个
而桶排序是用了 (max/m) 个桶 所以这个 m 的含义实际上是区间范围。
计数排序是桶排序的一种特殊情况,就是 取 m=1的时候。
这时我萌需要一个数组 a[i,j]表示 第 i 个桶中的第j个元素的数值。
(通常不用数组而是链表,原因是可能有这样的数据 如数列中全都是1-3范围的 这时数组就开不下,如果n十分大)
嗯列个表吧
这里我萌取 m=3 (就是举个栗子)
| 桶中数据的范围 | 1~3 | 4~6 | 7~9 |
| 相应的i(也就是第几个桶) | 1 | 2 | 3 |
| 桶内的元素 | 3,2,3 | 6,5 | 9 |
这时发现什么捏...每一个桶里的元素是无序的。
所以对每一个桶都做一个其他的排序,如快排。
然后排序后再把这些桶合并起来就好啦
诶???每一个桶?辣么效率岂不是很低。
答案是否定的,相反,桶排序效率通常比快排快。
快排的平均效率为O(n log n) 而桶排捏是 O(max/m *m log m) 即 O(max log M) 假设max=n=1000000(1百万)
快排的计算量约 23000000(2300万) 而 桶排序如果取M=2500(既省了一点空间,又有很高的时间效率) 的计算量约 12000000(1200万)
可见桶排序效率也比较高。
而且桶排序每个桶的排序算法还可以换为其他的不一定要快排。
桶排序的应用似乎不多,而似乎很多人搞混了基数排序与桶排序。
相比之下把基数排序误认为是桶排序的人会更多的样子。
所以基数排序的应用应该更广。
基数排序
基数排序的方法更是神奇,他用到了计数排序的思想。
基数排序的操作我还是要举个栗子...不过图就不放了QAQ不然水的成分有点大
如:543 123 756 666 841 322 10 799 69 (终于换了个栗子,因为上一次栗子次掉了)
基数排序的操作是这样的。
最低位(个位)为一个关键字,次低位是一个关键字...以此类推。
我萌先对最低位为关键字做一次计数排序。
如果依旧用桶来比喻的话,因为一个位数上只会有0-9 这些数字。
所以就是10个桶
列个表吧
| 桶 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
第1次操作后 桶里的元素 |
10 | 841 | 322 | 543,123 | 756,666 | 799,69 |
然后第一次操作后再合并起来就是这样的数列 (注意每一个桶内是无序的,都是按原来数列的位置)
10 841 322 543 123 756 666 799 69
还是一个无序的数列,接着对次低位为关键字做记数排序
| 桶 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
第2次操作后 桶里的元素 |
10 | 322,123 | 841,543 | 756 | 666,69 | 799 |
然后第二次操作后再合并起来就是这样的数列(注意每一个桶内依旧是无序的,都是按第一次操作后的数列的位置)
10 322 123 841 543 756 666 69 799
然后就第三低位为关键字做记数排序
| 桶 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
第2次操作后 桶里的元素 |
010,069 | 123 | 322 | 543 | 666 | 756,799 | 841 |
然后合并
10 69 123 322 543 666 756 799 841
这时排序结束,数列有序了。
是不是很神奇捏?
为什么要对每一位都做一次计数排序?
实际上就是改变位置。比如如果出现了 123 124 这样的元素,在原来数列是这样的 124 123
辣么对最低位进行计数排序就可以变成 123 124 从而改变了位置。
好了,辣基数排序的效率?
设最大值有 d 位
约O(d*n) 的效率
而d是十分小的,相比桶排序,虽然效率变低了一点,但适用于一些数值十分大的数据。
再扩充一点基排
实际上,这里使用了10个桶,辣么可不可以多用些桶捏?当然可以
我萌可以使用100个桶,将最低位和次低位看成一个整体 为一个关键字,比如 5678 此时 以78 为一个关键字 56为另一个关键字。
然后操作是一样的但是却只有 d/2个关键字了,从而效率又快了,但空间变多了,变成了100个桶。
以此类推,还有1000 10000 ...个桶。辣如果不是整10个桶行不行,当然行,这样的话需要把10进制数看为其他进制的数来做计数排序。具体就不细讲啦~
好啦~讲完啦,总结一下吧,总体来说,三个排序都是用到了计数排序的思想。
桶排序效率高,但数值过大还是无法使用,而基数排序不仅效率高了很多,而且适用数值大的数据。
老年菜兔的讲解结束啦~撒花~
记数排序 & 桶排序 & 基数排序的更多相关文章
- Python线性时间排序——桶排序、基数排序与计数排序
1. 桶排序 1.1 范围为1-M的桶排序 如果有一个数组A,包含N个整数,值从1到M,我们可以得到一种非常快速的排序,桶排序(bucket sort).留置一个数组S,里面含有M个桶,初始化为0.然 ...
- python 排序 桶排序
算法思想: 桶排序将数组分到有限数量的桶里.然后每个桶里再分别排序(使用任何算法) 当要倍排序的数组内的数值时均匀分配的时候,桶排序使用线性时间O(n) 步骤: 根据最大值.最小值.桶内数据范围设定一 ...
- 排序基础之非比较的计数排序、桶排序、基数排序(Java实现)
转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/6639353.html 比较和非比较排序 快速排序.归并排序.堆排序.冒泡排序等比较排序,每个数都必须和其他 ...
- 桶排序与基数排序代码(JAVA)
桶排序 publicstaticvoid bucketSort(int[] a,int max){ int[] buckets; if(a==null || m ...
- 计数排序和桶排序(Java实现)
目录 比较和非比较的区别 计数排序 计数排序适用数据范围 过程分析 桶排序 网络流传桶排序算法勘误 桶排序适用数据范围 过程分析 比较和非比较的区别 常见的快速排序.归并排序.堆排序.冒泡排序等属于比 ...
- 桶排序和计数排序的理解实现和比较(Java)
比较和非比较的区别 常见的快速排序.归并排序.堆排序.冒泡排序等属于比较排序.在排序的最终结果里,元素之间的次序依赖于它们之间的比较.每个数都必须和其他数进行比较,才能确定自己的位置.比较排序的优势是 ...
- 计数排序与桶排序python实现
计数排序与桶排序python实现 计数排序 计数排序原理: 找到给定序列的最小值与最大值 创建一个长度为最大值-最小值+1的数组,初始化都为0 然后遍历原序列,并为数组中索引为当前值-最小值的值+1 ...
- [C++] 习题 2.14 用队列实现桶排序
目录 前置技能 队列(已在上篇提到栈的时候顺便提到了,不再赘述) 桶排序 具体实现 由用户输入n个10以内的数,每输入i(0≤i≤9),就把它插入第i号队列中,最后把10个队列中的非空队列,按队列号从 ...
- 线性时间的排序算法--桶排序(以leetcode164. Maximum Gap为例讲解)
前言 在比较排序的算法中,快速排序的性能最佳,时间复杂度是O(N*logN).因此,在使用比较排序时,时间复杂度的下限就是O(N*logN).而桶排序的时间复杂度是O(N+C),因为它的实现并不是基于 ...
随机推荐
- Spoken English Practice(And I can't walk. Should i just stay home and pout about it?)
绿色:连读: 红色:略读: 蓝色:浊化: 橙色:弱读 下划线_为浊化 口语蜕变(2017/7/12) ...
- llvm,gcc
GCC,LLVM,Clang编译器对比 在XCode中,我们经常会看到这些编译选项(如下图),有些人可能会有些茫然,本文将对GCC4.2.LLVM GCC 4.2.LLVM compliler 2 ...
- 前端开发 - JQuery - 中
十四.jquery属性操作 attr prop <!DOCTYPE html> <html lang="en"> <head> <meta ...
- 剑指Offer——把字符串转换成整数
题目描述: 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一个合法的数值则返回0 输入描述: 输入一个字符串,包括数字字母符号,可以为空 输出描述: 如果 ...
- Linux上安装pip以及setuptools
毕竟丰富的第三方库是python的优势所在,为了更加方便的安装第三方库,使用pip命令,我们需要进行相应的安装. 1.安装pip前需要前置安装setuptools 命令如下: wget --no-ch ...
- 图解HTTP之HTTPS详解
背景:随着越来越多的主流网站已经使用了HTTPS,作为服务器端开发者,就必须了解HTTPS的优势与劣势. 在HTTP协议中有可能存在信息窃听或身份伪装等问题,而使用HTTPS通信机制可以有效地防止这些 ...
- 一行代码让python的运行速度提高100倍
python一直被病垢运行速度太慢,但是实际上python的执行效率并不慢,慢的是python用的解释器Cpython运行效率太差. “一行代码让python的运行速度提高100倍”这绝不是哗众取宠的 ...
- Hadoop的Combiner
在很多MapReduce应用的场景中,假设能在向reducer分发mapper结果之前做一下"本地化Reduce".一wordcount为样例,假设作业处理中的文件单词中" ...
- Linux 2.6 内核阅读笔记 中断和异常
2014年7月24日 中断门.陷阱门及中断门 中断是能够禁止的,能够通过告诉PIC停止对某个中断的公布.被禁止的中断是不会丢失的,在解除禁止后又会发送到CPU上. 禁止中断和屏蔽(mask)中断的不同 ...
- java中的静态分派和动态分派
多态是java的基本特征之一,多态即一个对象具有多种形态(多种表达形式,猴子是动物的一种的表现形式),例如:子类是父类的一种形态. 当方法重载时,就会涉及到多态. 1:在重载时是通过参数的静态类型,而 ...