用 Go 语言实现常见的十大排序算法(上)

十大常见的排序算法有:

  • 冒泡排序(Bubble Sort)

  • 选择排序(Selection Sort)

  • 插入排序(Insertion Sort)

  • 希尔排序(Shell Sort)

  • 归并排序(Merge Sort)

  • 桶排序(Bucket Sort)

  • 快速排序(Quick Sort)

  • 堆排序(Heap Sort)

  • 计数排序(Counting Sort)

  • 基数排序(Radix Sort)

一个一个说

冒泡排序

冒泡排序是一种简单的排序算法,通过重复比较相邻元素并交换位置从而确定一个元素的位置,直到没有需要交换的元素

大体有两种写法,一种是从前往后比,每次确定一个较大值;一种是从后往前比,每次确定一个较小值

 func BubbleSort(arr []int) {n := len(arr)​// 1、每次确定一个较大值的位置for i := 0; i < n-1; i++ {for j := 0; j < n-i-1; j++ {if arr[j] > arr[j+1] {// 如果当前值大于下一位,就交换arr[j], arr[j+1] = arr[j+1], arr[j]}}}​// 2、每次确定一个较小值的位置for i := 0; i < n-1; i++ {for j := n - 1; j > i; j-- {if arr[j] < arr[j-1] {// 当前值小于上一位,就交换arr[j], arr[j-1] = arr[j-1], arr[j]}}}​return arr}

冒泡排序是稳定的,稳定是指相同元素在排序完后相对位置不变,例如切片[2, 1, 3, 1, 5],经过排序后第一个 "1" 还是在第二个 "1" 之前

冒泡排序的平均时间复杂度是O(n^2),在元素近似有序的情况下,会有很多没有必要的比较和交换,一种优化思路是使用标志位,如果一次循环没有发生任何元素交换,就表示切片已经有序了,直接退出就可以,不需要再往下比较,这在元素近似有序的情况下会很省时间

 func BubbleSort(arr []int) {n := len(arr)​// 使用标志位和缩小比较范围优化for i := 0; i < n-1; i++ {swapped := false // 标志位,记录这次外层循环中是否有过交换​for j := 0; j < n-i-1; j++ {if arr[j] > arr[j+1] {arr[j], arr[j+1] = arr[j+1], arr[j]swapped = true}}​// 如果一次交换都没有,说明数组已经有序了,没有必要再循环下去if !swapped {break}​}​return arr}

选择排序

选择排序的思路是,反复选择未排序部分的最小(大)元素,把它放到已排序部分的末尾

 func selectionSort(arr []int) {n := len(arr)​for i := 0; i < n-1; i++ {// 最小元素下标minIndex := ifor j := i + 1; j < n; j++ {// 找出待排序元素中最小的一个if arr[j] < arr[minIndex] {minIndex = j}}// 把找出来的最小元素放到排序好的元素末尾arr[i], arr[minIndex] = arr[minIndex], arr[i]}​return arr}

特点:时间复杂度是 O(n^2)、不稳定的(比如待排序元素为 [5, 5, 3],把 3 和 5 交换就完成了排序,但是原先在之前的 5 变成了后面)、没有明显的优化思路,

插入排序

插入排序的大概思路是,构建一个排序好的数据,把新的元素插入到适当的位置中去

 func insertionSort(arr []int) {n := len(arr)​for i := 1; i < n; i++ {// 待排序元素compare := arr[i]// 排序好的元素右边界值,因为 arr[i] 是待比较元素,所以 [0,i-1] 这一段数据是已经排好序的j := i - 1// 如果元素大于待排序元素就往右挪 腾出位置for j >= 0 && arr[j] > compare {arr[j+1] = arr[j]j--}// 把元素放到合适的位置arr[j+1] = compare}}

特点:时间复杂度为 O(n^2)、稳定,适合在元素基本有序时使用,有序时只需要少量判断就可以确定正确的位置

归并排序

归并排序是一种分治算法,把数组逐次对半分,分别对两半进行排序,然后把排序好的两半合并在一起

 // 递归地拆分数组并进行归并func mergeSort(arr []int, l, r int) {// l == r 时退出 因为此时只有一个元素if l < r {// 求中间值m := (r-l)/2 + l// 递归左半边mergeSort(arr, l, m)// 递归右半边mergeSort(arr, m+1, r)// 把排好序地两半合并merge(arr, l, m, r)}}​// 把两个已经排好序的子数组合并成一个有序数组func merge(arr []int, l, m, r int) {// 创建切片存放左右两半元素leftSize := m - l + 1 // 把中间值归左半边rightSize := r - mleftArr := make([]int, leftSize)rightArr := make([]int, rightSize)​// 复制元素 注意是左开右闭区间copy(leftArr, arr[l:m+1])copy(rightArr, arr[m+1:r+1])​// 遍历左右半边元素 挑出小的写回到待排序数组中i, j, k := 0, 0, lfor i < leftSize && j < rightSize {if leftArr[i] <= rightArr[j] {arr[k] = leftArr[i]i++} else {arr[k] = rightArr[j]j++}k++}​// 复制剩余元素 不处理两半不均等时会漏元素for i < leftSize {arr[k] = leftArr[i]i++k++}​for j < rightSize {arr[k] = rightArr[j]j++k++}}

单看代码有点难理解,用一个例子来看排序的整个过程

比如现在有切片 arr = [2, 3, 1, 5]

通过 mergeSort(arr, 0, len(arr) - 1) 排序,整个流程为:

看图示流程就会比较清晰,先把左半边元素拆到底,逐个合并,使左半边元素有序,再处理右半边,把右半边也处理完,再合并左右半边,最终排序完成

特点:时间复杂度为 O(n log n)、稳定

改进思路:在元素量较小的时候,比如 10 或 20 个元素,使用插入排序比双指针要稍快一点,可以在排序过程中增加一个阈值,当子切片的长度小于该值时,使用插入排序

桶排序

大概思路是生成一些桶,把元素分布到不同的桶中,对每个桶再单独进行排序(可以使用任何排序方法,选择排序、插入排序等等),再将元素依次取出,需要注意,后一个桶中的每一个元素都要大于前一个桶中所有数据

核心点有两个:怎么确定桶的个数?哪个元素放哪个桶如何确定,即桶的索引如何确定?

对于第一个问题,桶排序适用的场景是分布均匀的浮点数,因为浮点数计算桶的索引方便一点,如果分布不均匀,可能会造成某些桶包含大量元素,某些桶只包含很少的元素,导致算法效率降低,一般来说,根据元素个数 n,桶的个数一般在 n^1/2 - n 之间

第二个问题,桶的索引计算一般基于最小值和最大值来完成,一个简单的索引计算方法:

 index := int((value - minValue) / (maxValue - minValue) * float64(bucketCount))
  • value: 当前要处理的元素

  • minValue: 在整个数组中的最小值

  • maxValue: 在整个数组中的最大值

  • bucketCount: 总的桶的数量

简单解释这条公式,(value - minValue) / (maxValue - minValue) 意思是当前值减去最小值并除以范围(最大值和最小值的差值),把元素的值定位到 [0, 1] 的范围中,这样就可以获得元素相对于整个数据的位置,拿这个值乘以桶的总数,然后用 int() 转换为 int 类型作为桶的下标索引,这样就完成了简单的定位操作

完整代码:

 func bucketSort(arr []float64, bucketCount int) []float64 {if len(arr) == 0 {return arr}​// 找最大值和最小值minValue, maxValue := arr[0], arr[0]for _, value := range arr {if value < minValue {minValue = value}if value > maxValue {maxValue = value}}​// 初始化桶 用切片表示buckets := make([][]float64, bucketCount)​// 把元素分配到桶里for _, value := range arr {// 用公式计算桶的索引index := int((value - minValue) / (maxValue - minValue) * float64(bucketCount))// 如果计算出的索引越界了 手动减一if index >= bucketCount {index = bucketCount - 1}// 把元素追加到对应的桶里buckets[index] = append(buckets[index], value)}​//  对每个桶进行排序 用哪种排序方法都可以 这里用自带的排序函数sortedArr := make([]float64, 0)for _, bucket := range buckets {sort.Float64s(bucket)sortedArr = append(sortedArr, bucket...)}​return sortedArr}

总结

为避免篇幅过长,简单的介绍了前五种排序算法,总结如下:

参考:

1.0 十大经典排序算法 | 菜鸟教程 (runoob.com)

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

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

相关文章

<数据集>考场行为识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;2192张 标注数量(xml文件个数)&#xff1a;2192 标注数量(txt文件个数)&#xff1a;2192 标注类别数&#xff1a;2 标注类别名称&#xff1a;[cheating, good] 序号类别名称图片数框数1cheating128214412good1067…

气膜建筑与装配式建筑的对比分析—轻空间

在现代建筑中&#xff0c;气膜建筑和装配式建筑都作为新型建筑形式受到关注。然而&#xff0c;在很多应用场景中&#xff0c;气膜建筑展现出了比装配式建筑更为明显的优势。以下将着重对比气膜建筑相较于装配式建筑的独特优势。 气膜建筑的突出优势 1. 更快的施工速度 气膜建筑…

在 Debian 上安装 IntelliJ IDEA 笔记

在 Debian&#x1f4a9; 上安装 IntelliJ IDEA &#x1f4a1; 笔记 下载安装 JDK17安装 IntelliJ IDEA Community添加桌面启动项&#xff08;快捷方式&#xff09; 参考资料 下载 两个包已经下好了&#xff0c;一个JDK17&#xff0c;一个IntelliJ IDEA Community 使用 wget ur…

微信对话开放平台接口源码分享

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 接口源码 📒⚓️ 相关链接 ⚓️📖 介绍 📖 微信对话开放平台是微信官方授权的智能对话技术平台,旨在帮助开发者及非开发者快速搭建智能对话机器人(智能客服),并轻松接入微信公众号、小程序、企业微信等微信生态中的各…

netty编程之UDP

写在前面 源码 。 UDP&#xff0c;user datagram protocol,是internet协议簇中无连接的传输协议&#xff0c;因为无连接所以相比于TCP需要维护更少的信息以及网络交互&#xff0c;所以具有更高的效率。本文看下netty是如何实现的&#xff0c;和TCP方式差别不大&#xff0c;下面…

自动化作业批改系统的实现以及代码分析

作者主页: 知孤云出岫 目录 作者主页:1. 系统需求分析1.1 功能需求1.2 性能要求 2. 系统设计2.1 模块化设计2.2 数据库设计2.3 系统接口设计 3. 具体技术实现3.1 题目解析模块3.2 答案匹配模块3.3 评分模块3.4 反馈生成模块3.5 系统集成 1. 系统需求分析 在构建一个自动化的…

【数学分析笔记】第2章第4节收敛准则(4)

2.数列极限 2.4 收敛准则 上节课举了一个例子 a N 1 1 2 p 1 3 p . . . 1 n p a_{N}1\frac{1}{2^{p}}\frac{1}{3^{p}}...\frac{1}{n^{p}} aN​12p1​3p1​...np1​ p > 1 p>1 p>1&#xff0c; { a n } \{a_{n}\} {an​}收敛 0 < p ≤ 1 0<p\le 1 0<p≤…

ET6框架(一)介绍及环境部署

文章目录 一、什么是ET框架&#xff1f;二、ET框架特色&#xff1a;三、开发环境准备&#xff1a;四、.Net Core下载安装五、安装Visual Studio六、下载Mongodb七.安装Robo 3T八、下载ET版本分支 一、什么是ET框架&#xff1f; 1.ET(客户端&#xff0c;服务器端)是一个开源的双…

《机器学习》 决策树 ID3算法

目录 一、什么是决策树&#xff1f; 1、概念 2、优缺点 3、核心 4、需要考虑的问题 二、决策树分类标准&#xff0c;ID3算法 1、什么是ID3 算法 2、ID3算法怎么用 1&#xff09;熵值计算公式 2&#xff09;用法实例 三、实操 ID3算法 1&#xff09;求出play标签的熵…

欧姆龙PLC数据 转 IEC61850项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 准备工作 4 网关采集欧姆龙PLC数据 5 用IEC61850协议转发数据 6 网关使用多个逻辑设备和逻辑节点的方法 7 案例总结 1 案例说明 设置网关采集欧姆龙PLC数据把采集的数据转成IEC61850协议转发给其他系统。 2 VFBOX网关工作原理 VFBOX…

【JUC并发编程系列】深入理解Java并发机制:从用户态到内核态的探索(一、前置知识)

文章目录 【JUC并发编程系列】深入理解Java并发机制&#xff1a;从用户态到内核态的探索&#xff08;一、前置知识&#xff09;1.用户态与内核态区别2. 线程安全同步的方式3. 传统锁有哪些缺点4. 发生CPU上下文切换的原因5. 如何避免上下文切换6. 详细总结6.1 用户态与内核态6.…

Python3.11二进制AI项目程序打包为苹果Mac App(DMG)-应用程序pyinstaller制作流程(AppleSilicon)

众所周知&#xff0c;苹果MacOs系统虽然贵为Unix内核系统&#xff0c;但由于系统不支持N卡&#xff0c;所以如果想在本地跑AI项目&#xff0c;还需要对相关的AI模块进行定制化操作&#xff0c;本次我们演示一下如何将基于Python3.11的AI项目程序打包为MacOS可以直接运行的DMG安…

Python(R)均方根误差平均绝对误差导图

&#x1f3af;要点 回归模型评估指标评估薪水预测模型评估员工倦怠率模型评估大气分析生成式对抗模型目标对象缺失下&#xff0c;性能估算法追踪模型误差指标降尺度大气学模拟模型准确性评估蛋白染色质相互作用模型评估 Python回归误差指标 平均绝对误差表示数据集中实际值和…

【flask框架搭建服务器demo】Python 使用轻量级 Flask 框架搭建 Web 服务器可视化数据库数据demo

本文适合刚入门flask框架用来熟悉项目的开发人员&#xff0c;关于flask框架的组成概念一些用法请参考下面的文章 https://blog.csdn.net/qq_47452807/article/details/122289200 本文主要给出一个可视化sqlite数据库数据的demo&#xff0c;先展示一下效果&#xff1a; 主要的…

【uniapp/uview1.x】u-collapse 高度随内容自适应

当 u-collapse-items 中的内容为动态的时候&#xff0c;会发生这种情况&#xff1a; 在 uview 官网中有一个方法可以解决&#xff1a; 具体方法&#xff1a; 在 u-collapse 标签中配置 ref"collapse"&#xff1a; <u-collapse ref"collapse" :item-…

Golang | Leetcode Golang题解之第376摆动序列

题目&#xff1a; 题解&#xff1a; int wiggleMaxLength(int* nums, int numsSize) {if (numsSize < 2) {return numsSize;}int prevdiff nums[1] - nums[0];int ret prevdiff ! 0 ? 2 : 1;for (int i 2; i < numsSize; i) {int diff nums[i] - nums[i - 1];if ((…

使用notepad++将shell脚本转为UNIX格式方法(主要差别在换行符)

sh文件尽量在linux上改&#xff0c;因windows和linux换行符不同&#xff0c;在windows上改后&#xff0c;在linux上改可能会出现换行符错误。 windows换行符 linux换行符 windows环境改换行符方法 使用notepad点 编辑–》文档格式转换–》转换未unix格式。 注&#xff1a;tx…

C# 泛型类型的约束详解与示例

文章目录 一、泛型约束概述二、泛型约束详解与示例1. 类约束2. 接口约束3. 引用类型约束4. 值类型约束5. 无参数构造函数约束6、多重约束7、默认构造函数约束8、基类和接口的组合约束 三、总结 在C#编程语言中&#xff0c;泛型是一种非常强大的特性&#xff0c;它允许我们编写可…

鸿蒙卡片服务开发

首先先创建一个项目 在该项目下创建一个卡片服务 在module.json5文件下配置 {"module": {..."extensionAbilities": [{"name": "EntryFormAbility","srcEntry": "./ets/entryformability/EntryFormAbility.ets",…

Apache Tomcat与反向代理

Apache Tomcat 是一个开源的 Java Servlet 容器&#xff0c;主要用于部署和运行基于 Java 的 Web 应用程序。Tomcat 提供了一个环境&#xff0c;让开发者能够使用 Java 编写的 Web 应用程序在 Web 服务器上运行。下面是对 Tomcat 的详细介绍&#xff1a; Tomcat 的历史 Tomca…