news 2026/9/22 2:40:23

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

作者头像

张小明

前端开发工程师

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/9/21 8:38:38

公考日记9

不论是什么样子的&#xff08;1-4-1、1-3-2&#xff09;&#xff0c;只要是中间隔一个&#xff1a;对立面。 2&#xff09;特殊面技巧&#xff1a; 1&#xff09;相邻翻转&#xff1a;原图的基础之上 顺时针902&#xff09;横向移动4格子-结果保持不变排列组合&#xff1a;

作者头像 李华
网站建设 2026/9/21 3:59:07

Screen to Gif帧率调整的正确姿势

如何用 Screen to Gif 制作出流畅又小巧的动图&#xff1f;关键在“帧率控制”你有没有遇到过这种情况&#xff1a;辛辛苦苦录了个操作演示&#xff0c;导出的 GIF 却卡得像幻灯片&#xff0c;要么就是文件大到根本发不出去&#xff1f;点开一看&#xff0c;文字模糊、动作跳跃…

作者头像 李华
网站建设 2026/9/20 23:55:09

LangFlow走失老人定位协助流程设计

LangFlow走失老人定位协助流程设计 在城市社区中&#xff0c;走失老人的搜救往往是一场与时间赛跑的行动。黄金48小时是关键窗口&#xff0c;而现实中信息传递滞后、线索碎片化、响应链条冗长等问题&#xff0c;常常让搜寻效率大打折扣。如果能有一种方式&#xff0c;在家属刚报…

作者头像 李华
网站建设 2026/9/22 1:43:27

操作系统移植视角下的x64和arm64差异:核心要点

操作系统移植中的x64与arm64&#xff1a;从启动到内存模型的实战解析你有没有遇到过这样的情况——同一段内核代码&#xff0c;在x64上跑得好好的&#xff0c;一搬到arm64板子上就卡在earlyprintk不动了&#xff1f;或者自旋锁明明加了原子操作&#xff0c;却在多核环境下出现诡…

作者头像 李华
网站建设 2026/9/22 1:44:23

vivo X300系列凭什么更受欢迎?旗舰体验这次更到位

Counterpoint Research近期发布的市场数据显示&#xff0c;2025年第三季度vivo以18.5%的份额再度领跑中国智能手机市场。与此同时&#xff0c;vivo X300系列也在上市后快速放量&#xff1a;开售15天内全球出货量已接近50万台&#xff0c;整体销量达到上代同期约160%。亮眼的市场…

作者头像 李华
网站建设 2026/9/21 19:29:54

新手避坑指南:multisim14.3下载安装时防病毒误删技巧

新手避坑指南&#xff1a;Multisim 14.3 安装时防病毒误删的实战技巧 你是不是也遇到过这种情况——好不容易找到了 Multisim 14.3 的安装包&#xff0c;兴冲冲地开始安装&#xff0c;结果刚一运行&#xff0c;杀毒软件“叮”一声弹出警告&#xff1a;“检测到潜在威胁&#…

作者头像 李华