algo-桶排序

桶排序

桶排序是一种分布排序,将元素数组分到多个桶内,然后每个桶再分别进行排序。

其计算复杂度取决于对桶内排序所用算法、使用桶数量以及输入均匀度。

主要流程如下

  1. 建立空桶数组
  2. 将原始数组发布到各桶中
  3. 对非空桶进行排序
  4. 按照顺序从非空桶里面收集元素得到排序后的数组
func bucketSort(arr []int, numBuckets int) []int {if len(arr) <= 1 {return arr}// 根据数据最大最小值,确定桶范围minVal, maxVal := findMinMax(arr)bucketRange := (maxVal - minVal + 1) / numBuckets// 初始化桶buckets := make([][]int, numBuckets)for i := range buckets {buckets[i] = make([]int, 0)}// 分布元素到桶中for _, num := range arr {bucketIndex := (num - minVal) / bucketRangeif bucketIndex == numBuckets {bucketIndex-- // Adjusting for the last bucket}buckets[bucketIndex] = append(buckets[bucketIndex], num)}// 桶内排序for _, bucket := range buckets {bucket = insertionSort(bucket)}// 连接桶元素为排序数组sortedArr := make([]int, 0, len(arr))for _, bucket := range buckets {sortedArr = append(sortedArr, bucket...)}return sortedArr
}func findMinMax(arr []int) (int, int) {minVal, maxVal := arr[0], arr[0]for _, num := range arr {if num < minVal {minVal = num}if num > maxVal {maxVal = num}}return minVal, maxVal
}func insertionSort(arr []int) []int {for i := 1; i < len(arr); i++ {key := arr[i]j := i - 1for j >= 0 && arr[j] > key {arr[j+1] = arr[j]j--}arr[j+1] = key}return arr
}

时间复杂度分析

最坏情况下如果数据分散聚集分布,那么就很多集中在极少量的桶内,这就会使得复杂度完全取决于桶内排序算法

在均匀分布情况

  1. 初始化桶,并找到最大值

    O(n)

  2. 分布到桶

    O(n)

  3. 若桶内排序位插入排序

    O ( n 2 k + n ) O(\frac{n^2}{k}+n) O(kn2+n),其中k为桶数量

  4. 聚合成排序数组

    O(k)

优化

一种常见的优化是先将桶中未排序的元素放回原始数组中,然后对整个数组运行插入排序。因为插入排序的运行时间是基于每个元素与最终位置的距离,所以比较的次数仍然相对较少,并且通过将列表连续存储在内存中可以更好地利用内存层次结构

如果输入分布是已知的或可以估计的,通常可以选择包含恒定密度的桶(而不仅仅是具有恒定大小)。这便能在即使分布非均匀情况下,也能保证性能

基数排序

基数排序可以理解为一种特别的桶排序,桶分布的规则是根据数字或者映射后数字的位数来决定的,而桶内排序则是由所有位的位数排序来达成的

时间复杂度为O(nw),n为数据量,w则为最长位数

  1. 将桶分为10个
  2. 从最低位开始,根据位的数字分配到相应桶
  3. 这样从最低位到最高位排序完成之后就得到一个有序数组。

由于基数排序是根据之前排序完成之后的顺序去进行下一位的排序,因此在下一位相同的情况下,之前位的顺序依然是相对一致的。

代码实现如下

func radixSort(nums []int) []int {mx := getMax(nums)exp := 1// 从低位到高位进行排序for mx/exp > 0 {nums = countSort(nums, exp)exp *= 10}return nums
}func countSort(nums []int, exp int) []int {n := len(nums)output := make([]int, n)count := make([]int, 10)// 统计当前位各个数字的个数for i := 0; i < n; i++ {count[nums[i]/exp%10]++}// 计算小于等于当前数字的总个数for i := 1; i < 10; i++ {count[i] += count[i-1]}// 根据之前小于等于的总个数获取到在当轮基数排序中的位置for i := n - 1; i >= 0; i-- {j := nums[i] / exp % 10output[count[j]-1] = nums[i]count[j]--}// 更新排序后的数组for i := 0; i < n; i++ {nums[i] = output[i]}return nums
}func getMax(nums []int) int {mx := nums[0]for i := 1; i < len(nums); i++ {if nums[i] > mx {mx = nums[i]}}return mx
}

基数排序在元素范围较小时非常快,但要求更多的空间,以及缺少更多的灵活性

一种特别的应用场景是适合于顺序访问

MSD

MSD(Most Significant Digit)相比于上面的LSD(Least SIgnificant Digit)提出了新的思路。其从高位到低位进行递归排序

主要思路就是

  1. 根据当前位分到不同桶
  2. 然后对于大于2的桶,递归下一个低位进行排序
  3. 最后将所有排序好的桶组合到返回值

相比于LSD,MSD适合不定长的变量,但不稳定(也可以稳定,但实现更为复杂),性能更差些

另一个MSD独特的优势点就是MSD能够更好利用并发

func MSDRadixSort(nums []int, d int) {// 若已经到达最低位,或者桶内元素低于两个,直接返回if len(nums) <= 1 || d <= 0 {return}// 根据当前位放置到桶里buckets := make([][]int, 10)for i := 0; i < len(buckets); i++ {buckets[i] = make([]int, 0)}for _, num := range nums {digit := num / power(10, d-1) % 10buckets[digit] = append(buckets[digit], num)}// 对每个桶往下位递归基数排序var i intfor _, bucket := range buckets {MSDRadixSort(bucket, d-1)copy(nums[i:], bucket)i += len(bucket)}
}func power(base, exp int) int {ans := 1for i := 0; i < exp; i++ {ans *= base}return ans
}

应用场景

  • 适用于对空间不太敏感的场景且数据分布不是特别聚集
  • 对于大量数据难以一次在内存中排序的

Ref

  1. https://en.wikipedia.org/wiki/Bucket_sort
  2. https://en.wikipedia.org/wiki/Radix_sort

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/668629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文讲透ast.literal_eval() eval() json.loads()

文章目录 一文讲透ast.literal_eval() eval() json.loads()1. ast.literal_eval()2. eval()3. json.loads()4. 总结 一文讲透ast.literal_eval() eval() json.loads() 在Python库中&#xff0c;我们经常会遇到需要将字符串转换为相应对象或数据结构的情况。在这种情况下&#…

ShardingSphere 5.x 系列【5】Spring Boot 3 集成并实现读写分离

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 概述2. 使用限制3. 案例演示3.…

ReactNative实现文本渐变

我们直接上图&#xff0c;可以看到上面文本的效果&#xff0c;使用SVG实现 1.首先还是要引入react-native-svg库 2.使用该库下面的LinearGradient和Text 好&#xff0c;话不多说&#xff0c;我们看具体代码 <Svg width{422} height{30} viewBox{0 0 422 30}><Defs&…

linux i2c驱动实例之ISL29035

目录 概述 1 认识ISL29035 1.1 ISL29035特征 1.2 ISL29035工作电路 1.3 ISL29035工作时序分析 1.4 ISL29035相关的寄存器 1.4.1 COMMAND-1( 0x00 ) 1.4.2 COMMAND-11&#xff08;0x01&#xff09; 1.4.3 DATA寄存器&#xff08;0x02和0x03&#xff09; 1.4.4 中断报警…

linux时钟类型

背景&#xff1a;在线程中使用wait时&#xff0c;中间修改了系统时间&#xff0c;线程一直阻塞&#xff0c;并未向下执行。 原因分析&#xff1a;wait等待时间采用了系统时间去等待&#xff0c;系统时间向后修改后&#xff0c;无法等到相应的时间点&#xff0c;从而导致线程阻…

解决Django应用部署时激活链接缺少端口号的问题

引言 在当今技术迅速发展的时代&#xff0c;前后端分离已经成为现代Web开发的一项标准实践。然而&#xff0c;当我们将这些先进的架构部署到生产环境时&#xff0c;常常会遇到一些预料之外的挑战。 问题说明 在一个典型的例子中&#xff0c;我在Windows环境下开发了一个采用…

离线环境怎么下载python依赖包

公司内网环境无网络&#xff0c;运行自动化脚本需要安装python模块 1、脚本依赖包及其版本获取&#xff0c;记录在requirements.txt中 pipreqs ./script --encodingutf8 requirements.txt注意&#xff0c;这里是将./script 里的python模块自动扫描并写入到requirements.txt中…

假期刷题打卡--Day23

1、MT1190分数乘法 输入5组分数&#xff0c;对他们进行乘法运算&#xff0c;输出结果。不考虑分母为0等特殊情况。 格式 输入格式&#xff1a; 输入整型&#xff0c;每组一行&#xff0c;如样例所示。 输出格式&#xff1a; 输出计算结果实型&#xff0c;如样例所示。 样…

[Vue3]父子组件相互传值数据同步

简介 vue3中使用setup语法糖&#xff0c;父子组件之间相互传递数据及数据同步问题 文章目录 简介父传子props传递值 使用v-bind绑定props需要计算toRefcomputed emit传递方法 使用v-on绑定 子传父expose v-model总结 父传子 props传递值 使用v-bind绑定 父组件通过props给子…

Python基础知识:Python与序列相关的内置函数

与序列相关的内置函数如表所示。 与序列相关的内置函数 函数的作用 len(seq) 计算序列的长度&#xff08;包含多少个元素&#xff09; max(seq) 查找序列中的最大元素 min(seq) 查找序列中的最小元素 list(seq) 将序列转换为列表&#xff0c;注意不能转换字典 str(se…

openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围

文章目录 openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围214.1 性能因素214.2 调优范围确定 openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围 数据库性能调优通常发生在用户对业务的执行效率不满意&#xff0c;期望通过调优加快业务执行的情况下。正…

如何解决部分图片读取转化异常的问题

问题描述 接触到一个数据集&#xff0c;有个别图片在读取转化的时候出现了异常&#xff0c;由于图片之间有关联&#xff0c;导致后续图片无法时候。 解决方法 将异常的图片转为白色或者黑色的图片&#xff0c;保证其他的图片可以正常使用&#xff01;代码如下&#xff1a; …

两种方式实现文本超出指定行数显示展开收起...

需要实现这样一个功能 默认高度下文本超出隐藏&#xff0c;点击展开可查看所有内容&#xff0c;点击收起可折叠 方法一&#xff1a;通过html和css实现 代码部分 html:<div className"expand-fold"><input id"check-box" type"checkbox&qu…

【Android】240204 android studio build.gradle.kts APK名字带日期

通过Android studio 生成 APK 名字的时候&#xff0c;带年月日时&#xff0c;可以在 build.gradle 里面定义&#xff1b; 在Gradle脚本的build任务中&#xff0c;每当我构建项目时&#xff0c;我都希望获得当前时间戳&#xff0c;并将其保存到项目资源目录中的文件中。如果我理…

04-尚硅谷Vue_Vue中的ajax

文章目录 1. 解决开发环境 Ajax 跨域问题 【前端】尚硅谷Vue2-Vue3全家桶笔记目录贴 1. 解决开发环境 Ajax 跨域问题

Camunda会签、或签、比例签

&#x1f496;专栏简介 ✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。 ✔️文章中只包含演示核心代码及测试数据&#xff0c;完整代码可查看作者的开源项目snail-camunda ✔️请给snail-camunda 点颗星吧&#x1f618; &#x1f496;说在前面 …

EasyX图形库学习(二、文字输出)

目录 一、文字绘制函数 字体属性结构体:logfont 文字输出 outtextxy 在指定位置输出字符串。 ​编辑 但如果直接使用,可能有以下报错&#xff1a; 三种解决方案&#xff1a; 将一个int类型的分数,输出到图形界面上 如果直接使用&#xff1a; 会把score输入进去根据A…

【C/C++ 13】C++11高效特性

目录 一、初始化列表 二、auto 三、decltype 四、可变参数列表 五、lambda表达式 C11在C98的基础上增添了许多特性&#xff0c;但是同时也使得C程序的开发变得复杂繁琐&#xff0c;让众多开发者苦不堪言&#xff0c;于是我们需要从C11新增舔的特性中选择一些能够提高开发效…

ROS从入门到精通4-1:Docker安装与常用命令总结

目录 0 专栏介绍1 Docker与机器人应用2 Docker安装步骤3 Docker常用命令3.1 创建与启动容器3.2 暂停与删除容器3.3 容器文件拷贝3.4 构建镜像与上下文 0 专栏介绍 本专栏旨在通过对ROS的系统学习&#xff0c;掌握ROS底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS进…

【文件增量备份系统】前端项目构建

文章目录 创建项目安装项目依赖引入element plus组件下载组件在main.js中使用组件测试 整合路由router下载组件创建路由管理器index.js使用路由App.vue上面使用 <router-view />测试 整合axios下载组件工具类axiosRequest.js工具类使用 创建项目 damwangrunqindeMBP dev…