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


目录

 一. 前言

二. 排序的概念及运用

        2.1 排序的概念

        2.2 排序的运用

        2.3 常见的排序算法

三. 冒泡and选择排序

        3.1 冒泡排序

        3.2 选择排序

四. 各大排序算法的复杂度和稳定性

 一. 前言

       从本期开始,我们的数据结构将迎来一个新的篇章:排序篇,啪叽啪叽

       排序是数据结构中非常重要的内容,在后续的内容中,我们会对各种各样的排序算法进行剖析和实现,敬请期待哦 

本期要点

  • 对排序进行一个整体的认识
  • 介绍一下两种最简单的排序
  • 笼统地介绍一下各大排序算法的复杂度和稳定性

二. 排序的概念及运用

        2.1 排序的概念

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

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

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

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

        2.2 排序的运用

        在日常生活中,我们可以找到许多和排序有关的场景。例如我们进入电脑磁盘右键就可以看到一个排序方式的选项,这是对我们电脑的磁盘文件进行排序,你可以根据需求选择不同排序方式进行排序

         又或者,随便打开一个网购网站/软件,例如京东,我们可以看到左上角就可以对商品的某一维度进行排序

         再或者,世界500强榜单也是经过排序后产生的

总之,无论是在计算机的学习上还是现实生活中,排序都是非常重要的主题,其运用十分广泛,它无处不在

        2.3 常见的排序算法

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

三. 冒泡and选择排序

本期我们先介绍一下我们的两个老朋友:冒泡排序选择排序

        3.1 冒泡排序

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

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

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

  •  循环控制:很明显,我们需要两层循环来控制冒泡排序的过程。内层循环控制当前趟的数据交换,外层循环控制冒泡排序的趟数
  • 外层循环结束条件:由于每一趟结束后都有一个数冒到序列后端,因此对于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* p1, int* p2)
    {
    	int tmp = *p1;
    	*p1 = *p2;
    	*p2 = 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趟的冒泡,即有三趟是无效的。

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


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

void swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void BubblingSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
	{
        int flag=0; //标识每一趟是否发生交换 0:没有  1:有
		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)
  • 稳定性分析:由于我们是将较大的或较小的进行交换,当两个数相等时并不会进行交换,因而不会改变相同元素的先后次序,所以冒泡排序是稳定的排序。

        3.2 选择排序

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

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

  •  循环控制:类似的,我们需要两层循环来控制选择排序的过程。内层循环遍历序列找出最大/最小值,外层循环控制选择的次数
  • 外层循环结束条件:每一次遍历完都可以选出一个数换到起始位置,一共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* p1, int* p2)
    {
    	int tmp = *p1;
    	*p1 = *p2;
    	*p2 = 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的后方,与最开始的顺序不一致。由此我们可以得出,选择排序是不稳定的排序。

四. 各大排序算法的复杂度和稳定性

废话不多说,直接上表:

排序算法时间复杂度(最好)时间复杂度(平均)时间复杂度(最坏)空间复杂度稳定性

数据敏感度

比较类排序
冒泡排序O(N)O(N^{2})O(N^{2})O(1)稳定
选择排序O(N^{2})O(N^{2})O(N^{2})O(1)不稳定
直接插入排序O(N)O(N^{2})O(N^{2})O(1)稳定
希尔排序O(N^{1.3})

O(NlogN)

\sim O(N^{2})

O(N^{2})O(1)不稳定
堆排序O(NlogN)O(NlogN)O(NlogN)O(1)不稳定
快速排序O(NlogN)O(NlogN)O(N^{2})O(1)不稳定
归并排序O(NlogN)O(NlogN)O(NlogN)O(N)稳定
非比较类排序
基数排序O(N\times K)O(N\times K)O(N\times K)O(N+K)稳定
桶排序O(N)O(N+K)O(N^{2})O(N+K)稳定
计数排序O(N+K)O(N+K)O(N+K)O(K)稳定


以上,就是本期的全部内容啦🌸

制作不易,能否点个赞再走呢🙏

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于RASC的keil电子时钟制作(瑞萨RA)(1)----安装RASC

基于RASC的keil电子时钟制作_瑞萨RA_1安装RASC 概述硬件准备视频教程RA Smart Configurator软件下载RASC安装Keil下Renesas RA pack包安装 概述 RA Smart Configurator"是一种基于"灵活组合软件"概念的代码生成辅助工具。它可以自动生成微控制器的初始配置程序…

看见未来:定位咨询如何预测行业趋势

商业竞争时代&#xff0c;变化无处不在。科技日新月异&#xff0c;消费者需求日益多元&#xff0c;市场环境更加动态不定。在这个快速发展的时代&#xff0c;如果企业想要继续领先&#xff0c;就必须有能力预见未来&#xff0c;适应并驾驭这些变化&#xff0c;这就是定位咨询的…

【ElasticSearch】ES集群搭建、监控、故障转移

文章目录 1、ES集群介绍2、搭建ES集群3、集群状态监控4、集群职责及脑裂5、分布式新增和查询流程6、ES故障转移 1、ES集群介绍 单机的ES做数据存储与搜索&#xff0c;必然面临两个问题&#xff1a; 海量数据存储问题单点故障问题 因此&#xff0c;考虑使用ES集群&#xff1a…

LCD-STM32液晶显示中英文-(5.字符编码)

目录 字符编码 字符编码说明参考网站 字符编码 ASCII编码 ASCII编码介绍 ASCII编码表 中文编码 1. GB2312标准 区位码 2. GBK编码 3. GB18030 各个标准的对比说明 4. Big5编码 字符编码 字符编码说明参考网站 字符编码及转换测试&#xff1a;导航菜单 - 千千秀字 …

学习AJAX

AJAX &#x1f680; HTTP请求报文响应报文 &#x1f684; express框架&#x1f6ac; express基本使用 &#x1f692; 原生AJAX&#x1f6ac; GET.HTML&#x1f6ac; POST.HTML&#x1f6ac; JSON.HTML&#x1f6ac; nodemon工具可以帮助重启服务&#x1f6ac; IE缓存问题&#…

Devops系列五(CI篇之pipeline libraray)jenkins将gitlab helm yaml和argocd 串联,自动部署到K8S

一、说在前面的话 本文是CI篇的上文&#xff0c;因为上一篇已经作了总体设计&#xff0c;就不再赘述&#xff0c;有需要的请看前文。 我们将演示&#xff0c;使用CI工具–jenkins&#xff0c;怎么和CD工具–argocd串联&#xff0c;重点是在Jenkins该怎么做。准备工作和argocd等…

Java springBoot项目报LDAP health check failed

报错内容如下&#xff1a; 在bootstrap.yml文件里加 management:health:ldap:enabled: false 配置。 或者在application.properties文件里加&#xff1a; management.health.ldap.enabledfalse 参考答案&#xff1a;LDAP health check failed 难道没有人遇到这样的问题吗&…

TCP/IP基础知识笔记

应用层&#xff1a;为用户提供应用功能&#xff0c;比如 HTTP、FTP、Telnet、DNS、SMTP等。 应用层是工作在操作系统中的用户态&#xff0c;传输层及以下则工作在内核态。 传输层&#xff1a;为应用层提供网络支持。 *TCP包含众多特性比如流量控制、超时重传、拥塞控制等因此可…

【CPU】关于x86、x86_64/x64、amd64和arm64/aarch64

为什么叫x86和x86_64和AMD64? 为什么大家叫x86为32位系统&#xff1f; 为什么软件版本会注明 for amd64版本&#xff0c;不是intel64呢&#xff1f; x86是指intel的开发的一种32位指令集&#xff0c;从386开始时代开始的&#xff0c;一直沿用至今&#xff0c;是一种cisc指令…

LinkNet分割模型搭建

原论文&#xff1a;LinkNet: Exploiting Encoder Representations for Efficient Semantic Segmentation 直接步入正题~~~ 一、LinkNet 1.decoder模块 class DecoderBlock(nn.Module):def __init__(self, in_channels, n_filters): #512, 256super(DecoderBlock, self).__in…

linux kernel单独编译某项驱动

linux内核经常涉及编译某一项驱动代码的场景&#xff0c;本次以网卡驱动e1000为例说明整个步骤流程。 首先编译内核驱动不必要编译整个内核&#xff0c;但编译的驱动代码必须要和要安装的内核版本保持一致&#xff0c;否则经常会出现无法加载模块。 在编译驱动前&#xff0c;最…

大坝安全监测中需要做好检查监测

大坝安全监测是人们了解大坝运行状态和安全状况的有效手段和方法。它的目的主要是了解大坝安全状况及其发展态势&#xff0c;是一个包括由获取各种环境、水文、结构、安全信息到经过识别、计算、判断等步骤&#xff0c;最终给出一个大坝安全 程度的全过程。 此过程包括&#xf…

layui增删改查的实现

前言 在前三篇layui博客的基础上继续完善&#xff0c;这篇博客增加了数据表格来实现增删改查 这里要注意layui需要使用2.6以上的版本 dao方法的编写 package com.zking.dao;import java.util.List; import java.util.Map;import com.zking.entity.User; import com.zking.uti…

进销不匹配将被严查,增值税高怎么办?

进销不匹配将被严查&#xff0c;增值税高怎么办&#xff1f; 《税筹顾问》专注于园区招商、企业税务筹划&#xff0c;合理合规助力企业节税&#xff01; 金税四期是通过对企业所得税、增值税、个人所得税等各类税种的统一管理&#xff0c;实现对企业财务活动的全面监管和规范&…

探索uni-app:构建跨平台应用的神奇工具

文章目录 &#x1f4da;1. 视图容器类组件⚡ <view>&#xff1a;视图容器&#xff0c;类似于div元素⚡<scroll-view>&#xff1a;可滚动的视图容器 &#x1f4da;2. 基础内容类组件⚡<text>&#xff1a;文本内容&#xff0c;类似于span元素⚡<icon>&am…

单例模式之常见模式详解

单例模式之常见模式详解 单例模式的定义单例模式的分类饿汉模式懒汉模式 单例模式的主要特点单例模式的应用场景总结 单例模式的定义 单例模式是一种设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。 在单例模式中&#xff0c;类…

MATLAB算法-数据挖掘算法详解,

Matlab是一种功能强大的数据分析和数据挖掘工具,提供了丰富的数据挖掘算法和函数。下面将介绍一些最著名的数据挖掘算法,并提供相应的代码示例。 K均值聚类算法(K-means Clustering): K均值聚类是一种常用的无监督学习算法,用于将数据集划分为K个不同的簇。以下是在Matla…

一些抄袭CSDN的爬虫网站(长期收集更新)

目录 一、CodeAntenna1. 简介2. 网址 二、待更新。。。 本文由CSDN点云侠原创&#xff0c;爬虫网站请努力加油爬。 一、CodeAntenna 1. 简介 互联网耻辱柱排行榜Top 1。本人博客里任何一点免费可读的部分都被该网站爬得体无完肤。 2. 网址 https://codeantenna.com/a/B4cMB…

【项目 进程3】2.6 exce函数族 2.7 进程退出、孤儿进程、僵尸进程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 2.6 exec函数族介绍&#xff08;execute 执行&#xff09;exec函数族 2.7 进程退出、孤儿进程、僵尸进程进程退出孤儿进程僵尸进程 2.6 exec函数族介绍&#xff08;…

前端做excel的录入解析,将excel的数据传给后端,显示在页面上。

具体的流程如图所示&#xff1a; 1.点击excel录入按钮 2.打开弹框 3.点击上传按钮&#xff0c;会自动打开计算机本地文件&#xff0c;选择想上传的文件&#xff0c;点击打开 4.会将excel的数据解析成一个表格&#xff0c;可以在表格中做删除操作&#xff0c;点击确定 5.将exc…