排序算法:插入排序,golang实现

news2025/1/12 16:05:36

目录

前言

插入排序

代码示例

1. 算法包

2. 插入排序代码

3. 模拟程序

4. 运行程序

5. 从大到小排序

插入排序的思想

循环细节

外层循环

内层循环

循环次数测试

假如 10 条数据进行排序

假如 20 条数据进行排序

假如 30 条数据进行排序

假设 5000 条数据,对比 冒泡、选择、快速、堆、归并

插入排序的适用场景

1. 小规模数据

2. 基本有序的数据

3. 稳定排序需求

4. 内存限制


前言

在实际场景中,选择合适的排序算法对于提高程序的效率和性能至关重要,本节课主要讲解"插入排序"的适用场景及代码实现。

插入排序

插入排序(Insertion Sort) 是一种简单直观的排序算法,它的工作原理是通过构建有序列表,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1) 的额外空间的排序),因而在从后向前扫描过程中,找到排序位置后,需要将已排序元素逐步向后挪动,为新元素提供插入空间。

代码示例

下面我们使用Go语言实现一个插入排序:

1. 算法包

创建一个 pkg/algorithm.go

touch pkg/algorithm.go

(如果看过上节课的选择排序,则已存在该文件,我们就不需要再创建了)

2. 插入排序代码

打开 pkg/algorithm.go 文件,代码如下

从小到大 排序

package pkg

// BubbleSort 冒泡排序
...

// SelectionSort 选择排序
...

// InsertionSort 插入排序
func InsertionSort(arr []int) {
	for i := 0; i < len(arr); i++ {
		key := arr[i]
		j := i - 1

		// 将arr[i]插入到arr[0...i-1]已排序的序列中
		for j >= 0 && arr[j] > key {
			arr[j+1] = arr[j] // 元素后移
			j = j - 1
		}
		arr[j+1] = key // 插入key
	}
}

3. 模拟程序

打开 main.go 文件,代码如下:

package main

import (
	"demo/pkg"
	"fmt"
)

func main() {
	// 定义一个切片,这里我们模拟 10 个元素
	arr := []int{456, 29, 3268, 537, 133, 772, 90, 2, 108, 299}
	fmt.Println("Original data:", arr) // 先打印原始数据
	pkg.InsertionSort(arr)             // 调用插入排序
	fmt.Println("New data:  ", arr)    // 后打印排序后的数据
}

4. 运行程序

go run main.go

能发现, Original data 后打印的数据,正是我们代码中定义的切片数据,顺序也是一致的。

New Data 后打印的数据,则是经过插入排序后的数据,是从小到大的。

5. 从大到小排序

如果需要 从大到小 排序也是可以的,在代码里,将两个元素比较的 大于符号 改成 小于符号 即可。

修改 pkg/algorithm.go 文件:

package pkg

// BubbleSort 冒泡排序
...

// SelectionSort 选择排序
...

// InsertionSort 插入排序
func InsertionSort(arr []int) {
	for i := 0; i < len(arr); i++ {
		key := arr[i]
		j := i - 1

		// 将arr[i]插入到arr[0...i-1]已排序的序列中
		for j >= 0 && arr[j] < key {
			arr[j+1] = arr[j] // 元素后移
			j = j - 1
		}
		arr[j+1] = key // 插入key
	}
}

只需要一丁点的代码即可

从 package pkg 算第一行,上面示例中在第十六行代码中,我们将 ">" 改成了 "<" ,这样就变成了 从大到小排序了

插入排序的思想

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素列表中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一个位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤 2 到 5

循环细节

外层循环

在外层循环中, for i := 0; i < len(arr); i++ ,循环变量 i 从 1 开始,直到切片 arr 的最后一个元素的前一个位置。这是因为第一个元素 (arr[0]) 默认是已排序的,所以我们从第二个元素 (arr[1]) 开始考虑如何将它插入到前面已排序的序列中

内层循环

内层循环的目的是为了找到新元素 (key) 在已排序序列中的正确位置,并将这个位置及之后的所有元素向后移动一位,为新元素腾出空间。内层循环的条件是 j >= 0 && arr[j] > key ,这意味着只要 j 没有越界,并且 arr[j] (已排序序列中的一个元素) 大于新元素 key,就执行元素的移动操作 (arr[j+1] = arr[j]) 和 j 的递减操作 (j = j - 1)。

当内层循环结束时,j + 1 就是新元素 key 应该插入的位置,因为此时 j 指向的是第一个不大于 key 的元素,或者 j 已经是 -1 (即已排序序列为空,或者 key 应该插入到序列的最前面)。然后,将 key 插入到这个位置 (arr[j+1] = key)

通过外层循环的不断迭代,整个切片 arr 将逐渐变成有序状态

循环次数测试

按照上面示例进行测试:

假如 10 条数据进行排序

外层循环了 9 

内层循环了 27 

总计循环了 36 

假如 20 条数据进行排序

外层循环了 19 

内层循环了 99 

总计循环了 118 

假如 30 条数据进行排序

外层循环了 29 

内层循环了 216 

总计循环了 245 

...

相对于 冒泡排序 和 选择排序,插入排序的循环次数减少了许多。

在平均和最坏的情况下,冒泡排序和选择排序都是 O(n^2),而插入排序在数据基本有序时可以达到 O(n)。所以在小规模数据或基本有序的数据时,插入排序通常表现较好。

假设 5000 条数据,对比 冒泡、选择、快速、堆、归并

  • 冒泡排序:循环次数 12,502,499 次
  • 选择排序:循环次数 12,502,499 次
  • 插入排序:循环次数 6,323,958 次
  • 快速排序:循环次数 74,236 次
  • 堆排序:循环次数 59,589 次
  • 归并排序:循环次数 60,288 次

插入排序的适用场景

1. 小规模数据

由于插入排序在数据规模较小的情况下,其时间复杂度为 O( n^2 ),但常数因子较小,因此实际运行效率并不低,特别是数据量很小 (如少于10个元素) 时,其效率甚至可能超过更复杂的排序算法

2. 基本有序的数据

对于已经部分排序的数组,插入排序的效率很高,因为它只需要少量的元素移动。例如,在数组末尾插入一个元素,或者数组已经是基本有序的情况下,插入排序的性能会非常好

3. 稳定排序需求

插入排序是一种稳定的排序算法,即相等元素的相对位置在排序前后不会改变。这在某些需要保持数据原有顺序的场合非常有用

4. 内存限制

由于插入排序是原地排序,它不需要额外的存储空间(除了几个变量外),这对于内存受限的环境非常有利

尽管插入排序在大数据集上表现不佳,但在上述场景下,它仍然是一种非常有用且简单的排序算法。

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

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

相关文章

Elasticsearch服务器开发教程(第2版 电子版)

前言 本书也将讨论被称为Querydsl的查询语言&#xff0c;通过它可以创建复杂的查询并过滤返回的结果。除了这些&#xff0c;你还将看到如何使用切面技术&#xff08;faceting&#xff09;基于查询结果来计算汇总数据&#xff0c;以及如何使用新引进的聚合框架&#xff08;分析…

云计算 Logstash 配置管理 Kibana数据统计分析

日志分析系统ELK 项目架构图 Logstash 是一个开源的、服务器端的数据收集引擎&#xff0c;与 Elasticsearch 和 Kibana 一起构成了 Elastic Stack&#xff08;之前称为 ELK Stack&#xff09;。Logstash 的主要功能是处理和转发数据&#xff0c;它可以从多种数据源收集数据&a…

Autowired自动注入Map问题

问题 昨天开发的时候遇到一个诡异的问题&#xff0c;通过Map注入接口下所有的子类&#xff0c;然后json打印出来的时候&#xff0c;没有子类的信息&#xff0c;并且去调用的时候报了空指针异常。 排查问题过长&#xff0c;并且涉及到源码&#xff0c;所以这里先说结论&#x…

2018-架构师案例(七)

问题1 性能需求指什么&#xff1f; 解析&#xff1a; 指响应时间&#xff0c;吞吐量&#xff0c;资源利用率等指标&#xff0c;保证系统正常运行的情况下&#xff0c;这些数据表示系统的性能。 问题2&#xff08;9分&#xff09; MemCache和Redis两种工具的优缺点&#xff0c…

js 前端 解析excel文件【.xlsx文件】信息内容

需求&#xff1a; 从excel文件中解析里面的内容 1、使用插件xlsx.full.min.js&#xff0c;地址&#xff1a;https://unpkg.com/xlsx/dist/xlsx.full.min.js实例&#xff1a; <script src"https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script><i…

【机器学习基础】数据预处理

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

【综合案例】使用DevEco Studio编写B站视频卡片

效果展示 知识点 层叠布局 介绍&#xff1a;层叠布局具有较强的 组件层叠 能力。 使用场景&#xff1a;卡片层叠效果 特点&#xff1a;层叠操作 更简洁&#xff0c;编码效率更高。【绝对定位的优势是更灵活】 Stack容器内的子元素顺序是先写的在最下面&#xff0c;即从下到上依…

数据结构与算法-二分搜索树节点删除

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、二分搜…

关于Unity四种合批技术详解

文章目录 一.静态合批(StaticBatching)1.启用静态合批2.举例说明3.静态合批的限制4.静态合批的优点缺点5.动态指定物品合批 二.动态合批(Dynamic Batching)1.启用动态合批2.合批规则3.举例说明4.使用限制 三.GPU Instancing1.启用GPU Instancing2.启用限制3.举例说明 四.SRP Ba…

构建积极心理学资源站:从零到一的旅程

自己搭建的心理学资源站 积极心理学网站&#xff1a;致力于推动积极未来 欢迎来到kuakua.app&#xff0c;这是一个致力于积极心理学的资源站。 作为一个独立开发者&#xff0c;我与一些热爱心理学的学生合作&#xff0c;创建了这个网站。 我们的目标是通过分享心理学知识和资源…

创新就业政策:智慧校园就业管理的策略之道

在智慧校园的广阔版图中&#xff0c;就业管理板块的“就业政策”功能模块犹如一颗璀璨的明星&#xff0c;照亮着学子们的未来职业道路。它不仅是一座信息的灯塔&#xff0c;指引着学生们穿越就业政策的迷雾&#xff0c;更是一把开启梦想大门的钥匙&#xff0c;帮助他们把握机遇…

2024智慧农场土地租赁家禽认养众筹实时监控商品溯源农业积分商城秒杀助农小程序源码

后端&#xff1a;系统后端使用PHP语言开发 前端&#xff1a;前端使用uniapp进行前后端分离开发 功能简介&#xff1a;土地种植、农业认养、积分商城、农场活动、视频监控、农场商城、实时数据监控、限时秒杀、农业众筹、送货上门、一键分销、农场入驻、全部店铺 运行环境&am…

《Token Contrast for Weakly-Supervised Semantic Segmentation》CVPR2023

摘要(Abstract)&#xff1a; 在弱监督语义分割&#xff08;WSSS&#xff09;中&#xff0c;传统方法通常使用类激活映射&#xff08;CAM&#xff09;生成伪标签&#xff0c;但受限于卷积神经网络&#xff08;CNN&#xff09;的局部结构感知能力&#xff0c;往往难以识别完整的对…

深入分析 Android ContentProvider (十二)

文章目录 深入分析 Android ContentProvider (十二)Android 中 ContentProvider 的系统代码分析&#xff08;续&#xff09;1. ContentProvider 的内部实现机制1.1. ContentProvider 的创建与生命周期管理1.2. ContentProvider 的数据访问与处理1.3. ContentProvider 的权限管理…

Node Red 与axios简易测试环境的搭建

为了学习在vue3中如何使用axios&#xff0c;我借Sider Fusion的帮助搭建了基于node的简易测试环境。 Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;通常用于浏览器环境&#xff0c;但它也可以在 Node.js 环境中使用。因此&#xff0c;可以在 Ubuntu 的 Bash 环境下通过…

NPDP|传统行业产品大神都是怎样管理产品的?

在传统行业中&#xff0c;产品管理不仅是技术的较量&#xff0c;更是策略、洞察力和执行力的综合体现。那些被誉为“产品大神”的经理们&#xff0c;他们如何管理产品&#xff0c;使其在市场上脱颖而出&#xff0c;成为行业内的佼佼者&#xff1f;本文将探讨他们的一些关键管理…

触发邮件接口如何与现有CRM系统无缝集成?

触发邮件接口的性能优化策略&#xff1f;如何设计高效的API接口&#xff1f; 随着企业对自动化和个性化沟通需求的增加&#xff0c;触发邮件接口的集成变得尤为重要。AokSend将探讨触发邮件接口如何与现有CRM系统无缝集成&#xff0c;以及这种集成带来的优势和挑战。 触发邮件…

c语言第七天笔记

作业题&#xff1a; 设计TVM&#xff08;地铁自动售票机&#xff09;机软件。 输入站数&#xff0c;计算费用&#xff0c;计费规则&#xff0c;6站2元&#xff0c;7-10站3元&#xff0c;11站以上为4元。 输入钱数&#xff0c;计算找零(找零时优先找回面额大的钞票)&#xff0…

与树莓派的“黄金”关系,是如何帮助这家医疗设备公司扩大规模

稳定的供应和与Raspberry Pi的“黄金”关系帮助医疗设备公司进行了规模扩张 埃及医疗设备制造商Bio Business需要将物联网功能集成到其成功的患者监测设备系列中。Raspberry Pi技术使他们得以实现。 解决方案 RP2040 Compute Module 4 企业规模 中小企业 行业 医疗技术 …

springbootJZ车行系统-计算机毕业设计源码93812

目 录 摘 要 1 绪论 1.1 研究背景与意义 1.2开发现状 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 操作可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2.4 系统流…