算法学习笔记(一):桶式排序及其稳定性
来源:互联网 发布:数据帧 格式 编辑:程序博客网 时间:2024/06/05 06:57
1、待排序数列的所有值在一个可枚举的范围之内;
2、待排序数列的可枚举范围不应太大。(如果值的分布还紧凑,便是极好的了。)
举个简单的例子,有如下待排序数列:
5 1 2 4 2
这个数列在1、2、3、4、5这个可枚举范围之内,且范围不大。所以很适合来个桶式排序。
有没有发现1、2、3、4、5这样的枚举多么像数组的索引那么井然有序啊?是的,这里需要引进数组了。
第一步:造桶。对这个可枚举范围建立一个对应的数组:
int[] buckets = new int[max - min + 1]; //max 为待排序数列的最大值,min 为待排序数列的最小值
这样各桶的初始状态为:
buckets[0] = 0
buckets[1] = 0
buckets[2] = 0
buckets[3] = 0
buckets[4] = 0
这个“桶”的编号(即数组的索引)对应了待排序数列的值,而每个桶要盛的东西将是对应值出现的次数。------巧妙之一
第二步:装桶。统计每个值出现的次数,并装到相应的桶中。
//dataSet为待排序数组//以上面的例子:int[] dataSet = {5, 1, 2, 4, 2};for(int i = 0; i < dataSet.length; i++) { buckets[dataSet[i]-min]++; //数组的索引从0开始,而枚举范围从1开始,通过表达式 dataSet[i]-min 就可以得到统一。记住,buckets数组是用索引来记录待排序数列的各值。}
这样各桶的状态发生了变化:
buckets[0] = 1 表示“1”出现1次
buckets[1] = 2 表示“2”出现2次
buckets[2] = 0 表示“3”出现0次
buckets[3] = 1 表示“4”出现1次
buckets[4] = 1 表示“5”出现1次
第三步:重装。这一步很重要。如何重装呢?将前一个桶所盛的数目(非桶的编号)加到后一个桶所盛的数目上。------巧妙之二
先贴代码,再解释。
for(int i = 1; i < buckets.length; i++) { buckets[i] += buckets[i-1]; // i对应了值“i+min”,表示值“i+min” 前面有了buckets[i-1]个数,这些数是小于自己本身的。也就定位了值”i+min“自身的位置}同样各桶的状态发生了变化:
buckets[0] = 1 表示“1”在有序数列中是第1个数,毫无疑问。
buckets[1] = 3 表示“2”在有序数列中是第3个数。那么有序数列中的第2个数呢,还是值“2”
buckets[2] = 3 表示“3”没出现
buckets[3] = 4 表示“4”在有序数列中是第4个数,因为前面已经有了三个小于“4”的数
buckets[4] = 5 表示“5”在有序数列中是第5个数,因为前面已经有了四个小于“5”的数
至此待排序数列的各值已有了顺序。
第四步:安排。既然知道了各值对应的在有序数组中的位置,那么我们需要做的就是建一个新数组,存放有序数列。这里有三个版本:
版本一:
int[] newDataSet = new int[dataSet.length];for(int i = 0; i < dataSet.length; i++) { newDataSet[buckets[(dataSet[i]-min)] - 1] = dataSet[i]; //注意与下面两个版本的区别}
版本二:
int[] newDataSet = new int[dataSet.length];for(int i = 0; i < dataSet.length; i++) { //注意与第三个版本的区别 newDataSet[--buckets[(dataSet[i]-min)]] = dataSet[i];}
版本三:
int[] newDataSet = new int[dataSet.length];for(int i = dataSet.length - 1; i >= 0; i--) { newDataSet[--buckets[(dataSet[i]-min)]] = dataSet[i];}
讨论一,准确性:
很显然第一个版本是错误的。当待排序数列中出现重复值时,就会出现错误。如果重复的是“0”,就看不出来。以上例为例,最后的结果是:
第二、三版本是正确的,结果均如下。
然而这两个版本仍有差异。这个差异就是稳定性。
讨论二,稳定性:
为了显示差异,我们用*来区别待排序数列中的重复值。dataSet = {5, 1, 2, 4, 2*},结果分别如下:第二个版本结果:
第三个版本结果:
所以第三个版本是稳定的,才称得上一个好算法!这也就是巧妙之三了。
好了,算是记完了流水账。至于稳定性的巧妙之处需要亲自写代码,才能更好体会!
桶式排序的图解:
那么元素 0 在有序数列的第1位,元素 5 在有序数列的第5位,元素 3 在有序数列的第3位,元素 4 在有序数列的第4位,元素 2 在有序数列的第2位。
末了,桶式排序代码如下:
public int[] bucketsort() {int min = this.min(); //min(),返回出待排序数列的最小值int max = this.max(); //max(),返回待排序数列的最大值int len = max - min + 1; //计算可枚举范围int[] buckets = new int[len];for(int i = 0; i < dataSet.length; i++) {buckets[dataSet[i]-min]++;}for(int i = 1; i < len; i++) {buckets[i] += buckets[i-1];}int[] newDataSet = new int[dataSet.length]; //有序数列for(int i = dataSet.length - 1; i >= 0; i--) {newDataSet[--buckets[dataSet[i]-min]] = dataSet[i];}return newDataSet;}
- 算法学习笔记(一):桶式排序及其稳定性
- 排序算法 及其稳定性解释
- 8种排序算法及其稳定性
- 各种排序算法思想及其稳定性总结
- 排序算法的稳定性及其意义
- 各种排序算法及复杂度稳定性分析(一)
- 一句话总结几种排序算法及其稳定性
- 八大排序算法思想,时间复杂度,稳定性、及其java实现
- 八大排序算法学习笔记:插入排序(一)
- 排序算法分析(复杂度,稳定性)
- 排序算法 (稳定性时间复杂度分析)
- 常用排序算法稳定性分析(转载)
- 排序算法稳定性
- 排序算法稳定性
- 排序算法稳定性
- 排序算法的稳定性
- 排序算法的稳定性
- 排序算法的稳定性
- 指针和引用的比较小结
- 基于 Jenkins 快速搭建持续集成环境
- Linux下Redis安装详解
- android Notification
- 字符全排列算法
- 算法学习笔记(一):桶式排序及其稳定性
- Delphi Web Service(1)
- raw和assets文件的使用
- chrome font-size<12px无效
- B. Command Line Arguments
- 泛型
- HTTP协议之缓存
- 【风宇冲】Unity3D教程宝典之Shader篇:第二十讲法线贴图
- 项目管理实践【三】每日构建【Daily Build Using CruiseControl.NET and MSBuild】