【排序篇】插入排序与选择排序

🌈个人主页:Yui_
🌈Linux专栏:Linux
🌈C语言笔记专栏:C语言笔记
🌈数据结构专栏:数据结构

文章目录

  • 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.2.3堆排序

1. 排序的概念及其应用

1.1 排序的概念

排序:所谓排序,就是使一连串记录,按照其中的某个或者某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假如在待排序的记录序列中,存在多个具有相同关键字的记录中,如果经过排序,这些记录的相对次序保存不变,就是说在原序列中,r[i] = r[j],且r[i]在r[j]前,然后在后序的排序后,r[i]仍在r[j]前,那么就叫这种排序是稳定的,否则就是不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存间移动数据的排序。

1.2 排序的应用场景

排序的应用场景非常广泛,任何邻域都存在竞争,只要存在竞争就会有比较,那么就有了高低之分了,比如高校排名:
排序

1.3 常见的排序算法

插入排序

  • 直接插入排序
  • 希尔排序
    选择排序
  • 选择排序
  • 堆排序序
    交换排序
  • 冒牌排序
  • 快速排序
    归并排序
  • 归并排序
    各种排序

2.常见排序算法的实现

2.1 插入排序

2.1.1 基本思想

直接插入排序是一种简单的插入排序算法,其基本思想为:

把待排序的数据按其关键码值的大小逐个插入到一个已经排好序的有序个体中,直到所有的数据插入完为止,得到一个新的有序序列。

就像我打扑克牌一样,当我们手中的牌位3 4 5 7的时候,此时摸到了6就会把6插入5和7的中间的到3 4 5 6 7的顺子。

2.1.2 直接插入排序

当插入第i(i>=1)个数据时,前面的array[0],array[1],array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2]的排序码顺序进行比较,找到插入位置便将array[i]插入,原来位置的元素顺序后移。
插入排序

#include <stdio.h>
//维持[0,end]有序
//通过比较把end+1的数据插入到[0,end]中合适的位置,来保存[0,end]的持续有序
void InsertSort(int* arr, int n)
{for (int i = 0; i < n - 1; ++i){int end = i;int tmp = arr[end + 1];//防止end+1位置的数据丢失while (end >= 0){if (tmp < arr[end]){arr[end + 1] = arr[end];end -= 1;}else{break;}}arr[end+1] = tmp;//当我们比较到最后,是tmp大于arr[end]所以tmp要在end的后面//可不能写成arr[end] = tmp,这样写程序会崩溃的}
}
int main()
{int arr[10] = { 0,9,8,7,6,5,4,3,2,1 };sort(arr, 10);for (int i = 0; i < 10; ++i){printf("%d ", arr[i]);}return 0;
}
//打印结果:
/*
0 1 2 3 4 5 6 7 8 9
*/

总结:

  1. 元素越接近有序,直接插入排序算法时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定的排序算法

2.1.3 希尔排序

希尔排序又称缩小增量法。希尔排序法的基本思想:先选定一个数,把待排序文件中所有文件分成个组,所有距离的记录分在同一组内,并对每一组内的记录进行排序。然后,取重复上述分组和排序的工作。当到达gap = 1时,所有记录在统一组内排好序。
本质就是先进行预排序,然后在用直接插入排序。预排序的目的就是为了让数组变得更加有序,而直接插入排序的效率是和数据的有序程度挂钩的,越有序效率越高。
希尔排序

如此一来,代码就好写了,既然最后一次是直接插入排序的逻辑,那么也就说明了主体代码不会有太大的变化,还有因为gap是变化的,我们用一个循环来处理gap。令初始的gap为5,后序的gap = gap/2.循环的执行条件就是gap!=0;
然后因为gap会将数组分组,后续我们就要把i限制在n-gap中了。

#include <stdio.h>
void ShellSort(int* arr, int n)
{int gap = 5;while (gap){for (int i = 0; i < n - gap; i+=1){int end = i;int tmp = arr[end + gap];while (end >= 0){if (tmp < arr[end]){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = tmp;}gap /= 2;}}
int main()
{int arr[10] = { 0,9,8,7,6,5,4,3,2,1 };sort(arr, 10);for (int i = 0; i < 10; ++i){printf("%d ", arr[i]);}return 0;
}
//打印结果
/*
0 1 2 3 4 5 6 7 8 9
*/

关于gap的取值
gap当然不是固定的,gap的取值是根据数组大小进行变化的。目前主流的gap取值是n/3+1
后续的变化也是gap = gap/3+1
修改后的代码:

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

总结:

  1. 希尔排序是对直接插入排序的优化
  2. 当gap>1时都是预排序,目的是为了让数组更接近有序。当gap = 1时,数组已经接近有序了,这样直接插入排序就会很快。整体而言,可以达到优化的效果。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法多样,导致很难取计算,因此许多书给出的希尔排序的时间复杂度都不固定
  4. 稳定性:不稳定。
    下面是一些介绍希尔排序的书籍:
    《数据结构(C语言版)》 — 严蔚敏
    《数据结构(C语言版)》 --- 严蔚敏

《数据结构-用面向对象方法与C++描述》 – 殷人昆
《数据结构-用面向对象方法与C++描述》 -- 殷人昆

2.2 选择排序

2.2.1 基本思想

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

2.2.2 直接选择排序

  • 在元素集合array[i]—array[n-1]中选择关键码最大/小的数据元素。
  • 如果它不是这组数据中的最后一个元素/第一个元素,那么将它与这组元素中的最后一个/第一个元素交换
  • 在剩余的array[i] --array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余一个元素。
    直接选择排序
#include <stdio.h>
void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void slectsort(int* arr, int n)
{for (int i = 0; i < n; ++i){int _min = i;for (int j = i; j < n; ++j){if (arr[j] < arr[_min]){_min = j;}}swap(&arr[_min], &arr[i]);}
}
int main()
{int arr[10] = { 0,9,8,7,6,5,4,3,2,1 };slectsort(arr, 10);for (int i = 0; i < 10; ++i){printf("%d ", arr[i]);}return 0;
}

总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好,实际中很少用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

2.2.3堆排序

堆排序就是利用堆的思想进行排序,总共分为两个步骤:
建堆

  • 升序:建大堆
  • 降序:建小堆
    利用向下调整建堆
    提问:为什么向下调整可以建堆
    回答:
    向下调整的关键就除了要调节的地方不对,其下方都为正确的堆。
    以下图为例:以10为根的左右子树,都满足小堆(堆)的性质,只有根节点不满足时,因此只需将根节点往下调,整合到合适的位置就可以了。
    堆

为了我只有由后往前向下调整就可以了,第一次要传的参数就是最后一个节点的父节点。然后依次传入前面是位置就可以了。

#include <stdio.h>void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}//建大堆
void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child + 1] > a[child]){child = child + 1;}if (a[child] > a[parent]){swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}int main()
{int arr[] = { 2,3,5,7,4,6,8,65,100,70,32,50,60 };//初始化一个小堆int n = sizeof(arr) / sizeof(arr[0]);for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(arr, n, i);//通过向下调整建立大堆}for (int i = 0; i < n; ++i){printf("%d ", arr[i]);}return 0;
}
//打印结果:
/*
100 70 60 65 32 50 8 3 7 4 2 5 6
*/

利用堆删除思想来进行排序
建堆和堆删除中都用到了向下调整,因此掌握了向下调整就可以完成堆排序。
提问:为什么升序需要建大堆呢?
回答:堆排序的本质是选择排序,每次都要选择一个最大的数到数组的最后一位,那么问题就变成了如何选择最大的数到数组最后一位,要找出堆中最大数就必须要用到大堆,因为大堆中最大的数就在堆堆顶,通过一次次的选择就可以将数组排序。
下面是画图解释:
堆排序

#include <stdio.h>void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}//建大堆
void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child + 1] > a[child]){child = child + 1;}if (a[child] > a[parent]){swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}int main()
{int arr[] = { 2,3,5,7,4,6,8,65,100,70,32,50,60 };int n = sizeof(arr) / sizeof(arr[0]);for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(arr, n, i);}//排序for (int end = n - 1; end >= 0; --end){swap(&arr[0], &arr[end]);AdjustDown(arr, end, 0);}for (int i = 0; i < n; ++i){printf("%d ", arr[i]);}return 0;
}
//打印结果:
/*
2 3 4 5 6 7 8 32 50 60 65 70 100
*/

总结

  1. 堆排序使用堆来选数,效率高
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

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

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

相关文章

Vue3+vite+ts 项目使用mockjs

1、安装mockjs npm i mockjs 2、安装vite-plugin-mock npm i vite-plugin-mock -D 3、安装axios npm i axios 4.在src目录下创建mock文件夹,在文件夹内创建login.ts等文件&#xff0c;并在文件夹内放置以下内容&#xff08;注&#xff1a;URL要和真实请求地址保持一致&am…

走向绿色:能源新选择,未来更美好

当前&#xff0c;全球范围内可再生能源正经历着从辅助能源向核心能源的深刻转型&#xff0c;绿色能源日益渗透至居住、出行、日常应用等多个领域&#xff0c;深刻影响着我们的生活方式&#xff0c;使我们能够更加充分地体验清洁能源所带来的优质生活。 一、绿色能源与“住” …

搭建知识中台:让企业告别低效率

在当今这个信息爆炸、知识更新日新月异的时代&#xff0c;企业面临着前所未有的挑战与机遇。如何在浩瀚的信息海洋中高效筛选、整合并利用知识资源&#xff0c;成为决定企业竞争力的关键因素之一。因此&#xff0c;搭建知识中台&#xff0c;构建企业知识管理的核心枢纽&#xf…

day 28 HTTP协议

一、TCP粘包问题 TCP发送数据是连续的&#xff0c;两次发送的数据可能粘连成一包被接收到 解决粘包问题方法&#xff1a; 1.接收指定长度&#xff1a;&#xff08;不稳定&#xff09; 2.睡眠&#xff1a;&#xff08;效率低&#xff09; 让每次…

19010 最小的特殊数字

### 详细分析 1. 读取输入的N和K&#xff0c;以及N个数字。 2. 使用回溯算法生成所有可能的数字组合。 3. 对于每个组合&#xff0c;检查是否满足没有前置0且能被K整除。 4. 记录满足条件的最小数。 5. 输出满足条件的最小数&#xff0c;如果没有满足条件的数输出-1。 ### 代码…

java流程控制之分支结构(附有案例说明)

顺序结构&#xff1a;从上到下依次执行 前向引用 分支结构&#xff1a;根据条件选择的执行某段代码 1.if -else 结构 分支结构 if-else 1、格式1 if&#xff08;条件表达式&#xff09;{ 语句块 } 2、格式2 if&#xff08;条件表达式&#xff09;{ 语句块&#xff1b…

鸡爪全自动包冰衣设备:

一、快速冷冻&#xff0c;效率高 速冻挂冰机是一种能够快速降温并迅速冷冻食品的冷藏设备。其采用强制循环风冷技术&#xff0c;可以将食品迅速降温到所需温度&#xff0c;使食品更加新鲜。相比于传统的冷冻方式&#xff0c;速冻挂冰机的速度更快&#xff0c;效率更高&#xf…

2021年上半年网络工程师考试上午真题

2021年上半年网络工程师考试上午真题 网络工程师历年真题含答案与解析 第 1 题 以下关于RISC和CISC计算机的叙述中&#xff0c;正确的是&#xff08; &#xff09;。 (A) RISC不采用流水线技术&#xff0c;CISC采用流水线技术(B) RISC使用复杂的指令&#xff0c;CISC使用简…

超级外链工具,可发9600条优质外链

超级外链工具&#xff0c;是一款在线全自动化发外链的推广工具。使用本工具可免费为网站在线批量增加外链&#xff0c;大大提高外链发布工作效率&#xff0c;是广大草根站长们必备的站长工具。 外链工具只是网站推广的辅助工具&#xff0c;一般适用于短时间内无法建设大量外链…

欧拉远程桌面 安装tigervnc

注意&#xff1a;安装远程tigevnc前提必须已经安装桌面环境&#xff0c;以下为ukui桌面环境&#xff0c;dde稍有区别&#xff1b; 1、关闭selinux 注意&#xff1a;selinux为安全措施也可以加入对应规则 setenforce 0 sed -i s/^SELINUXenforcing.*/SELINUXdisabled/ /etc/sel…

坚鹏讲人才第12期:引领数字化未来—数字化人才与导师共赢之路

坚鹏讲人才第12期&#xff1a;引领数字化未来—数字化人才与导师共赢之路 ——抢占名额先机 成为坚鹏弟子 加速数字化转型 数字化浪潮汹涌而至&#xff0c;你是否感到迷茫、困惑、焦虑&#xff1f;想不想一脚油门冲进未来&#xff0c;和我一同探寻数字化人才的奥秘&#xf…

基于STM32开发的智能温室控制系统

基于STM32开发的智能温室控制系统 目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化传感器数据采集控制与状态指示Wi-Fi通信与远程监控应用场景 农业温室智能控制室内植物养护管理常见问题及解决方案 常见问题解决方案结论 1. 引…

WebRTC音视频开发读书笔记(一)

一、基本概念 WebRTC(Web Real-Time Communication&#xff0c;网页即时通信)于2011年6月1日开源&#xff0c;并被纳入万维网联盟的W3C推荐标准&#xff0c;它通过简单API为浏览器和移动应用提供实时通信RTC功能。 1、特点 跨平台&#xff1a;可以在Web&#xff0c;Android、…

C# VisionPro 海康相机SDK源代码

运行界面如下所时&#xff1a; 实时图像效果如下&#xff1a; Winform窗体代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Fo…

LabVIEW光纤管道泄漏检测系统

光纤管道泄漏定位系统利用干涉型光纤传感器和数据采集卡进行信号获取与处理&#xff0c;实现了高灵敏度的泄漏点定位。通过软件对泄漏信号进行实时降噪处理和数据库管理&#xff0c;提高了系统的自动化和智能化水平。 项目背景&#xff1a; 长输管道在石油、天然气等行业中发挥…

XSS和DOM破坏案例

XSS案例 环境地址&#xff1a;XSS Game - Learning XSS Made Simple! | Created by PwnFunction 1.Ma Spaghet! 源码&#xff1a; <!-- Challenge --> <h2 id"spaghet"></h2> <script>spaghet.innerHTML (new URL(location).searchParam…

Python爬虫——某网站的视频数据

一、选题背景 1.背景 随着大数据时代的来临&#xff0c;网络爬虫在互联网中的地位将越来越重要。互联网中的数据是海量的&#xff0c;如何自动高效地获取互联网中我们感兴趣的信息并为我们所用是一个重要的问题&#xff0c;而爬虫技术就是为了解决这些问题而生的。对于身为数据…

【业务场景实战】你知道布隆过滤器怎么用吗?

布隆过滤器想必大家都听过&#xff0c;背过Redis面试题的兄弟应该都知道&#xff0c;布隆过滤器是解决缓存穿透问题的一种方法。但可能很少用过 布隆过滤器主要是为了解决海量数据的存在性问题。对于海量数据中判定某个数据是否存在且容忍轻微误差这一场景&#xff08;比如缓存…

03 网络编程 TCP传输控制协议

目录 1、TCP基本特征 2、TCP通信流程基本原理 &#xff08;1&#xff09;基本原理 &#xff08;2&#xff09;TCP通信代码实现 &#xff08;3&#xff09;核心API解析 1&#xff09;地址绑定--bind 2)设置监听-listen 3)等待连接请求-accept-产生一个已连接套接字 4&a…

Transformer2

1.编解码 外国人来到中国&#xff0c;是如何知晓“梨”的中文&#xff1f; 相同的词&#xff0c;上下文应该都是相关的&#xff0c;又因为是计算机&#xff0c;所以需要将语义关系码进行数字化&#xff0c;这些数字需要体现出语义关系。 1.编解码的两个标准 编解码的两个标准包…