🤡博客主页:Code_文晓
🥰本文专栏:数据结构与算法
😻欢迎关注:感谢大家的点赞评论+关注,祝您学有所成!
✨✨💜💛想要学习更多数据结构与算法点击专栏链接查看💛💜✨✨
一般情形的桶排序比较少用,做个简单了解即可,为后面基于桶排序思想的计数排序和基数排序做个铺垫 《计数排序和基数排序详解》。
桶排序
桶排序将待排序序列划分成若干个区间,每个区间可形象地看作一个桶,如果桶中的记录多于一个则使用较快的排序方法进行排序,把每个桶中的记录收集起来,最终得到有序序列。
桶排序需要创建若干个桶来协助排序 每一个桶(bucket)代表一个区间范围,里面可以承载一个或多个元素。桶排序的第1步,就是创建这些桶,并确定每一个桶的区间范围具体需要建立多少个桶,如何确定桶的区间范围,有很多种不同的方式,这个比较随意。
例如,这里以 {12,18,0,91,40,66,78,89,6,27,39,22,31,55,52,97,62,45,11,80} 这组待排序的数据进行说明。
上面这组数据的范围在0~100之间,所以可以把这个区间划分成4个(该数字比较随意)大小相同的子区间(4个桶):0~25、26~50、51~75、76~100。然后把这些待排序的数据根据自身大小放入对应的桶中。如下图所示。
同一个桶中的数据可以采用数组、链表等数据结构存储。针对每一个桶中的数据进行单独的从小到大排序,再按桶的次序(从左到右)把各个桶中的数据输出出来,如下图所示。
不过,桶排序会涉及一些问题。
-
待排序数据如果分布不均匀,就会导致有的桶中数据很多,有的桶中数据很少,甚至有的桶中没有数据的情形。
-
每个桶中数据如何存储(比如是使用数组还是链表)以及桶中数据如何排序的问题。
如果用数组存储桶中数据,那么数组设置多大合适呢?如果采用可以扩容的数组,存满数据时将申请更大的内存空间,将整个数组搬到该内存空间,那么无疑会影响算法效率,而如果采用固定大小数组,那么数组就得设置为能够容纳所有待排序数据的大小,就会很浪费内存。如果采用链表,那么对桶中数据进行排序就会很不方便,时间复杂度会很高。
-
每个桶中的数据可以采用归并排序、快速排序等手段进行排序。
总之,桶排序是一种用空间换取时间的排序算法。这个算法是有一些使用限制的,要求待排序的数据均匀分布,桶的个数要设置合理以避免空桶的产生。
桶排序算法的实现代码我在这里就不提供了,并不复杂,实现方式也比较灵活。有兴趣的话你可以自行编写。
桶排序算法复杂度分析
我们先来梳理一下桶排序的时间复杂度。
-
遍历n个元素的数组(n次循环),求数据中最小值和最大值来决定桶的数量和每个桶中保存数据的范围。这个时间复杂度为O(n)。
-
遍历n个元素并装到桶中(n次循环),所以这一步的时间复杂度为O(n)。
-
假设共有k个桶(大概每个桶中平均有
个元素),k次循环对每个桶中的数据排序。如果采用快速排序方式(算法的时间复杂度为O(
),这里的 n 应该用
来代替,因为
才是桶中元素个数,所以快速排序算法时间复杂度为O(
),所以所有桶中数据排序的总时间复杂度为O(
),即O(
)。
-
结果输出的时间复杂度也是O(n)。
-
所以整个算法时间复杂度是O(
)。
-
如果使用n个桶并且待排序值分布很均匀,此时可以避免桶内数据排序,此时的时间复杂度接近O(
),此时的排序就等于是计数排序了。
-
如果数据全部放到一个桶去那就是最差的情况了,此时桶排序的时间复杂度就退化到O(
)了。
其实,桶排序算法的时间复杂度说法不一,因为内部使用的数据结构不同,实现代码不一样等。另外因为有k个桶,也涉及对 k个桶初始化,所以有些资料上给的算法时间复杂度是O()等。其实这些答案各有道理,并不建议你深究,因为本身时间复杂度也是一个估算值,既然是估算,就肯定不会非常精确。
桶排序的空间复杂度大概为O()。一般来说,如果算法的时间复杂度有所改善,那么算法的空间复杂度一般就会增加。
桶排序算法的稳定与否取决于对同一个桶中数据的排序所采用的排序算法是否稳定,比如采用快速排序,则桶排序算法是不稳定的,如果采用归并排序,则桶算法是稳定的。
一般情形桶排序的并不常用,本篇文章学习结束后推荐学习桶排序的特殊情形,《计数排序和基数排序详解》✨❤️~