【数据结构】排序算法(一)—>插入排序、希尔排序、选择排序、堆排序

news2024/11/25 7:31:21

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

1.直接插入排序

2.希尔排序

3.直接选择排序

4.堆排序


前言

本篇文章博主将介绍排序算法中的插入排序:直接插入排序、希尔排序和选择排序:选择排序、堆排序,并进行代码实现,感兴趣的同学给博主点点关注哦🌝


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.直接插入排序

直接插入排序的思想就是从左到右进行遍历,在遍历过程中将当前的元素插入到前面(已经有序)合适的位置,直到遍历完成。

直接插入排序的特性:

  • 元素集合越接近有序,直接插入排序算法时间效率越高;
  • 时间复杂度:O(N^2);
  • 空间复杂度:O(1);
  • 稳定性:稳定。

排序的稳定性:指的是保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。

代码实现:

// 插入排序
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//因为此时前面已经是有序序列,如果tmp>当前值,证明比前面都大,所以break跳出即可
			{
				break;
			}
			end--;
		}
		a[end+1]= tmp;
	}
}

2.希尔排序

希尔排序与直接插入排序同属插入排序方法,也就是说希尔排序也是靠向前插入的思路进行的。

不同的是,希尔排序先进行预排序,将待排序序列调整的接近有序后,再进行一次直接插入排序。

希尔排序利用了插入排序的特性:待排序序列越接近有序,插入排序时间效率越高。

那么如何进行预排序呢?

希尔排序将待排序序列分组,假设定义一个变量 gap ,那么间隔gap的数据我们分为一组,如图:

预排序阶段:我们以分组情况为基础,每组内部进行直接插入排序,每完成一轮,gap=gap/3-1。

注意:预排序阶段的边界设计很多可以参照直接插入排序,就是将1改为了gap而已,不理解时可以代入直接插入排序进行理解。 

直接插入排序阶段:直到gap的值为1的时候,我们发现此时就是直接插入排序了,经过这轮排序就能得到最终的有序序列。


图片取自wikipedia-Shell_sort


希尔排序的特性总结:

  • 希尔排序是对直接插入排序的优化。
  • 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  • 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定。大致为O(N^1.25)到O(1.6*N^1.25)。
  • 稳定性:不稳定

代码实现:

// 希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//gap递减普遍取这种,也有取gap=gap/2的
		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;
		}
	}
}

3.直接选择排序

选择排序的思想是每遍历一遍选出最小的值,放到最开始的位置。

我们对该思想优化,每次遍历选出最大值和最小值,分别放到两边。

直接选择排序的特性:

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

代码实现:

// 选择排序
void SelectSort(int* a, int n)
{
	int left = 0;
	int right = n - 1;
	while (right > left)
	{
		int maxi = left;
		int mini = left;
		for (int i = left+1; i <=right ; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		swap(&a[left], &a[mini]);
		if (maxi == left)//假设max被换走了,恢复一下
		{
			maxi = mini;
		}
		swap(&a[right], &a[maxi]);
		right--;
		left++;
	}
}

4.堆排序

堆排序首先要介绍的是向下调整算法。

向下调整算法的前提是左右子树是堆。

以小堆为例:

1.给定向下调整的起点(双亲节点下标)和节点总数,根据起点下标计算孩子节点下标。

注意:向下调整时,若有两个孩子节点,则需要确保调整的是较大的孩子节点。

2.比较孩子节点与双亲节点数值大小,若孩子节点小于双亲节点,则交换两者,并将双亲节点的下标更新为之前的孩子节点下标,根据最新的双亲节点下标重新计算孩子节点下标,重复这一过程直到孩子节点超出节点总数。


对于堆排序来说:

以升序为例:

首先构建大堆(推荐使用向下调整),此时堆顶元素一定为最大值,然后将堆顶元素与最后一个节点交换,此时最大值就放到了整个数组的最后面,然后除了最后一个值以外,其他的数据再向下调整,调整完成后堆顶元素为次大值,再与数组倒数第二个位置的值交换,这样依此往复就得到了升序数组。

注意:升序建大堆,降序建小堆。


🌐更多关于堆的内容可以参考博客:堆排序与TopK问题---樊梓慕🌐


堆排序的特性总结: 

  • 堆排序擅于处理庞大数据。
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

代码实现:

// 堆排序
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;
		}

		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			// 继续往下调整
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* a, int n)
{
	// 向下调整建堆
	// O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

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

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

相关文章

力扣:112. 路径总和(Python3)

题目&#xff1a; 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

用css画一个半圆弧(以小程序为例)

一、html结构 圆弧的html结构是 两个块级元素嵌套。 <View classNamewrap><View className"inner">{/* 图标下的内容 */}</View></View>二、css样式&#xff1a;原理是两个半圆叠在一起&#xff0c;就是一个半圆弧。那么&#xff0c;如何画一…

【小白专属03】SpringBoot实现增删改查

目录 前言 一、新建Controller层 二、使用PostMan测试接口 前言 上节回顾 上一节我们SpringBoot集成了MybatisPlus。MybatisPlus是一个Mybatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 本节介绍 这一节&#x…

基于微信小程序的明星应援小程序设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

DirectX12_Windows_GameDevelop_0:启程之旅

前言 今天是2023年9月28日&#xff0c;明天就是中秋节了&#xff0c;先祝福大家中秋快乐&#xff01;时光飞逝&#xff0c;岁月如梭&#xff0c;大学四年一晃而逝&#xff0c;眨眼间我们即将毕业。毕业不是意味着要面对社会的险恶&#xff0c;也不是意味着要当打工社畜&#x…

cesium在vue中引入报错解决;cesium在vue中初始化地球

第一步&#xff1a; npm install cesium 第二步&#xff1a; 找到node_modules/cesium/Build/Cesium 文件夹&#xff0c;把这个 Cesium 文件夹复制一份到项目的 public 文件夹下 第三步&#xff1a; 在public文件夹下的index.html 文件中&#xff0c;head 标签里面&#…

51单片机实训项目之产品数量计数器

/********************************************************************************* * 【实验平台】&#xff1a; QX-MCS51 单片机开发板 * 【外部晶振】&#xff1a; 11.0592mhz * 【主控芯片】&#xff1a; STC89C52 * 【编译环境】&#xff1a; Keil μVisio3 * 【程序…

BiMPM实战文本匹配【上】

引言 今天来实现BiMPM模型进行文本匹配&#xff0c;数据集采用的是中文文本匹配数据集。内容较长&#xff0c;分为上下两部分。 数据准备 数据准备这里和之前的模型有些区别&#xff0c;主要是因为它同时有字符词表和单词词表。 from collections import defaultdict from …

3 OpenCV两张图片实现稀疏点云的生成

前文&#xff1a; 1 基于SIFT图像特征识别的匹配方法比较与实现 2 OpenCV实现的F矩阵RANSAC原理与实践 1 E矩阵 1.1 由F到E E K T ∗ F ∗ K E K^T * F * K EKT∗F∗K E 矩阵可以直接通过之前算好的 F 矩阵与相机内参 K 矩阵获得 Mat E K.t() * F * K;相机内参获得的方式…

spring6-IOC容器

IOC容器 1、IoC容器1.1、控制反转&#xff08;IoC&#xff09;1.2、依赖注入1.3、IoC容器在Spring的实现 2、基于XML管理Bean2.1、搭建子模块spring6-ioc-xml2.2、实验一&#xff1a;获取bean①方式一&#xff1a;根据id获取②方式二&#xff1a;根据类型获取③方式三&#xff…

Zilliz@阿里云:大模型时代下Milvus Cloud向量数据库处理非结构化数据的最佳实践

大模型时代下的数据存储与分析该如何处理?有没有已经落地的应用实践? 为探讨这些问题,近日,阿里云联合 Zilliz 和 Doris 举办了一场以《大模型时代下的数据存储与分析》为主题的技术沙龙,其中,阿里云对象存储 OSS 上拥有海量的非结构化数据,Milvus(Zilliz)作为全球最有…

华为摄像头智能安防监控解决方案

云时代来袭&#xff0c;数字化正在从园区办公延伸到生产和运营的方方面面&#xff0c;智慧校园&#xff0c;柔性制造&#xff0c;掌上金融和电子政务等&#xff0c;面对各种各样的新兴业态的涌现&#xff0c;企业需要构建一张无所不联、随心体验、业务永续的全无线网络&#xf…

多线程锁-线程锁知识概述、乐观锁和悲观锁

3. 说说Java"锁"事 3.1 从轻松的乐观锁和悲观锁开讲 悲观锁&#xff1a; 认为自己在使用数据的时候一定有别的线程来修改数据&#xff0c;因此在获取数据的时候会先加 锁&#xff0c;确保数据不会被别的线程修改&#xff0c;synchronized和Lock的实现类都是悲观锁…

【通意千问】大模型GitHub开源工程学习笔记(2)

使用Transformers来使用模型 如希望使用Qwen-chat进行推理,所需要写的只是如下所示的数行代码。请确保你使用的是最新代码,并指定正确的模型名称和路径,如Qwen/Qwen-7B-Chat和Qwen/Qwen-14B-Chat 这里给出了一段代码 from transformers import AutoModelForCausalLM, Aut…

正点原子lwIP学习笔记——WebServer实验

1. WebServer简介 Web Server就是提供Web服务的Server&#xff0c;主要功能是&#xff1a;存储、处理和传递网页给客户端&#xff0c;他只需支持HTTP协议、HTML文档格式以及URL&#xff0c;与客户端的网络浏览器配套。 其中&#xff0c;HTTP的协议就是基于TCP进一步实现的&…

零代码编程:用ChatGPT批量修改文件夹名称中的大小写

一个文件夹下面有很多个子文件夹&#xff0c;要把文件夹中的大写数字全部重命名为小写数字&#xff0c;比如将二 三 四&#xff0c;改成&#xff1a; 2 34 在ChatGPT中输入提示词如下&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个文件夹重命名的任务。具体步骤如…

芯片测试方案之如何测试芯片EN输入阈值?

在电源管理芯片的设计中&#xff0c;除了常规的VIN、VOUT以及GND端口之外&#xff0c;还会有SW、EN、FB等芯片独有的特殊端口引脚&#xff0c;这些引脚或负责电源开关的输入&#xff0c;或负责电路的反馈电压/电流&#xff0c;这些引脚在芯片的工作中有着极其重要的作用&#x…

CUDA学习笔记0929

一、GPU缓存和变量作用域 1. 缓存类型 &#xff08;1&#xff09;GPU缓存是非可编程存储区域 &#xff08;2&#xff09;GPU包含4类缓存&#xff1a; L1缓存&#xff0c;每个流处理器一个 L2缓存&#xff0c;全部流处理器共享一个 L1和L2都可用于存储本地和全局内存中的数…

了解vtk显示的原理

文章目录 目标:知识补充:1.什么是图元?2.最让我不解的是:官方讲的是:mapper讲polydata转换为可渲染的图元数据,然后actor是将polydata映射为可渲染的图元???既然mapper就已经将其解析为图元数据,为什么actor还要进一步解析呢?3.那polydata不是也获得了一些数据,这些数据是…

快速将iPhone大量照片快速传输到电脑的办法!

很多使用iPhone 的朋友要将照片传到电脑时&#xff0c;第一时间都只想到用iTunes 或iCloud&#xff0c;但这2个工具真的都非常难用&#xff0c;今天小编分享牛学长苹果数据管理工具的照片传输功能&#xff0c;他可以快速的将iPhone照片传输到电脑上&#xff0c;并且支持最新的i…