排序|插入排序|希尔排序|直接选择排序|堆排序的实现即特性(C)

news2024/10/9 21:52:50

插入排序

![[Pasted image 20241009174707.png]]

基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

单趟

当插入第 i ( i ≤ 1 ) i(i\le 1) i(i1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

void InsertSort(int* a, int n)
{
	//[0, end]有序,把end+1位置的插入到前面序列
	//控制[0,end + 1]有序
	int end = ; 
	int tmp = a[end + 1];
	while (end >= 0)
	{
		if (tmp < a[end])
		{
			a[end + 1] = a[end];
		}
		else
		{
			break;
		}
	}
	
	a[end + 1] = tmp;
}
  • 每一次把end的后一个值往前插入,0到end已经有序了,把end的后一个数字插入
  • 先用中间变量tmp保存要插入的值,否则向后挪动的过程中会被覆盖掉
  • 如果tmp比end位置的值小,就将end的值往后挪动,也就是将end赋给end+1
  • 否则弹出
控制end变整体

![[Pasted image 20241009172951.png]]

5小于9,将end赋给end+1
![[Pasted image 20241009174002.png]]

end–
![[Pasted image 20241009174039.png]]

5小于6,end赋给end+1
![[Pasted image 20241009174117.png]]

5大于4,将tmp赋给end+1
![[Pasted image 20241009174223.png]]

void InsertSort(int* a, int n)
{
	for (size_t 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;
	}
}
  • 0到n-2有序,所以end落得最后一个位置i是n-2,把后一个位置n-1插入进去
  • i从0到n-1的开区间,也就是end从0开始遍历,直到最后一个数字的前一个,也就是end+1指向最后一个
  • 整个循环从将第二个数字往前出入,第三个数字往前插入,直到最后一个数字往前插入
  • 循环中,如果end+1下标的数字小于end位置的数字,将end位置的数字向后挪动,然后end–,end往前遍历,继续将tmp与之前的数字比较
  • 直到tmp不大于end,退出循环
特性总结
  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 稳定性:稳定
时间复杂度

最坏 O ( N 2 ) O(N^{2}) O(N2),逆序
最好 O ( N ) O(N) O(N),顺序有序

空间复杂度

没有开多余的空间
O ( 1 ) O(1) O(1)

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

  1. 预排序
    分组排,间距为gap分为一组,分为gap组,每组进行排序,用插入排序的思想完成
    gap越小,预排序完成之后越接近有序
  2. 直接插入排序
    如果gap是1,就是直接插入排序
多组排序
void ShellSort (int* a, int n)
{
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
		for (int i = j; i < n - gap; i += gap)
		{
			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;
		}
	}
}
  • tmp保存end的下一个
  • end从第一个开始往后挪,如果end>=0,就继续
  • i循环代表end走每组里面的gap间距的第i个数字,是每一组数据的插入排序,内层循环是组内进行插入排序,end每次后移gap个下标
  • j循环代表end走间距为gap的第j组,外层循环是遍历每个组,gap为几就分为几组
  • 一组排完,走另外一组

![[Pasted image 20241009175550.png]]

第一次排第一组9585,5589
第二次排第二组176,167
第三次排第三组243,234
![[Pasted image 20241009175812.png]]

此时整体更接近有序

多组并排
void ShellSort (int* a, int n)
{
	int gap = 3;
	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;
	}

}

![[Pasted image 20241009175550.png]]

end从0下标开始走到第一组的最后一个,如8
排完第一组的9和5,下来就排第二组的1和7,然后是第三组的2和4
跳着组排,直到遍历完所有的数据

多次预排序

预排序可以有多次
预排序的意义是让大的数更快得到后面去,小的数更快得到前面去,gap越大跳得越快,越不接近有序;gap越小,跳得越慢,越接近有序;gap=1,直接就有序
所以要进行多次预排序,gap逐渐减小

void ShellSort (int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//gap /= 2;
		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;
		}
	}


}

gap除以3最后需要加1,防止除到小于三以后,答案等于0,这样加1,保证最后gap是1

特性总结
  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当 g a p = 1 gap=1 gap=1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算
  4. 稳定性:不稳定
时间复杂度

当gap很大的时候,如 n / 3 n/3 n/3,总共有 n 3 \frac{n}{3} 3n个gap组数据,每组有3个数据,逆序的情况下,每组比较三次,第二个数据插入,比1次,第三个数据插入,比2次,总共三次,三个数据即每一组的消耗是3次;这里的间距为gap的这些数据,合计 n 3 ⋅ 3 = n \frac{n}{3}\cdot 3=n 3n3=n
gap很小的时候,如1,这个时候已经很接近有序了,间距为1的这些数据合计是n
gap为中间值的时候,消耗是逐渐变大,再逐渐变小
n / 9 n/9 n/9,假设整个数组逆序,其实之前的预排序肯定会使数据整体偏向有序, n / 9 n/9 n/9组数据,每组9个数据,单组合计1+2+3+…+8=36次;总共合计 n 9 ⋅ 36 = 4 n \frac{n}9\cdot36=4n 9n36=4n
外面的while循环,除3是 log ⁡ 3 N \log_{3}N log3N,除2是 log ⁡ 2 N \log_{2}N log2N
结论: O ( N 1.3 ) O(N^{1.3}) O(N1.3),略差于 O ( n ⋅ log ⁡ 2 N ) O(n\cdot \log_{2}N) O(nlog2N)

选择排序

基本思想

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

直接选择排序

  • 在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  • 在剩余的array[i]--array[n-2]array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
    通过遍历选出最小的交换,再选出次小的
    优化:遍历一遍选出最小的和最大的,把最小的放左边,最大的放右边
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	
	while (begin < end)
	{
		int mini = 0, maxi = 0;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
	
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}

		Swap(&a[begin], &a[mini]);

		if (maxi == begin)
		{
			maxi = mini;
		}
		
		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

从两边开始,遍历找出最小的和最大的,不断往中间走
期间如果maxi等于begin下标的数字,会被mini换走,所以要修正一下

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

堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

void AdjustDown(HPDataType* 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)
{
	//向下调整建堆
	for (int i = (n - 1 - 1)/2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}
特性总结
  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定
时间复杂度

用满二叉树来计算
因为最差的情况就是节点最多的时候
总共有h层
最后一层不需要调整,从第h-1层开始调整,每个节点向下调整一次
合计要调整
T ( h ) = 2 h − 2 + 2 h − 3 ⋅ 2 + ⋯ + 2 1 ⋅ ( h − 2 ) + 2 0 ⋅ ( h − 1 ) T(h)=2^{h-2}+2^{h-3}\cdot2+\dots+2^{1}\cdot(h-2)+2^{0}\cdot(h-1) T(h)=2h2+2h32++21(h2)+20(h1)
每层的数据个数乘以向下移动的层数
等比每项乘以等差每项
Expected node of symbol group type, but got node of type cr
T ( h ) = 2 h − 1 − h T(h)=2^{h}-1-h T(h)=2h1h
T ( h ) T(h) T(h)是向下调整建堆,最坏情况下的合计调整次数
换算关于N的式子,得到时间复杂度
T ( N ) = N − log ⁡ 2 ( N + 1 ) T(N)=N-\log_{2}(N+1) T(N)=Nlog2(N+1)
约等于N

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

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

相关文章

人数识别 人员超员识别系统 作业区域超员预警系统 ai#YOLO视觉

在当今复杂的生产作业与社会管理场景中&#xff0c;人员管理的精准性和高效性变得愈发重要。人数识别、人员超员识别系统、作业区域超员预警系统以及特殊岗位人员达标监测等&#xff0c;都是保障安全生产、提高运营效率和维护社会秩序的关键要素。随着人工智能(AI)技术的飞速发…

【Python实例】Python读取并绘制nc数据

【Python实例】Python读取并绘制nc数据 准备&#xff1a;安装netCDF库等读取nc数据相关信息绘制图形利用basemap绘图 参考 准备&#xff1a;安装netCDF库等 以【1960-2020年中国1km分辨率月降水数据集】中2020年降水为例。 先在Panopoly中查看数据属性&#xff0c;如下&#…

单细胞转录组 —— kb-python 原始数据处理

单细胞转录组 —— kb-python 原始数据处理 前言 kallisto|bustools 是一种用于预处理 scRNA-seq 数据的工作流程。 数据预处理步骤包括&#xff1a; 将 reads 与其来源细胞关联起来&#xff1b;根据唯一分子标识符&#xff08;UMI&#xff09;对 reads 进行去重&#xff1…

西门子S7-200 SMART高速计数器指令向导

在 Micro/WIN SMART 中的命令菜单中选择 Tools&#xff08;工具&#xff09;> Wizards&#xff08;向导&#xff09;中选择 High Speed Counter&#xff08;高速计数器向导&#xff09; &#xff0c;也可以在项目树中选择 Wizards&#xff08;向导&#xff09;文件夹中的 Hi…

下载相应版本的PyTorch

1、前置条件 下载某个版本的Python&#xff0c;本文涉及的Python版本为3.10 2、查看该Python版本可以下载的whl文件格式 pip debug --verbose 从上图可以发现python3.10可以下载格式为cp310-cp310-win_amd64的whl文件 PyTorch各稳定版本下载链接&#xff1a;https://downloa…

GNN与Transformer创新结合!模型性能起飞!

近年来&#xff0c;图神经网络&#xff08;GNN&#xff09;和Transformer模型因其在处理复杂数据结构和序列依赖性方面的卓越表现而受到广泛关注。这种优势使得将GNN与Transformer结合成为图表示学习领域的一个新兴且充满潜力的研究方向。通过结合这两种模型&#xff0c;我们不…

软考下午题1-数据流图

问题一&#xff1a;求实体的名称 例题&#xff1a; 1.提问方式-如问题1 从子图(0层数据流图)找比较快 外部实体可以是 人、物体、系统 在子图中找到加工&#xff0c;与文章中加工文字相对应&#xff0c;继续读文章&#xff0c;可以找到实体 E1-巴士列表文件 E2-机械师 E3-会…

《深度学习》LSTM 长短期记忆网络 结构及原理解析

目录 一、关于LSTM网络 1、什么是LSTM网络 举例&#xff1a; 2、RNN网络的结构 3、Tanh双曲正切函数 二、LSTM网络结构 1、遗忘门 1&#xff09;功能 2&#xff09;步骤 2、输入门 1&#xff09;功能 2&#xff09;步骤 3、输出门 1&#xff09;功能 2&#xff09;步骤…

斯坦福 CS229 I 机器学习 I 构建大型语言模型 (LLMs)

1. Pretraining -> GPT3 1.1. Task & loss 1.1.1. 训练 LLMs 时的关键点 对于 LLMs 的训练来说&#xff0c;Architecture&#xff08;架构&#xff09;、Training algorithm/loss&#xff08;训练算法/损失函数&#xff09;、Data&#xff08;数据&#xff09;、Evalu…

3D看车如何实现?有哪些功能特点和优势?

3D看车是一种创新的汽车展示方式&#xff0c;它利用三维建模和虚拟现实技术&#xff0c;将汽车以更真实、更立体的形式呈现在消费者面前。 一、3D看车的实现方式 1、三维建模&#xff1a; 通过三维建模技术&#xff0c;按照1:1的比例还原汽车外观&#xff0c;包括车身线条、细…

uniapp学习(003-2 vue3学习 Part.2)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战&#xff0c;开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第15p-第p20的内容 文章目录 事件监听以及组件内置事件处理自定义模板快速创建uniapp条件渲染 v-if和v-elsev-e…

骨传导耳机哪个牌子好?五大选购妙计带你精准入手优质骨传导耳机!

随着骨传导耳机市场的蓬勃发展&#xff0c;此产品凭借优秀的佩戴体验以及可降低听力损伤等优点引起了广泛的关注。然而&#xff0c;随着热度提高&#xff0c;市面上开始出现了许多品牌&#xff0c;这些品牌实力技术各不相同&#xff0c;甚至其中还有一些劣质机型&#xff0c;这…

国内经典多模态大模型工作1——Qwen-VL系列(Qwen-VL、Qwen2-VL解读)

Qwen-VL 论文标题&#xff1a;《Qwen-VL: A Versatile Vision-Language Model for Understanding, Localization, Text Reading, and Beyond》 论文链接&#xff1a;https://arxiv.org/pdf/2308.12966.pdf 项目&#xff1a;https://github.com/QwenLM/Qwen-VL/tree/master 模…

如何构建某一行业的知识图谱

构建一个行业的知识图谱是一个系统而复杂的过程&#xff0c;它涉及到数据收集、处理、分析等多个环节。以下是构建行业知识图谱的基本步骤&#xff1a; 1. 需求分析&#xff1a; - 明确构建知识图谱的目的和应用场景&#xff0c;比如是用于辅助决策、市场分析、产品推荐等。…

【python机器学习】线性回归 拟合 欠拟合与过拟合 以及波士顿房价预估案例

文章目录 线性回归之波士顿房价预测案例 欠拟合与过拟合线性回归API 介绍:波士顿房价预测数据属性:机器学习代码实现 拟合 过拟合 欠拟合 模拟 及处理方法(正则化处理)导包定义函数表示欠拟合定义函数表示拟合定义函数表示过拟合 正则化处理过拟合L1正则化L2正则化 线性回归之波…

李沐 X动手学深度学习 数据操作+数据预处理 学习笔记(无代码,纯理论部分)

数据结构介绍 机器学习和神经网络最主要的的数据结构&#xff1a;N维数组0维数组&#xff1a;标量&#xff0c;eg:1.0&#xff08;是一个浮点数&#xff0c;可能表示一个类别&#xff09;1维数组&#xff1a;向量&#xff0c;eg:[1.0, 2.7, 3.4]&#xff08;特征向量&#xf…

Java中System类和RunTime类的Api

目录 System 类 1)out 2)err 3)in 4)currentTimeMillis() 5)nanoTime() 6)arraycopy(Object 要从里面复制东西的数组, int 要从里面复制东西数组的索引起始位置, Object 获得复制元素的数组, int 获得复制元素数组的起始索引, int 要复制东西的个数) 7)gc() 8)exit(int status)…

Miniconda 入门级使用教程

前言 Miniconda是一个更小的Anaconda发行版&#xff08;Anaconda是一个包含大量预装数据科学和机器学习库的Python发行版&#xff09;&#xff0c;它只包含conda包管理器和Python以及其必要的库。Miniconda的目的是提供一个更轻量级的选项来安装和运行conda环境&#xff0c;同…

动态轻量级线程池项目

动态线程池&#xff1a; 使用线程池ThreadPoolExecutor过程中你是否有以下痛点呢&#xff1f; ① 代码中创建了一个ThreadPoolExecutor&#xff0c;但是不知道参数设置多少比较合适。 ② 凭经验设置参数值&#xff0c;上线后发现需要调整&#xff0c;改代码重新发布服务&…

电脑缺失msvcr120.dll怎样修复,马上教你6种修复方法

在用电脑的时候&#xff0c;经常会碰到各种错误提示&#xff0c;比如“msvcr120.dll丢失”&#xff0c;导致的结果就是某些程序无法正常启动。那么&#xff0c;这个dll文件到底是啥&#xff0c;为什么会丢失&#xff0c;怎么解决呢&#xff1f;将通过这篇文章详细解释一下&…