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

news2024/10/6 12:22:25


目录

 一. 前言

二. 排序的概念及运用

        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)稳定


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

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

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

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

相关文章

【7天学GO】第1章 开发环境

1.1 开篇介绍(必看) A. Why choose the go language B. 学语言阶段 1.2 环境搭建前戏 A. 学习一门语言步骤 B. 编译型与解释型 1.3 mac系统Go开发环境搭建 (略) 1.4 linux系统Go开发环境搭建 (略) 1.5 windows系统Go开发环境搭建 A. 开发环境搭建 Stage 1&#xff1a…

Appium+python自动化(十一)- 元素定位- 下卷超详解)

1、 List定位 List故名思义就是一个列表&#xff0c;在python里面也有list这一个说法&#xff0c;如果你不是很理解什么是list&#xff0c;这里暂且理解为一个数组或者说一个集合。首先一个list是一个集合&#xff0c;那么他的个数也就成了不确定性&#xff0c;所以这里需要用复…

和为 K 的子数组——前缀和+哈希

题目链接&#xff1a;力扣 注意&#xff1a;此题不能使用滑动窗口&#xff0c;因为数组中可能会出现负数。也就是说右指针向后移1位不能保证区间会增大&#xff0c;左指针向后移1位也不能保证区间和会减小。给定左右指针的位置没有二段性 已知sum[i]是从nums[0~i]的和&#x…

STM32之按键驱动的使用和自定义(MultiButton)

原始Github地址 Github地址 修改后 调整内容 将宏定义转换成配置结构体 头文件 #ifndef _MULTI_BUTTON_H_ #define _MULTI_BUTTON_H_#include "stdint.h" #include "string.h"//According to your need to modify the constants. //#define TICKS_IN…

数据结构--图的存储邻接表法

数据结构–图的存储邻接表法 邻接矩阵&#xff1a; 数组实现的顺序存储&#xff0c;空间复杂度高&#xff0c;不适合存储稀疏图 邻接表&#xff1a; 顺序链式存储 邻接表法&#xff08;顺序链式存储&#xff09; //边/弧 typedef struct ArcNode {int adjvex; //边/弧指向哪个…

MVX-Net Multimodal VoxelNet for 3D Object Detection 论文学习

论文链接&#xff1a;MVX-Net Multimodal VoxelNet for 3D Object Detection 1. 解决了什么问题&#xff1f; 2D 目标检测取得了显著成效&#xff0c;但由于输入模态的本质区别&#xff0c;CNN 无法直接应用在 3D 检测任务。LiDAR 能准确地定位到 3D 空间的物体&#xff0c;基…

根据对象数组的key进行分组

简单版&#xff1a; const arr [{key: aaa,tableName: bbbbb},{key: aaa,tableName: bbbbb},{key: www,tableName: bbbbb},{key: www,tableName: bbbbb},{key: mysql_ytr,tableName: bbbbb} ]// 把arr按key進行分組&#xff0c; 輸出結果是對象&#xff0c;對象裡面用key做鍵…

logback自定义调用以及文件输出

1、logback 首先五大日志等级是不可更改的&#xff0c;我们所定义的日志输出和调用也是用的这五大等级&#xff0c;这个就不多说了&#xff0c;没啥用。 2、效果 调用 String msg "测试日志"; MyLoger.myloger(msg); 输出 2023-07-18 10:55:05 [main] INFO m…

[element-ui] el-select,虚拟滚动(vue-virtual-scroll-list)

一、问题描述 表单中某下拉框&#xff0c;由于数据过多&#xff0c;选择的时候会因为数据量过大导致页面卡顿&#xff0c;于是对于el-select进行二次封装&#xff0c;实现虚拟滚动。 二、实现如下&#xff1a; 看起来是加载了全部数据&#xff0c;实际上只加载了自己设定的1…

单例模式类设计|什么是饿汉模式和懒汉模式

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量干货博客汇总https://blog.csdn.net/yu_cblog/c…

汇编实现1-100累加(ARMv7)

汇编实现1-100累加 代码.text .globl _start _start:mov r0,#0 summationmov r1,#0 autoIncrementbl funadd funadd:cmp r1,#100addccs r0,r1,r0addccs r1,r1,#1mov pc,lr stop:b stop .end运行效果

请问如何用oracle触发器实现不允许新增/删除表/增加/减少/修改字段类型

请问如何用oracle触发器实现不允许新增/删除表/增加/减少/修改字段类型 给本帖投票 56211打赏收藏 分享 转发到动态举报 写回复 性能测试中发现oracle11g数据库每天22点,oralce进程CPU占用率突增>> 11 条回复 切换为时间正序 请发表友善的回复… 发表回复 microsof…

UWB天线设计之一种优化扁平超宽带单极的新方法

文章亮点 一种新颖的方法提出了扁平超宽带单极天线。 通过应用收缩,可以设计具有相同性能的更小的天线作为平面单极天线。 优化结果表明该方法能够设计非常小的天线。 在这项研究中,提出了一种优化扁平超宽带单极天线的新方法。在该方法中,一般性地描述了天线的形状。这种一…

Http 接口测试框架

目录 前言&#xff1a; 实际效果 框架的下一步 最新框架图&#xff08;红色部分未完成&#xff09; 部分代码 你需要做的 前言&#xff1a; 在进行HTTP接口测试时&#xff0c;使用一个可靠的测试框架可以提高测试效率和质量。HTTP接口测试框架是一种用于自动化测试HTTP接…

STM32数字小键盘

基于STM32的数字小键盘 自己的键盘小键盘数字键坏了几个&#xff0c;准备自己用STM32做一个数字键盘。 硬件 找了一些资料&#xff0c;感谢知乎老哥。 原理图 采用的是主控是STM32F103RBT6&#xff0c;上拉1.5K接高速USB。按键采用的是矩阵按键。轴位可以自己选择。还接了一…

OpenCv之图像轮廓

目录 一、图像轮廓定义 二、绘制轮廓 三、计算轮廓面积与周长 一、图像轮廓定义 图像轮廓是具有相同颜色或灰度的连续带你的曲线.轮廓在形状分析和物体的检测和识别中很有用 轮廓的作用: 用于图形分析物体的识别与检测 注意点: 为了检测的准确性&#xff0c;需要先对图像…

AI 救不了好莱坞,16 万演员联合编剧上演史诗级「罢工大戏」

内容一览&#xff1a; 近日&#xff0c;美国演员工会正式加入编剧工会行列&#xff0c;开始举行罢工&#xff0c;由此&#xff0c;被多家媒体称为好莱坞「末日」时刻来临。值得关注的是&#xff0c;本次罢工的原因&#xff0c;除了老生常谈的薪资问题&#xff0c;还有一个重要的…

多用户商城系统Dokan评测优点与缺点(2023)

目录 多用户商城系统Dokan优点 多用户商城系统Dokan缺点 您应该开始使用多供应商市场吗&#xff1f; 多用户商城系统Dokan评论 为什么选择Dokan&#xff1f; 用户界面 用户友好的前端 仪表板和后端 管理员后台 供应商仪表板 第三方兼容性 Dokan 可以卖什么&…

c#调用cpp库,debug时不进入cpp函数

选中c#的项目&#xff0c;右击属性&#xff0c;进入属性页&#xff0c;点击调试&#xff0c;点击打开调试启动配置文件UI&#xff0c;打开启用本机代码调试。

Scrapy和Selenium整合(一文搞定)

文章目录 前言一、开始准备1. 包管理和安装chrome驱动2. 爬虫项目的创建&#xff08;举个栗子&#xff09;3. setting.py的配置 二、代码演示1. 主爬虫程序2. 中间件的配置3. 定义item对象4. 定义管道 总结 前言 scrapy和selenium的整合使用 先定个小目标实现万物皆可爬&#…