news 2026/3/27 4:24:34

直接插入排序、希尔排序、选择排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
直接插入排序、希尔排序、选择排序

目录

直接插入排序和希尔排序

直接插入排序

​编辑

单趟

全过程

希尔排序

简单版本希尔排序

完整版希尔排序

选择排序

算法简介

代码实现


直接插入排序和希尔排序

直接插入排序实际上可以视作是希尔排序的组件,所以我这里将直接插入排序和希尔排序放到一起了

直接插入排序

下面是直接插入排序的升序例子

我们可以看到,直接插入排序就是将一个值“拿出来”,将他和他将要插入的值的前一个值依次对比

如果拿出来的值小于该值,就将拿出来的值插入到前面比较过的位置,此时break

如果拿出来的值大于该值,就将对比后的值向后挪,继续向前遍历

单趟

void InsertSort(int* arr, int n) { int end;//按下不表,芝士拿出来的值的上一个值的下标 int temp = arr[end + 1]; while (end >= 0) { //当arr[end]大于temp是继续遍历 if (arr[end] > temp) { arr[end + 1] = arr[end]; end--; } else { break; } } arr[end + 1] = temp; }

这里我将最后插入做了统一处理

当在end>=0时找到了合适的插入位置,此时end+1位置上的数已经移动到了上一个end+1的位置上(按照此时的位置就是end+2),相当于是此时end+1上的值是无效的,此时我们将temp赋值给arr[end+1]

当在end>=0的范围内都没有找到合适得插入位置,此时end=-1(刚刚跳出循环),end+1正好是0,没有越界,也符合实际:此时temp是最小的,插到最前面。

全过程

void InsertSort(int* arr, int n) { for (int begin = 0; begin < n - 1; begin++) { int end = begin; int temp = arr[end + 1]; while (end >= 0) { //当arr[end]大于temp是继续遍历 if (arr[end] > temp) { arr[end + 1] = arr[end]; //这一步是挪动arr中的值 end--; } else { break; } } arr[end + 1] = temp; //这里将所有的情况统一处理,并处理了end = -1的边界情况 } }

这里相当于是每次都对begin+1(也是end+1)的数据进行排序

所以for循环是这样写的:

for (int begin = 0; begin < n - 1; begin++)

这里的直接插入排序实际上改几下就是希尔排序

希尔排序

希尔排序(Shell Sort),全称“缩小增量排序”(Diminishing Increment Sort),是插入排序的一种更高效的改进版本

直接插入排序在碰到全是逆序的数据使会变得非常的坑,这时,希尔排序就通过将数据大踏步的向后调整的预排序使数据更趋向于有序,从而大大减少了计算量

希尔排序的本质是分组。它不再把数组看作一个整体,而是根据一个“增量”(gap)将数组分割成若干个子序列,这个过程中所有的值都被遍历了一遍。

希尔排序通过让元素“跳跃式”地向最终位置移动,大幅减少了数据交换和移动的次数

简单版本希尔排序

我们先写一个gap=3的,只进行一次预排序的希尔排序

void ShellSort(int* arr, int n) { int gap = 3; for(int i = 0; i <gap; i++)//分组写法 { for (int begin = i; begin < n - gap; begin += gap) { int end = begin; int temp = arr[end + gap]; while (end >= i) { if (arr[end] > temp) { arr[end + gap] = arr[end]; end--; } else { break; } } arr[end + gap] = temp; } } for (int begin = 0; begin < n - 1; begin++) { int end = begin; int temp = arr[end + 1]; while (end >= 0) { if (arr[end] > temp) { arr[end + 1] = arr[end]; end--; } else { break; } } arr[end + 1] = temp; } }

这个希尔排序只进行了一次粗排,而且gap也是写死的,这实际上是不够完善的,对于大量的数据,只进行这一次预排序显然是不够的

这时我们就应该将gap写成动态的

完整版希尔排序

这里的gap取值也是有讲究的

gap取得大一点跳得更快,但是排的数据有序性较差

gap取得小一点跳得更慢,但是排的数据有序性较好

学术界经过研究得出:每次gap除3是最好的,整个排序算下来的时间复杂度是O(n^1.3)

void ShellSort(int* arr, int n) { int gap = n / 3 + 1; //这里的do_while是一个小巧思,当gap==1时可以只进行一次排序,在首个gap do { //先使用再改变gap for (int j = 0; j < gap; j++) { for (int i = j; i < n - gap; i += gap) { int end = i; int temp = arr[end + gap]; while (end >= j)//这里是一个边界条件,我们应该将预排序视作是划分了一个新的组 { if (arr[end] > temp) { arr[end + gap] = arr[end]; end -= gap; } else { break; } } arr[end + gap] = temp; } } gap = gap / 3 + 1; } while (gap > 1); }

选择排序

算法简介

选择排序是一种简单直观的排序算法。它的工作原理是:

  1. 在未排序序列中找到最小(或最大)元素

  2. 将其存放到排序序列的起始位置

  3. 然后,再从剩余未排序元素中继续寻找最小(或最大)元素

  4. 放到已排序序列的末尾

  5. 重复以上步骤,直到所有元素均排序完毕

代码实现

void SelectSort(int* arr, int n) { int begin = 0, end = n - 1; while (begin < end) { int max = begin, min = begin; for (int i = begin + 1; i <= end; i++) { if (arr[max] < arr[i]) { max = i; } if (arr[min] > arr[i]) { min = i; } } Swap(&arr[begin], &arr[min]); if (begin == max) max = min; Swap(&arr[end], &arr[max]); begin++; end--; } }

这里有一步需要解释一下

if (begin == max) max = min;

这一步是为了处理begin==max的边界情况

示例arr = [5, 1, 4, 2, 3]

第一轮循环:

  • begin = 0,end = 4

  • max = 0(arr[0]=5是最大值)

  • min = 1(arr[1]=1是最小值)

如果没有这一步的话,直接交换arr[begin]和arr[min]会导致max指向的值被移动,后面的逻辑就错了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 2:03:54

LangFlow差评应对策略建议生成

LangFlow 差评应对策略建议生成 在当前 AI 应用快速迭代的浪潮中&#xff0c;如何让非技术人员也能参与大模型产品的设计与验证&#xff1f;这个问题正变得越来越关键。许多产品经理、业务分析师甚至教育工作者都希望快速构建一个基于语言模型的原型系统——比如智能客服、知识…

作者头像 李华
网站建设 2026/3/17 18:05:26

Keil编辑器中文乱码问题系统学习路径

一文搞懂 Keil 中文注释乱码&#xff1a;从编码原理到团队规范的完整解决方案你有没有遇到过这样的场景&#xff1f;打开一个老项目&#xff0c;main.c文件里的中文注释变成“涓枃”、“鑻辨枃”&#xff0c;完全看不懂&#xff1b;或者新同事提交的代码在你电脑上显示正常&a…

作者头像 李华
网站建设 2026/3/24 5:09:44

Sprint Summary Essay

FZU Meteorological Bureau —— Alpha Sprint_Sprint Summary Essay Assignment 5Alpha SprintCourseEE308FZ — Software EngineeringClass Link2501_MU_SE_FZURequirementsFifth Assignment——Alpha SprintTeam NameFZU Meteorological BureauObjectiveAlpha Sprint Summa…

作者头像 李华
网站建设 2026/3/27 1:56:11

AUTOSAR网络管理多ECU协同配置方案实战案例

AUTOSAR网络管理实战&#xff1a;多ECU协同休眠如何做到“快唤醒、低功耗”&#xff1f;你有没有遇到过这样的场景&#xff1f;车辆锁车后&#xff0c;明明所有功能都关闭了&#xff0c;可几天后再启动却发现电瓶亏了。排查下来发现某个ECU没真正进入睡眠——只因为一个节点“睡…

作者头像 李华
网站建设 2026/3/26 21:55:45

ESP32-CAM通过UDP协议传输视频流的核心要点

如何让一块不到30元的ESP32-CAM稳定推UDP视频流&#xff1f;实战全解析你有没有试过用一个指甲盖大小的模块&#xff0c;把实时画面从阳台传到客厅电脑上&#xff1f;这不是什么高端监控系统&#xff0c;而是基于ESP32-CAM的嵌入式视觉方案。它成本低、体积小、功耗可控&#x…

作者头像 李华