算法与数据结构-常用排序算法总结2-桶排序
来源:互联网 发布:心动网络校招笔试 编辑:程序博客网 时间:2024/06/04 18:16
序言
排序算法大体可分为两种:
比较排序:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等非比较排序:基数排序,计数排序,桶排序等
本文介绍非比较排序算法中的桶排序算法。
桶排序(Bucket Sort)
原理
又称箱排序,原理为:将数组元素分到有限数量的桶子里,每个桶子再单独进行排序
- 单独排序可能使用别的排序算法(比较排序算法)或是以递归方式继续使用桶排序进行排序
桶排序的思想:映射函数。
假设有M个桶,N个数据待排,将待排序列的关键字映射到某一个桶中,该关键字即该桶中的一个元素。
一个桶中可能有多个元素,桶内可使用比较排序算法(快排、插入排序等)或者继续递归桶排序
映射函数举例说明:
- 假如待排序列K = {49、 38 、 35、 97 、 76、 73 、 27、 49 }
- 这些数据全部在1—100之间。因此我们定制10个桶,然后确定映射函数f(k) = k/10
- 那么,第一个关键字49将定位到第4个桶中(49/10 = 4)
- 依次将所有关键字全部堆入桶中,并在每个非空的桶中进行快速排序
- 最后,顺序输出每个桶中的数据就可以得到有序序列了
动态示意图:http://www.cs.usfca.edu/~galles/visualization/BucketSort.html
步骤
设置一个定量的数组当作空桶
根据映射关系,将数组元素一个个放入对应的桶中
对每个不为空的桶进行单独排序(冒泡排序,插入排序,快速排序,归并排序等)
将不为空的桶中将元素放回原数组中
要点
映射函数/关系的设计
桶内排序
时间复杂度分析
桶排序的时间复杂度分为两部分(假设元素个数为n,桶个数为M)
循环计算每个元素的桶映射函数/关系,这个时间复杂度为O(N)
假设桶内排序使用时间复杂度为O(N*logN),这个时间复杂度为∑O(Ni*logNi)
显然,桶内排序是桶排序性能好坏的决定因素。
尽量减少桶内数据的数量是提高效率的唯一办法,基于比较排序的最好平均时间复杂度只能达到O(N*logN)。为了减小时间复杂度,需尽量做到下面两点:
(1)映射函数f(k)能够将N个数据平均的分配到M个桶中,这样每个桶就有[N/M]个数据量
- (桶内元素分布不平衡将导致算法效率大大降低,如果所有数据都落在同一个桶中,则退化为一般的比较排序了)
(2)尽量的增大桶的数量。极限情况下每个桶只能得到一个数据,避开桶内数据的“比较”排序操作
桶数量越多,意味着空间浪费越大,所以在时间和空间复杂度之间需要做出权衡
最优时间复杂度:O(N)
假设N个待排数据,M个桶,平均每个桶N/M个数据,则时间复杂度为
O(N) + O(M*(N/M)*log(N/M)) = O(N + N*(logN - logM))
当N = M时,即极限情况下每个桶一个数据,桶排序的最优时间复杂度能达到:O(N)
平均时间复杂度:O(N + C)
其中C = N*(logN - logM)
M越大,效率越高。“桶越多,效率越高”
空间复杂度分析
桶排序的空间复杂度为:O(N + M)
当输入数据量很大,桶数量也非常多时,空间代价相应也增大
评价
桶排序是稳定的
桶排序利用函数的映射关系,减少了几乎所有的比较工作。
- 实际上,桶排序的f(k)值的计算,其作用就相当于快排中划分,希尔排序中的子序列,归并排序中的子问题,已经把大量数据分割成了基本有序的数据块(桶)。然后只需要对桶中的少量数据做先进的比较排序即可。
计数排序与桶排序比较:
- 桶排序算是计数排序的一种改进和推广,比计数排序更为复杂
基数排序与桶排序的比较:
基数排序的性能比桶排序要略差。
- 每一次关键字的桶分配都需要O(N)的时间复杂度,而且分配之后得到新的关键字序列又需要O(N)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2N) ,当然d要远远小于N,因此基本上还是线性级别的。基数排序的空间复杂度为O(N+M),其中M为桶的数量。一般来说N>>M,因此额外空间需要大概N个左右。
但是,对比桶排序,基数排序每次需要的桶的数量并不多。而且基数排序几乎不需要任何“比较”操作,而桶排序在桶相对较少的情况下,桶内多个数据必须进行基于比较操作的排序。因此,在实际应用中基数排序的应用范围更加广泛。
Code Example
/**************************************功能:桶排序参数: pos:第pos位 n:数组元素个数**************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 10 //数组元素个数 struct barrel { int node[N]; int count; //元素个数 }; /* 输出函数 */ void PrintArr(int arr[],int n) { for(int i = 0; i < n; ++i) printf("%d ", arr[i]); printf("\n"); } /* 直接插入排序 */ void InsertionSort(int array[], int count) { for (int i = 0; i < count; i++) { int temp = array[i]; int j = i; while (j - 1 >= 0 && temp < array[j - 1]) { array[j] = array[j - 1]; j--; } array[j] = temp; } } /* 桶排序函数 */ void BucketSort(int data[], int n) { int max, min, bucket_num, pos; int i, j, k; struct barrel *pBarrel; //提取数组最大最小值,确定映射关系 max = min = data[0]; for (i = 1; i < n; i++) { if (data[i] > max) { max = data[i]; } else if (data[i] < min) { min = data[i]; } } bucket_num = (max - min + 1) / 10 + 1; //桶空间分配即初始化 pBarrel = (struct barrel*)malloc(sizeof(struct barrel) * bucket_num); memset(pBarrel, 0, sizeof(struct barrel) * bucket_num); //数组元素放入桶内 for (i = 0; i < n; i++) { k = (data[i] - min + 1) / 10; //应放入哪个桶内 (pBarrel + k)->node[(pBarrel + k)->count] = data[i]; (pBarrel + k)->count++; //计数 } //桶内排序 pos = 0; for (i = 0; i < bucket_num; i++) { //直接插入排序 InsertionSort((pBarrel+i)->node, (pBarrel+i)->count); //桶内排序完成即输出 for (j = 0; j < (pBarrel+i)->count; j++) { data[pos++] = (pBarrel+i)->node[j]; } } free(pBarrel); } int main() { int data[] = {78, 17, 39, 26, 72, 94, 21, 12, 23, 91}, i; int n = sizeof(data) / sizeof(int); //函数调用 BucketSort(data, n); //输出 PrintArr(data, n); return 0; }
注:
以上桶排序算法元素采用结构体方式存储,为了易于变更和操作,在实际应用中可采用链表方式,可参考文章:http://hxraid.iteye.com/blog/647759
桶内排序使用了直接插入排序,可修改为其他比较排序算法,比如快排、归并、冒泡等
Acknowledgements:
http://blog.csdn.net/han_xiaoyang/article/details/12163251#t139(推荐,桶排序的应用实例)
http://blog.csdn.net/houapple/article/details/6480100
https://segmentfault.com/a/1190000003054515
2017.08.09
- 算法与数据结构-常用排序算法总结2-桶排序
- 算法与数据结构-常用排序算法总结2-计数排序
- 算法与数据结构-常用排序算法总结2-基数排序
- 算法与数据结构-常用排序算法总结1-比较排序
- 数据结构常用排序算法总结
- 【数据结构与算法】【排序】总结
- 数据结构与算法-排序总结
- 常用数据结构与算法之排序算法
- 《数据结构与算法分析》排序算法总结
- 【数据结构与算法】-常见排序算法总结
- 【数据结构与算法】【排序算法】排序算法总结
- 简单数据结构总结及常用排序算法
- 数据结构几种常用排序算法总结
- 数据结构排序算法总结
- 数据结构排序算法总结
- 数据结构排序算法总结
- 数据结构排序算法总结
- 数据结构排序算法总结
- GitLab 结合 sourceTree 图形化管理使用
- UISnapBehavior-动画效果:迅猛移动弹跳摆动
- PHP 获取二维数组中某个key的集合
- JAVA学习(六)
- Ubuntu 打开命令行终端窗口的几种方式
- 算法与数据结构-常用排序算法总结2-桶排序
- 轻量级的 jquery 自定义弹窗插件 用法简单
- Cain使用教程
- c++ 高精度加法
- Maven使用Tomcat组件出现错误的解决方案
- qcom modem 名词缩写
- 将博客搬至CSDN
- XML解析错误:XML或文本声明不在实体的开头
- JNI编程(一) —— 编写一个最简单的JNI程序