【数据结构】手撕排序NO.1

在这里插入图片描述
🔥博客主页 小羊失眠啦.
🎥系列专栏《C语言》 《数据结构》 《Linux》《Cpolar》
❤️感谢大家点赞👍收藏⭐评论✍️


在这里插入图片描述

文章目录

  • 一、排序的概念及其运用
    • 1.1 排序的概念
    • 1.2 常见的算法排序
  • 二、 冒泡排序
  • 三、直接插入排序
  • 四、希尔排序
  • 五、 选择排序

一、排序的概念及其运用

1.1 排序的概念

排序:所谓排序就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1.2 常见的算法排序

排序算法分为比较类排序非比较类排序,如下图所示:

在这里插入图片描述


二、 冒泡排序

  • 思想 : 在一个序列中,每次对序列中的相邻记录的键值大小进行比较,将较大(升序)或较小(降序)的记录向后移动。如此循环,大/小的记录会慢慢“”到序列的后端,整个过程就像是冒泡一样,顾称之为冒泡排序。
  • 冒泡过程:以下是对某个序列进行冒泡排序的过程

在这里插入图片描述

可以看出,对于上面具有5个元素的无序数组,我们通过4趟的冒泡后就将其变为有序数组,每一趟冒泡后都可以使最大的数沉底。

  • 动图演示:我们可以通过一下动图感受一下冒泡两两比较的过程:

img

  • 循环控制:很明显,我们需要两层循环来控制冒泡排序的过程。内层循环控制当前趟的数据交换,外层循环控制冒泡排序的趟数
  • 外层循环结束条件:由于每一趟结束后都有一个数冒到序列后端,因此对于N个数的序列来说,一共需要N-1趟(只剩一个数不需要冒泡)。
for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
{; 
}
  • 内层循环结束条件:内层循环用于数据的比较。已知N个数据共需比较N-1次,由于每一趟结束后就有数据到正确的位置,下一趟需要比较的数据个数就会少1,因此每趟的比较次数随着趟数的增加呈递减趋势,初始为N-1次
for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
{for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1{;}
}
  • 完整代码:
void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}void BubblingSort(int* a, int n)
{for (int i = 0; i < n - 1; i++) //外层循环,N-1趟{for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1{if (a[j] > a[j + 1]) //升序排列,较大的往后移{swap(&a[j], &a[j + 1]); //交换}}}
}
  • 改进优化:上面的代码还存在着改进空间,我们来看下面两个情景:

在这里插入图片描述

对于情境1,我们只需一趟冒泡即可让数组有序,而如果按照上面的代码,我们依旧要进行4趟的冒泡,即有三趟是无效的。

情境2就更夸张了,数组已经有序,我们却傻乎乎的做了4趟无效冒泡。无疑是非常浪费时间的。


考虑到这些情况,我们提出了优化方案在每趟结束后判断一下当前趟是否发生了元素交换,如果没有,则说明序列已经有序了,及时止损,反之继续。优化后的代码如下:

void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}void BubblingSort(int* a, int n)
{for (int i = 0; i < n - 1; i++) //外层循环,N-1趟{int flag = 0;for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1{if (a[j] > a[j + 1]) //升序排列,较大的往后移{swap(&a[j], &a[j + 1]); //交换flag = 1;}}if (flag == 0)break;}
}
  • 时间/空间复杂度:结合上面的图片和代码我们可以看出,总共N-1趟,每趟N-1,N-2…次比较,共比较 (N-1) + (N-2) + (N-3) + (N-4) + (N-5) + … + 1次,时间复杂度为O(N^2);而由于没有额外的辅助空间,空间复杂度为O(1)。
  • 稳定性分析:由于我们是将较大的或较小的进行交换,当两个数相等时并不会进行交换,因而不会改变相同元素的先后次序,所以冒泡排序是稳定的排序。

三、直接插入排序

  • 思想:把待排序的数据按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的数据插入完为止,得到一个新的有序序列 。 实际中我们玩扑克牌时,就用了插入排序的思想。

img

注意:数组中除了第一个元素(默认有序),其余所有元素都看作待插入数据。

  • 排序步骤
  1. 将有序数据的最后一个元素的下标记为 end,则第一个待插入元素的下标为 end+1,记作 tmp
  2. 将 tmp 与有序数据从后向前依次比较
  3. 如果 tmp < a[end],就将 a[end] 向后移动,end–,再去找下一位进行比较
  4. 直到 tmp > a[end] 或者 end < 0,将 tmp 插入到 end+1 的位置
  5. 重复步骤,就可以实现排序
  • 代码实现
void InsertSort(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (tmp < a[end]){a[end + 1] = a[end];}else{break;}--end;}a[end + 1] = tmp;}
}

在这里插入图片描述

  • 时间/空间复杂度:结合上面的图片和代码我们可以看出时间复杂度为O(N^2);由于没有额外的辅助空间,空间复杂度为O(1)。
  • 稳定性分析:是稳定的排序。

四、希尔排序

  • 思想

    先选定一个整数,把待排序文件中所有记录分成个组,所有距离为3的数据分在同一组内,并对每一组内的数据进行排序。然后,重复上述分组和排序的工作。当距离=1时,所有数据在统一组内排好序。

    希尔排序分为两步:

    1. 预排序
    2. 直接插入排序

    当元素集合越接近有序,直接插入排序的效率很高,希尔排序就是通过预排序使元素集合接近有序,再进行直接插入排序,这样大大提高了效率。

img

  • 排序步骤:
  1. 选取一个合适的 gap 作为间距
  2. 将间距为 gap 的数据分为一组,分成 gap 组
  3. 每一组数据都进行直接插入排序,使数据接近有序
  4. 不断缩小间距,当 gap==1 时,数据进行直接插入排序,实现排序
  • 代码实现
void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}
  • 特点:
    1. 希尔排序是对直接插入排序的优化。
    2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
    3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算。
    4. 空间复杂度:O(1)
    5. 稳定性:不稳定

五、 选择排序

  • 思想 : 每一次从待排序的数据元素中选出最小(升序)或最大(降序)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
  • **选择过程:**以下是对某个序列进行选择排序的过程:

在这里插入图片描述

  • 动图演示:我们一样通过动图感受一下选择排序的过程:

img

  • 循环控制:类似的,我们需要两层循环来控制选择排序的过程。内层循环遍历序列找出最大/最小值,外层循环控制选择的次数
  • 外层循环结束条件:每一次遍历完都可以选出一个数换到起始位置,一共N个数,故要选N-1次(最后一个数不需要选择)
for (int i = 0; i < n-1; i++) //外层循环,共要选择n-1次
{;
}
  • 内层循环结束条件:内层循环通过比较进行选数,一开始N个数需要比较N-1次,然后每趟结束后下一次选择的起始位置就往后移动一位,比较次数减1
for (int i = 0; i < n-1; i++) //外层循环,共选择n-1次
{for (int j = i + 1; j < n; j++) //内层循环,起始位置开始向后进行比较,选最小值{;}
}
  • 完整代码:
void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}void SelectSort(int* a, int n)
{for (int i = 0; i < n - 1; i++) //外层循环,共选择n-1次{int mini = i; //记录最小值的下标,初始为第一个数下标for (int j = i + 1; j < n; j++) //内层循环,起始位置开始向后进行比较,选最小值{if (a[mini] > a[j]) //比最小值小,交换下标{mini = j;}}swap(&a[mini], &a[i]); //将最小值与起始位置的数据互换}
}
  • 时间/空间复杂度:一共选了N-1次,每次选择需要比较N-1,N-2,N-3…次,加起来和冒泡一样时间复杂度为O(N);没有用到辅助空间,空间复杂度为O(1)
  • 稳定性分析:由于是选数交换,在交换的过程中很可能会打乱相同元素的顺序,例如下面这个例子:

在这里插入图片描述

我们发现,在第一趟交换中,黑5被交换到了红5后面,在整个排序结束后,黑5依然在红5的后方,与最开始的顺序不一致。由此我们可以得出,选择排序是不稳定的排序。

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,小羊一定认真修改,写出更好的文章~~

在这里插入图片描述

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

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

相关文章

【电源专题】什么是电源管理

电源管理为什么重要? 在电子系统和电路的设计中,负载往往需要恒定的电流电压,所以最先考虑的就是电源电路的设计。电源管理所考虑的问题是如何将电源有效分配给系统的不同组件,保障系统不同的负载正常运行。 如电源的输入是交流 (AC) 或直流 (DC)?输入电压是高于或低于输…

RedHat8 安装部署DzzOffice协同办公平台+onlyoffice(docker)以及问题解决(亲测可用,花费2天)

一、基础配置(MysqlDzzoffice) 1&#xff1a;安装软件需要的环境&#xff0c;我们用LAMP的环境。基本上CentOS8自带的软件版本都达到安装DzzOffice的要求。 2&#xff1a;关闭防火墙&#xff08;不关的话需要开放80端口自行决定&#xff09;。 systemctl disable --now fire…

HarmonyOS引入其他包,以引入请求axios为例

安装文件 安装文件位置: 总目录的oh-package.json5文件 dependencies&#xff1a;生产环境–上线运行时候必须需要的包 devDependencies&#xff1a;开发环境–开发适合为了方便提高效率的包。 包管理工具 OHPM CLI 作为鸿蒙生态三方库的包管理工具&#xff0c;支持OpenHar…

Facebook引流怎么做?写个脚本就好!

在当今的数字化时代&#xff0c;流量对于任何一个网站或应用程序来说都至关重要&#xff0c;Facebook&#xff0c;作为全球最大的社交网络平台&#xff0c;无疑是一个获取流量的绝佳场所&#xff0c;但是&#xff0c;如何有效地从Facebook引流呢?写个脚本就好了! 在本文中&am…

Python字符串模糊匹配工具:TheFuzz 库详解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在处理文本数据时&#xff0c;常常需要进行模糊字符串匹配来找到相似的字符串。Python的 TheFuzz 库提供了强大的方法用于解决这类问题。本文将深入介绍 TheFuzz 库&#xff0c;探讨其基本概念、常用方法和示例代…

什么是Overlay网络?Overlay网络与Underlay网络有什么区别?

你们好&#xff0c;我的网工朋友。 在传统历史阶段&#xff0c;数据中心的网络是以三层架构&#xff08;核心、汇聚、接入&#xff09;为基本标准。 但是随着技术的发展&#xff0c;不同的厂家有不同的组建方式&#xff0c;比如说在核心层、汇聚层和接入层增加虚拟化技术。 …

Maven项目目录结构

项目结构 目录说明.ideaIDEA工具的配置文件.mvn用于运行Maven项目src源码文件夹target字节码文件夹.gitignore配置git忽略文件HELP.md自述文件mvnw运行Maven命令&#xff08;Linux&#xff09;mvnw.cmd运行Maven命令&#xff08;Windows&#xff09;pom.xml依赖管理文件 如图…

从零开始入门Zapier:与ChatGPT双剑合璧,手把手教程让你进入AI与自动化新纪元

coments 1. 1. 打开Zapier的官方界面 登录之后&#xff0c;会出现一个调查表&#xff0c;可以根据自己的情况进行选择。 第一次注册成功&#xff0c;会送你14天的免费体验

经验分享|MySQL分区实战(RANGE)

概述 分区概述 在 MySQL 中&#xff0c; InnoDB存储引擎长期以来一直支持表空间的概念。在 MySQL 8.0 中&#xff0c;同一个分区表的所有分区必须使用相同的存储引擎。但是&#xff0c;也可以为同一 MySQL 服务器甚至同一数据库中的不同分区表使用不同的存储引擎。 通俗地讲…

网络初识:局域网广域网网络通信基础

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、局域网LAN是什么&#xff1f;二、广域网是什么&#xff1a;三. IP地址四.端口号五.认识协议5.1五元组 总结 前言 一、局域网LAN是什么&#xff1f; 局域网…

flask web开发学习之初识flask(三)

文章目录 一、flask扩展二、项目配置1. 直接配置2. 使用配置文件3. 使用环境变量4. 实例文件夹 三、flask命令四、模版和静态文件五、flask和mvc架构 一、flask扩展 flask扩展是指那些为Flask框架提供额外功能和特性的库。这些扩展通常遵循Flask的设计原则&#xff0c;易于集成…

CUDA简介——Grid和Block内Thread索引

1. 引言 前序博客&#xff1a; CUDA简介——基本概念CUDA简介——编程模式CUDA简介——For循环并行化 Thread Index&#xff1a; 每个Thread都有其thread index。 在Kernel中&#xff0c;可通过内置的threadIdx变量来获取其thread index。threadIdx为三维的&#xff0c;有相…

Leetcode每日一题学习训练——Python版(从二叉搜索树到更大和树)

版本说明 当前版本号[20231204]。 版本修改说明20231204初版 目录 文章目录 版本说明目录从二叉搜索树到更大和树理解题目代码思路参考代码 原题可以点击此 1038. 从二叉搜索树到更大和树 前去练习。 从二叉搜索树到更大和树 给定一个二叉搜索树 root (BST)&#xff0c;请…

【c++|SDL】二、读取图片、显示图片、动画制作

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 读取图片&#xff0c;显示图片&#xff0c;动画 SDL中有两种在屏幕上显示的方法 SDL_Surface: 使用软件渲染处理SDL_Texture: 使用硬件加速渲染处理 1.…

iOS代码安全加固利器:深入探讨字符串和代码混淆器的作用

​ 在网上搜“代码混淆”关键词&#xff0c;可以看到n多教程。包括本篇博客&#xff0c;大部分重要内容也是从网上各位大神的博客里面看到然后摘取和总结出来的。虽然网上都有&#xff0c;但是对于我个人来说&#xff0c;很难找到一篇博客概括完全的&#xff0c;所以还是总结一…

现在的00后,实在是太卷了......

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

Java中各种数据类型之间的转换

低类型向高类型自动进行转换&#xff0c;高类型向低类型的准换会丢失数据&#xff0c;整数到字符类型的转换将获取对应编码的字符。 进行高精度向低精度的强制类型准换时&#xff0c;需要将想要转换成的数据类型加一个括号()。 如何完成自动转换呢&#xff1f; 转换前的数据类…

KNN算法实战-健康医疗

健康医疗 算法建模 knn 算法建模构建微观数据和疾病之间的关系knn 调整超参数&#xff0c;准确率提升数据归一化、标准化&#xff0c;提升更加明显 算法实战 导入包 import numpy as np import pandas as pd from sklearn.neighbors import KNeighborsClassifier from sklea…

LeetCode 每日一题 Day 3||深度优先搜索(DFS)

1038. 从二叉搜索树到更大和树 给定一个二叉搜索树 root (BST)&#xff0c;请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 提醒一下&#xff0c; 二叉搜索树 满足下列约束条件&#xff1a; 节点的左子树仅包含键 小于 节点键的节点。节点的右子树仅…