排序1——C语言

news2024/12/24 2:37:31

排序

  • 1. 复杂度
  • 2. 插入排序
    • 2.1 直接插入排序
    • 2.2 希尔排序
  • 3. 选择排序
    • 3.1 直接选择排序
    • 3.2 堆排序

排序在生活中很常见,比如在网购时,按价格排序,按好评数排序,点餐时,按评分排序等等。而排序有快和慢,快的排序效率高,慢的排序效率低,需要的时间也多。下面就一一介绍各种排序。介绍排序算法时,统一以 升序为例。

1. 复杂度

当一个算法编写完成后,运行时需要消耗时间和空间资源。因此,衡量一个算法的好坏,需要从时间和空间两个维度来衡量,即时间复杂度和空间复杂度。

时间复杂度是衡量快慢的,空间复杂度是衡量该算法运行所需的额外空间。现如今,计算机的内存空间已经很大了,因此空间复杂度已经不是特别关注了。

时间复杂度是一个函数,一个算法的基本操作的执行次数就是该算法的时间复杂度。

void Func1(int N)
{
	int count = 0;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < N; ++j)
		{
			++count;
		}
	}
}

比如这段代码主要执行的是++count语句,计算该语句的执行次数。

可以看到,++count外套了两层循环,外循环每执行一次,内循环执行N次,而外循环执行了N次,因此++count语句执行了N^2次。算法的执行次数最多的语句一般在循环内部。因此计算时间复杂度,首要计算的就是循环内的。而这个函数可能是若干多项式的和,我们不可能把这个算法的时间复杂度算的非常清楚,只需要知道大概就可以了。因此时间复杂度采用大O渐进表示法

大O渐进表示法:
1.在这个运行次数的函数中,只保留最高阶的那一项,比如10N^2+2N+2---->10N^2
2.如果最高阶存在并且不是1,那么将该项的系数化为1,比如10N^2 —>N^2

最终我们就得到了一个很简单的函数。此外,有些算法的时间复杂度在不同情况下会有不同,因此需要计算最坏情况和最好情况,有些排序算法就存在这种情况。

空间复杂度也是一个函数,是对一个算法在运行过程中临时占用存储空间大小的量度 。
空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。空间复杂度计算的是额外使用的空间的大小,不包括本身对变量开辟的空间。

复杂度主要有以下几种
在这里插入图片描述

其中含有对数的主要是以2为底数的。

2. 插入排序

2.1 直接插入排序

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

什么意思呢?我们举一个例子,比如将排序5,9,7,6,2
排序过程如下。
在这里插入图片描述
当数组遍历完,得到的就是有序的数组了。

void InsertSort(int* array, int numsArr)//待排序数组和数组大小
{
	//插入numsArr-1次
	for (int i = 0; i < numsArr - 1; i++)
	{
		int end = i;
		int tmp = array[end + 1];

		while (end >= 0)
		{
			//后移
			if (array[end] > tmp)
			{
				array[end + 1] = array[end];
				--end;
			}
			else
			{
				break;
			}
		}
		array[end + 1] = tmp;
	}
}

直接插入排序的时间复杂度分最好情况和最坏情况,最好情况是数组本就有序,不需要插入,但是需要遍历一遍数组,所以时间复杂度为O(N);最坏情况是数组逆序,插入的次数是1,2,3,4…N-3,N-2,N-1次,数据是一个等差数列,计算出来为**(N^2-N)/2** 根据大O渐进表示法最终化简为O(N^2);

结论:最坏情况O(N^2)最好情况O(N)
空间复杂度O(1),表示没有用到额外空间。

2.2 希尔排序

希尔排序又称为缩小增量排序,希尔排序对直接插入排序进行了优化,先进行若干次预排序,在进行一次直接插入排序,预排的作用是使得所有记录更快的接近有序。

基本思想是:先选定一个整数(假设为K),把待排序的所有记录分成K个
,所有距离为K的记录分在同一组内,并对每一组内的记录进行插入排序。然后缩小K的值,重复上述分组和排序的工作。当K=1时,所有记录在一组内排好序。

这里举例将10,9,8,7,6,5,4,3,2,1进行第一轮的排序,假设K=3;
排序过程如图
在这里插入图片描述
可以看到,第一轮的排序结果,已经很接近有序了,缩小K的值,在进行分组和排序,当K=1时,所有数据为一组,此时进行的就是直接插入排序。

将数据分组进行预排,可以将更小的数据更快的插入到前面更大的数据更快的移到后面,减少了插入和移动的次数。

整数的选择也是一个问题,太小了会导致预排效果不明显,太大了会导致预排次数变多,因此整数的每次选取方式为缩小三倍在加1,加1会使得最后一次这个整数一定为1。即最后一次的排序一定是直接插入排序。

代码如下

void ShellSort(int* array, int numsArr)
{
	int gap = numsArr;
	while (gap > 1)
	{
		//间隔gap的数据作为一组,一共gap组
		//gap=1时是直接插入排序
		gap = gap / 3 + 1;    
		for (int i = 0; i < numsArr - gap; i++)
		{
			int end = i;
			int tmp = array[end + gap];
			while (end >= 0)
			{
				//往后挪数据
				if (array[end] > tmp)
				{
					array[end + gap] = array[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			array[end + gap] = tmp;
		}
	}
}

希尔排序的时间复杂度比较难算,因为预排和gap的选择会影响结果,并且每一次的预排都会对下一次的预排产生影响。这里直接说结论,希尔排序的时间复杂度大约为N^1.3。

3. 选择排序

3.1 直接选择排序

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

这里进行一个小的优化,同时选出最大和最小的元素,分别放到末尾和起始位置。

但也会产生一个小问题,我们先看代码。

void SelectSort(int* array, int numsArr)
{
	int begin = 0, end = numsArr - 1;
	while (begin < end)
	{
		//最大最小值的下标
		int minIndex = begin, maxIndex = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			//找最小值并更新下标
			if (array[i] < array[minIndex])
			{
				minIndex = i;
			}
			//找最大值并更新下标
			if (array[i] > array[maxIndex])
			{
				maxIndex = i;
			}
		}
		swap(&array[begin], &array[minIndex]);
		//最大值和起始位置重复了
		if (maxIndex == begin)
			maxIndex = minIndex;
		swap(&array[end], &array[maxIndex]);
		begin++;
		end--;
	}
}

问题是会产生数据重复,看下面这组数据。
9,2,3,4,5,6,8,1
如果没有这两条语句会产生什么情况。

if (maxIndex == begin)
maxIndex = minIndex;

在这里插入图片描述
当最大值的下标和起始位置的下标重复,就会产生上面的情况,解决办法就是加上判断语句。

时间复杂度:O(N^2)
空间复杂度:O(1)

3.2 堆排序

关于堆排序在之前已经介绍过了,这里就不在赘述了,大家可以看这篇进行了解:堆的应用
代码如下

void HeapSort(int* array, int numsArr)
{
	//向下调整建堆,复杂度O(N)
	for (int i = (numsArr - 2) / 2; i >= 0; i--)
	{
		AdJustDown(array, numsArr, i);
	}

	//升序建大堆;降序建小堆
	//复杂度O(N*logN)
	int i = numsArr - 1;
	while (i > 0)
	{
		swap(&array[0], &array[i]);//交换首尾元素
		AdJustDown(array, i, 0);
		i--;
	}
}
void AdJustDown(int* array, int num_array, int parent)//建大堆
{
	//假设左孩子符合条件
	int child = parent * 2 + 1;

	while (child < num_array)
	{
		//存在右孩子且右孩子符合条件
		if (child + 1 < num_array && array[child + 1] > array[child])
		{
			++child;
		}
		
		if (array[child] > array[parent])
		{
			//交换数据
			swap(&array[child], &array[parent]);
			//更新下标
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

这里对堆排序的时间复杂度进行一个计算。
如下图,这是建堆的时间复杂度

在这里插入图片描述
根据大O渐进表示法,最终建堆的时间复杂度为O(N)

而进行排序时,时间复杂度为
在这里插入图片描述
建堆的时间复杂度为O(N),排序的时间复杂度为O(NlogN),最大项为NlogN,因此堆排序的时间复杂度为O(N*logN)

关于其他排序,后续会依次介绍。

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

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

相关文章

vue2响应式原理----发布订阅模式

很多人感觉vue2的响应式其实用到了观察者发布订阅。我们先来看一下简单的发布订阅的代码&#xff1a; // 调度中心 class Dep {static subscribes {}// 订阅所有需求static subscribe (key, demand) {// 对需求分类收集if (!Dep.subscribes[key]) Dep.subscribes[key] []Dep…

使用腾讯云服务器如何搭建网站?新手建站教程

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com整理使用腾讯云服务器建站教程&#xff0c;…

前端下载url文件(解决PDF, 图片自动在浏览器打开)

常规下载方法&#xff1a; /* 方法1 */ window.open(下载url地址, _blank)/* 方法2 */ const link document.createElement("a"); link.download true; link.href 下载url地址; link.click(); document.body.removeChild(link);pdf文件默认在浏览器中展示解决方案…

Linux:Zabbix + Grafana10.4.2(3)

1.部署zabbix 下面这篇文章写了详细的部署zabbix过程 &#xff0c;使用的centos9系统 Linux&#xff1a;部署搭建zabbix6&#xff08;1&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/137426966?spm1001.2014.3001.5501下面这篇文章使用的是centos7…

RTSP/Onvif安防视频EasyNVR平台 vs.多协议接入视频汇聚EasyCVR平台:设备分组的区别

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&#xff0c;能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、W…

二叉树练习day.8

235.二叉搜索树的最近公共祖先 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共…

30万的源码和300的源码有什么区别?

源码的质量很大程度上取决于其来源、开发者的技术水平和项目的具体需求。有些源码可能确实存在一些问题&#xff0c;比如代码结构混乱、注释不清晰、性能不佳等。 而价高优秀的源码都采用了高效的数据结构和算法&#xff0c;代码结构清晰&#xff0c;逻辑严谨&#xff0c;具有良…

ubuntu22下使用vscode调试redis7源码环境搭建

ubuntu22下使用vscode调试redis7源码环境搭建 ##vscode launch.json配置文件 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0&…

【神经网络与深度学习】循环神经网络基础

tokenization tokenization&#xff1a;分词 每一个词语都是token 分词方法&#xff1a;转为单个词、转为多个词语 N-gram表示法 准备词语特征的方法 &#xff08;把连续的N个词作为特征&#xff09; 如 ”我爱你“——>[我&#xff0c;爱&#xff0c;你] 2-gram——[[我…

游戏服务器DDOS克星-抗D盾(游戏盾)

随着网络游戏市场的不断扩大和发展&#xff0c;游戏服务器遭受DDOS攻击的频率也在逐年增加。DDOS攻击的主要目的是使游戏服务器瘫痪&#xff0c;使得游戏无法正常进行&#xff0c;导致游戏运营商巨额损失。鉴于此&#xff0c;针对游戏服务器的防DDOS攻击技术德迅云安全自主研发…

Ubuntu 22上安装Anaconda3。下载、安装、验证详细教程

在Ubuntu 22上安装Anaconda3&#xff0c;你可以遵循以下步骤&#xff1a; 更新系统存储库&#xff1a; 打开终端并运行以下命令来更新系统存储库&#xff1a; sudo apt update安装curl包&#xff1a; 下载Anaconda安装脚本通常需要使用curl工具。如果系统中没有安装curl&#x…

【Python函数和类4/6】递归与匿名函数

目录 目标 匿名函数 多个形参 匿名函数的局限性 递归 语言例子 数学例子 递归的实现 递归代码 练习 总结 目标 在之前的博客中&#xff0c;我们学习了定义函数、调用函数以及设置函数的参数。在今天&#xff0c;我们会补充函数的两个常见的知识点&#xff0c;一个是匿…

前端css笔记(pink老师)

css css书写顺序 自适应屏幕 html { width: 100%; height: 100%; display: table; } body { display: table-cell; } 用了这个方法以后&#xff0c;如果希望页面内的盒子也适应屏幕大小&#xff0c;则使用以下方法&#xff0c;会根据父亲的宽高计算出该盒子的宽高 width:xx%; …

策略模式(知识点)——设计模式学习笔记

文章目录 0 概念1 使用场景2 优缺点2.1 优点2.2 缺点 3 实现方式4 和其他模式的区别5 具体例子实现5.1 实现代码 0 概念 定义&#xff1a;定义一个算法族&#xff0c;并分别封装起来。策略让算法的变化独立于它的客户&#xff08;这样就可在不修改上下文代码或其他策略的情况下…

死锁的成因, 和解决方案.

死锁 死锁就是两个或两个以上线程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象&#xff0c;若无外力作用&#xff0c;它们都将无法推进下去。 成因 1.一个线程一把锁 一个线程&#xff0c;对同一个对象&#xff0c;重复加锁两次&#xff0c;如…

相机参数的意义

相机标定的意义&#xff1a; 相机标定&#xff1a;使用带有pattern的标定板来求解相机参数的过程&#xff1b;用一个简化的数学模型来代表复杂的三维到二维的成像过程&#xff1b;相机参数包括&#xff1a;相机内参&#xff08;焦距等&#xff09;&#xff0c;外参&#xff08…

⑤-1 学习PID--什么是PID

​ PID 算法可以用于温度控制、水位控制、飞行姿态控制等领域。后面我们通过PID 控制电机进行说明。 自动控制系统 在直流有刷电机的基础驱动中&#xff0c;如果电机负载不变&#xff0c;我们只要设置固定的占空比&#xff08;电压&#xff09;&#xff0c;电机的速度就会稳定在…

Solana 上创建自己的 SLPToken:简明指南

Solana 定义 Solana 是由 Solana Labs 创建的区块链平台&#xff0c;旨在提供高吞吐量和低延迟的去中心化应用&#xff08;DApps&#xff09;开发环境。它采用一系列创新技术&#xff0c;如 PoH&#xff08;Proof of History&#xff09;共识机制和 Tower BFT&#xff08;BFT …

好用的企业知识管理SaaS产品推荐来啦,小白必看!

知识管理在企业运营中扮演了重要角色&#xff0c;特别是在现代化办公环境下&#xff0c;一个高效卓越的知识管理系统是企业提高生产力、促进创新和保持竞争力的关键。SaaS(Software as a Service) 我们通常称之为“软件即服务”&#xff0c;为企业提供了灵活、高效和划算的知识…

每日一题(力扣)---插入区间

官方网址&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表 intervals&#xff0c;其中 intervals[i] [starti, endi] 表示第 i 个区间的开始和结束&#xff0c;并且 intervals按照 st…