数据结构初阶之排序(上)

news2024/9/21 4:30:36

排序的概念及其应用

排序的概念

排序:所谓排序,就是使⼀串记录,按照其中的某个或某些关键字的⼤⼩,递增或递减的排列起来的操作。

排序的应用

如下图:


样例数组

下面我们给出一组乱序的数组,接下来的算法我们都将以该数组为例进行排序测试。

int a[] = {5, 3, 9, 6, 2, 4, 7, 1, 8};

常见的排序算法

排序在我们的日常生活中可谓是无处不在,它潜移默化的影响着我们的生活。那么今天,我将为大家介绍一下几种常见的排序算法-----我们先来看一下总览图

插入排序

顾名思义,插入排序就好比打扑克时的理牌

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

下面我们通过一张动图来了解直接插入排序:

代码的实现:

首先来写一个交换元素的过程:

void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void InsertSort(int* arr, int n)
{
	//n-2
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];

		while (end >= 0)
		{
			if (arr[end] > tmp)
			{
				arr[end + 1] = arr[end];
				end--;
			}
			else {
				break;
			}
		}
		arr[end + 1] = tmp;
	}
}

直接插入排序的特征

直接插⼊排序的特性总结

1. 元素集合越接近有序,直接插⼊排序算法的时间效率越⾼

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

3. 空间复杂度:O(1)

那么问题来了,直接插入排序的时间复杂度来到了惊人的N^2,它是否还能继续优化呢?

答案是肯定的:

希尔排序

希尔排序法⼜称缩⼩增量法

希尔排序法的基本思想是:先选定⼀个整数(通常是gap=n/3+1),把待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于直接插⼊排序。

希尔排序是在直接插⼊排序算法的基础上进⾏改进⽽来的,综合来说它的效率肯定是要⾼于直接插⼊排序算法的。

如图所示:

希尔排序的特征

1. 希尔排序是对直接插⼊排序的优化。

2. 当 gap > 1 时都是预排序,⽬的是让数组更接近于有序。当 gap == 1 时,数组已经接近有序的了,这样就会很快。这样整体⽽⾔,可以达到优化的效果。

3.

代码的实现:

//希尔排序时间复杂度大约为:O(n^1.3)
void ShellSort(int* arr, int n)
{
	int gap = n;//6

	while (gap > 1)
	{
		gap = gap / 3 + 1;//保证最后一次gap一定为1
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;//n-gap-1
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else {
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

希尔排序的时间复杂度大约在(N^1.3),它对直接插入排序进行了分组预排序处理。大大提高了算法效率


选择排序

选择排序的基本思想:

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

我们还是用一张动图来了解选择排序的工作原理:

代码的实现:

//时间复杂度为O(n^2)
void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;

	while (begin < end)
	{
		int mini = begin, maxi = begin;
		for (int i = begin+	1; i <= end; i++)
		{
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
		}
		//mini begin
		//maxi end
		//避免maxi begini都在同一个位置,begin和mini交换之后,maxi数据变成了最小的数据
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&arr[mini], &arr[begin]);
		Swap(&arr[maxi], &arr[end]);

		++begin;
		--end;
	}
	
}

直接选择排序的特征

1. 直接选择排序思考⾮常好理解,但是效率不是很好。实际中很少使⽤

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

3. 空间复杂度:O(1)


堆排序(选择排序的一种)

堆排序(Heapsort)是指利⽤堆积树(堆)这种数据结构所设计的⼀种排序算法,它是选择排序的⼀ 种。它是通过堆来进⾏选择数据。需要注意的是排升序要建⼤堆,排降序建⼩堆。

堆排序是通过比较每一层父节点与子节点间的大小后进行的递归性的排序,相较于直接选择排序与直接插入排序,它是相当高效的,下面我们来欣赏一下它的代码实现:

代码的实现:

首先便是向下调整的过程:

void AdjustDown(int* arr, int parent, int n)
{
	int child = parent * 2 + 1;//左孩子
	//while (parent < n)
	while (child < n)
	{
		//小堆:找左右孩子中找最小的
		//大堆:找左右孩子中找大的
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;

		}
		else
		{
			break;
		}
	}
}

接下来便是建堆,堆顶与堆底元素的交换后向下调整的过程:

//堆排序
//空间复杂度为0(1)
//时间复杂度为O(n*logn)
void HeapSort(int* arr, int n)
{
	//建堆
	//升序---大堆
	//降序----小堆
	//向下调整算法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, i, n);
	}

	//循环将堆顶数据跟最后位置(会变化,每次减少一个数据)的数据进行交换
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, 0, end);
		end--;
	}
}

交换排序

交换排序基本思想:

所谓交换,就是根据序列中两个记录键值的⽐较结果来对换这两个记录在序列中的位置

交换排序的特点是:将键值较⼤的记录向序列的尾部移动,键值较⼩的记录向序列的前部移动

交换排序中最为基础也最为典型的便是冒泡排序。

冒泡排序:

我们通过一张图来了解:

该排序算法可谓是通俗易懂,但是它的缺点也相当明显(它的时间复杂度相当差)

代码的实现:

void BubbleSort(int* a, int n) 
{
 int exchange = 0;
 for (int i = 0; i < n; i++)
 {
 for (int j = 0; j <n-i-1 ; j++)
 {
 if (a[j] > a[j + 1]) 
 {
 exchange = 1;
 swap(&a[j], &a[j + 1]);
 }
 }
 if (exchange == 0) 
 {
 break;
 }
 }
}

冒泡排序的特征

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

• 空间复杂度:O(1)


结尾

以上便是本期的全部内容,下期我将继续为大家分享剩下的快速排序算法,敬请期待哦~

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

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

相关文章

程序员进阶架构知识体系、开发运维工具使用、Java体系知识扩展、前后端分离流程详解、设计模式开发实例汇总专栏分享

场景 作为一名开发者&#xff0c;势必经历过从入门到自学、从基础到进阶、从学习到强化的过程。 当经历过几年企业级开发的磨炼&#xff0c;再回头看之前的开发过程、成长阶段发现确实是走了好多的弯路。 作为一名终身学习的信奉者&#xff0c;秉承持续学习、持续优化的信念…

GitHub推出全新AI模型平台:简化开发者体验

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

《计算机网络》(第8版)第8章 互联网上的音频/视频服务 复习笔记

第 8 章 互联网上的音频/视频服务 一、概述 1 多媒体信息的特点 多媒体信息&#xff08;包括声音和图像信息&#xff09;最主要的两个特点如下&#xff1a; &#xff08;1&#xff09;多媒体信息的信息量往往很大&#xff1b; &#xff08;2&#xff09;在传输多媒体数据时&a…

【网络】TCP协议——TCP连接相关、TCP连接状态相关、TCP数据传输与控制相关、TCP数据处理和异常、基于TCP应用层协议

文章目录 Linux网络1. TCP协议1.1 TCP连接相关1.1.1 TCP协议段格式1.1.2 确定应答(ACK)机制1.1.3 超时重传机制 1.2 TCP连接状态相关1.2.1 TIME_WAIT状态1.2.2 CLOSE_WAIT 状态 1.3 TCP数据传输与控制相关1.3.1 滑动窗口1.3.2 流量控制1.3.3 拥塞控制1.3.4 延迟应答1.3.5 捎带应…

草的渲染理论

Unity引擎提供了基础的terrain工具&#xff0c;可以制作地形&#xff0c;在上面刷树刷草。对于树&#xff0c;Unity是支持带LOD的Prefab&#xff0c;不同距离显示不同细节的模型&#xff0c;效果还不错。对于草&#xff0c;Unity支持两种方式来刷草&#xff0c;一种是Add Grass…

汇凯金业:解读区块链概念、类型与独特优势

区块链作为一种具有革命性的创新技术&#xff0c;正在逐渐改变我们的生活和商业模式。它的去中心化、安全可靠、不可篡改等特性&#xff0c;为解决许多传统领域中的问题提供了新的思路和方法。 一、区块链的基本概念 区块链是一种具有创新性的计算机技术应用模式&#xff0c;…

C#复习之类和对象

知识点一&#xff1a;什么是类 基本概念&#xff1a; 具有相同特征 具有相同行为 一类事物的抽象 类是对象的模板 可以通过类创建出对象 类的关键字 Class 知识点二&#xff1a;类声明在哪里 类一般声明在namespace语句块中 知识点三&#xff1a;类声明的语法 知识点四&#xf…

html+css 实现文字滚动的按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

2024年前端趋势:全栈或许是不容错过的选择!

近年来&#xff0c;前端开发的技术不断推陈出新&#xff0c;2024年也不例外。在这个变化迅速的领域&#xff0c;全栈开发逐渐成为一股不容忽视的趋势。无论你是经验丰富的开发者&#xff0c;还是刚刚入门的新手&#xff0c;掌握全栈技术都能让你在竞争中脱颖而出。而在这个过程…

Spring -- 拦截器

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 文章目录 1. 自定义拦截器2. 注册配置拦截器3. 拦截器详解3.1 拦截路径3.2 拦截器执行流程 3.3 DispatcherServlet源码分析3.3.1 初始化:3.3.2 处理请求3.3.3 适配器 拦截器是Spring框架提供的…

vue项目删除无用的依赖

1.安装依赖检查工具 npm i depcheck 2.查看无用的依赖 npx depcheck 3.手动删除pageage.json中的无用的依赖&#xff08;如果有sass和sass-loader不要删&#xff0c;会引起项目报错&#xff09; 4.全部删除完成之后&#xff0c;删除package-lock.json和yarn.lock文件&#x…

【文件解析漏洞复现】

一&#xff0e;IIS解析漏洞复现 1.IIS6.X 方式一&#xff1a;目录解析 搭建IIS环境 在网站下建立文件夹的名字为.asp/.asa 的文件夹&#xff0c;其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行。 访问成功被解析 方式一&#xff1a;目录解析 在IIS 6处理文件解…

图纸加密与零信任沙箱:构建企业数据安全的双重保障

在这个信息爆炸的时代&#xff0c;数据安全如同一场没有硝烟的战争。深信达SDC沙盒防泄密系统&#xff0c;以其零信任沙盒技术&#xff0c;为企业提供了一个坚不可摧的“金钟罩铁布衫”&#xff0c;确保企业图纸安全“坚如磐石”。 一、数据安全的“冰与火之歌” 数据安全是一…

如何简便改文件名

在出OI题的时候&#xff0c;有时候想要方便地把输入输出文件的文件名都改掉&#xff0c;类似于将a1.in,a2.in,…,a50.in都改成b1.in,b2.in,…,b50.in 我用gpt写了一个python代码 import osdef rename_files(base_name, new_name, num_files):for i in range(1, num_files 1)…

函数实例讲解 (一)

文章目录 函数中的引用、运算符、通配符1、引用2、运算符3、通配符 函数的类别、输入方式、结果检查1、函数类别2、输入方式3、结果检查 数组的基本概念1、数组极其元素的概念2、数组的书写3、数组的类型4、内存数组的存储位置5、数组公式与普通公式的区别 逻辑判断函数之IF1、…

【工具】-gdb-学习笔记

准备工作 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须在源代码生成二进制程序的时候, 加上 -g 选项&#xff0c;发布成debug模式 如下源代码经过编译&#xff1a; #…

VS Code C/C++ MSVC编译器

官方教程 通过快捷方式打开VS Code是编译不了的,需要对tasks.json修改(Tasks: Configure default build task) 先创建tasks.json 复制这段配置到tasks.json,记得修改VsDevCmd.bat的路径 {"version": "2.0.0","windows": {"options"…

深度学习中卷积算子和dropout算子的作用

笔者在调网络的时候&#xff0c;有时调细一些在想不同卷积核尺寸的卷积操作有啥区别&#xff0c;在哪些算子后用dropout会比较好呢&#xff1f;于是有了下面一段总结。 文章目录 一、卷积核尺寸1X1和3X3的区别1x1卷积核3x3卷积核 二、dropout的作用使用情况算子组合注意事项 一…