排序算法1:堆排序,直接插入排序与希尔排序

news2024/12/23 0:07:58

前言

前些时间,博主带领着大家学习了数据结构,数据结构中的二叉树更是其中的重中之重,我们之前了解了二叉树是现实计算机存储数据的一种重要形式。借助其结构,我们还能实现更多高效的功能。

今天我们将进入排序算法的章节,首先我们会先学习,基于二叉树顺序结构—堆, 而实现的堆排序,还有两种重要的排序方法,直接插如排序和希尔排序,同时我们将探讨他们的排序时间复杂度。

好,废话不多说,开始我们今天的正题:

1.堆排序

在我们上次刚实现二叉树顺序结构的基础上,我们根据这个排序的名字就能够知道,这个·排序的的实现逻辑与堆有关系,所以如果我们有一个如下的数组,我们要怎样的排序呢?

不了解二叉树顺序结构的同学,可以先去看看我之前的这篇文章:http://t.csdnimg.cn/A165d

int arr[] = {17, 20, 10, 13, 19, 15}

1.1建堆

首先我们还是要建成一个堆的结构:

我们需要像之前一样,通过HPPush函数将所有的元素都推进一个新创建的堆中吗?

如果是这样的话,我们的空间复杂度就会变为O(n),对我们的程序运行并不是很友好。

那我们可以怎样来建成一个堆呢?

还记得我们在实现二叉树结构的向上、向下调整算法吗?

void AdjustUp(HpDataType* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1 )/ 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(int* arr, int parent, int n)
{
	int child = parent  * 2 + 1;
	if (arr[child] < arr[child + 1])
	{
		child++;
	}
	while (child < n)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[parent], &arr[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			break;
	}
}

其实,二叉树的顺序结构堆的底层结构就是数组,那我们就只需要将数组中的元素进行向上向下的调整,就可以建成我们需要的大堆(小堆)了。

int main()
{
	int arr[] = { 17, 20, 10, 13, 19, 15 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		AdjustUp(arr, i);
	}

	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们可以看到,通过向上调整算法,就可以在原数组的基础上直接建成大堆!!

1.2排序 

根据大小堆的性质,我们可以这样来进行排序呢?

我们先来看看我们已经建成的大堆:

大堆,就是整个数组最大的值放在了堆顶。相反,小堆的堆顶元素就是最小值。

所以如果我们要进行升序操作,我们可以将堆顶的元素与堆尾的元素交换位置,同时缩小向下调整的范围,就可以得到排序的结果。 

 

代码实现:

int main()
{
	int arr[] = { 17, 20, 10, 13, 19, 15 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		AdjustUp(arr, i);
	}
	int end = sz - 1;
	while (end > 1)
	{
		Swap(&arr[0], &arr[end]);//交换堆顶和堆尾的数据
		AdjustDown(arr, 0, end);
		end--;//缩小调整范围
	}
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

这样,堆排序就完成了!! 

接下来我们想要实现数组元素的降序,我们该怎么办呢?

不难看出,我们想要实现降序就要通过建小堆,所以我们就要在建堆的操作上下功夫:

void AdjustUp(HpDataType* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])//当子节点的值比父节点的小时,进行交换,如此堆顶的元素就是最小的元素
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1 )/ 2;
		}
		else
		{
			break;
		}
	}
}

 ,可以发现,我们现在就成功的建成了一个小堆。

接下来,我们再将向下调整算法,修改一下。

void AdjustDown(int* arr, int parent, int n)
{
	int child = parent  * 2 + 1;
	if (arr[child] > arr[child + 1])//降序时,要找出左右子节点中值较小的那个
	{
		child++;
	}
	while (child < n)
	{
		if (arr[child] < arr[parent])//子节点比父节点值小时交换,堆顶的元素就是堆中排序范围中最小的那个
		{
			Swap(&arr[parent], &arr[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			break;
	}
}

 这样我们就轻松的实现了数组的降序排列

2.直接插入排序

当插入第i(i>=1)个元素时,前面的arr[0], arr[1],....arr[1 - 1]已经排序好了,此时用arr[i]的排序码与arr[i - 1],arr[i - 2],...的排序码顺序进行比较,找出插入位置将arr[i]插入,原来位置上的数据后移。

 这里我们画图理解一下,这个排序算法的思想:

加入我们现在有这样的数组:

接下来我们按照这个思路来实现代码:

void InsertSort(int* arr, int n)
{
	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;
	}
}

 我们来验证一下:

直接插入排序就实现了。

3.希尔排序

希尔排序有被称之为缩小增量法。希尔排序法的基本思想是:先选定一个整数(通常gap = n / 3 + 1),把待排序的文件所有记录分成各组,所有的距离相同的记录分在同一组内,并对每一组内的记录进行排序,然后将gap = gap / 3 + 1得到下一个整数,再将数组分成各组,进行插入排序,当gap = 1时,就相当于进行直接插入排序。

他是在直接插入排序的基础上进行优化得来的,综合来说他的效率要高于直接插入排序!!

void ShellSort(int *arr, int sz)
{
	int gap = sz;
	while (gap > 1)//在gap等于1之前的排序,我们都可以看做是预排序,可以让小的数据先出现在前面,大的数据出现在后面,
	{//从而是排序的时间复杂度降低
		gap = gap / 3 + 1;
		for(int  i = 0; i < sz - gap; i++)
		{
			int end = i;
			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;
		}
	}
}

好,今天的内容就到这里,我们下期再见!!

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

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

相关文章

Spring MVC框架学习笔记

学习视频:10001 Spring MVC概述_哔哩哔哩_bilibili~11005 请求映射方式_哔哩哔哩_bilibili 目录 1.概述 Java EE三层架构 Spring MVC在三层架构中的位置 ​编辑 Spring MVC在表现层的作用 Spring MVC的特点 2.Spring MVC入门程序 代码实现 Spring MVC工作原理 Spring …

ETF套利有什么好用的软件?ETF套利神器—万得宏汇

ETF套利全场景覆盖&#xff0c;支持瞬时、趋势、事件套利等业务场景。丰富的组合交易工具、灵活高效的窗口设置&#xff0c;叠加ETF利润计算器联动&#xff0c;让ETF投资更轻松。 L2行情极速柜台&#xff0c;交易快人一步 市场行情瞬息万变&#xff0c;行情速度决定交易速度&a…

智能化解决方案:提升汽车制造图文档发送效率,实现高效传输

汽车制造业企业数据外发需求频繁&#xff0c;不仅有与异地研发机构间、供应商之间的协同研发文件交换&#xff0c;还有与外包供应商及零部件供应商之间的基于价值链的协同关系。主要涉及的数据类型有&#xff1a;汽车制造图文档发送、研发数据发送、项目文件发送、反馈数据与协…

用 GO 开发一个windows桌面图形化软件入门

项目采用的是walk技术方案 一、初始化项目 创建一个文件夹比如demo&#xff0c;然后进入demo执行 go mod init demo 二、安装walk模块 go get github.com/lxn/walk go get github.com/lxn/win 三、安装rsrc 安装&#xff1a; go install github.com/akavel/rsrc 生成*…

【突发】国内大量家用路由器网络访问异常和流量劫持事件分析

以下内容由WebRAY和Panabit联合发布 0x01 事件背景 从2024年5月开始&#xff0c;国内部分家用路由器开始出现间歇性断网、域名解析延迟高以及解析到海外IP等情况&#xff0c;今年8月该现象变得尤为严重。前几天在做应急响应时候发现某企业暴露在公网上的路由器配置的DNS地址被莫…

无线自组网应急指挥系统解决方案详解

随着全球自然灾害频发和社会应急事件的增加&#xff0c;如地震、洪水、泥石流等&#xff0c;传统的通信手段在面对这些极端情况时往往显得力不从心。尤其是在灾区&#xff0c;基础设施的损毁往往导致通信网络瘫痪&#xff0c;使得救援行动陷入困境。如何在这种紧急情况下迅速建…

深度学习入门(六):无监督学习

一、K-means算法 K-means算法是一种常用的聚类算法&#xff0c;旨在将数据集划分成 k 个簇&#xff0c;使得每个簇中的数据点尽可能相似&#xff0c;而不同簇之间的数据点差异尽可能大。该算法是基于迭代的方法来寻找最优的簇中心&#xff0c;并通过不断调整簇的划分来最小化簇…

【web安全】权限漏洞之未授权访问

一.Jenkins未授权访问漏洞 步骤一&#xff1a;使用以下fofa语法进行搜索 port"8080" && app"JENKINS" && title"Dashboard [Jenkins]" 步骤二&#xff1a;进入执行页面http://xxx.xxx.xxx.xxx:xxxx/manage/script/index.php 执…

预训练大语言模型综述来了!中国人民大学教授发表包含了416个参考文献的大语言模型综述

尽管大语言模型在最近今年发展十分迅速&#xff0c;但是相关的综述却相对比较落后。本文是由中国人民大学教授Wayne Xin Zhao等人前几天刚公开的关于大语言模型的综述&#xff0c;论文正文部分共32页&#xff0c;包含了416个参考文献。内容十分详实。 这份大模型综述我已经打包…

【iOS多线程(三)】优先级反转问题

优先级反转 实时操作系统的一个基本要求就是基于优先级的抢占系统。保证优先级高的线程在“第一时间”抢到执行权&#xff0c;是实时系统的第一黄金准则。 但是这种基于优先级抢占的系统&#xff0c;有一个著名的问题需要关注&#xff0c;就是“优先级反转”&#xff08;Prio…

优思学院:标准化作业在精益管理之屋中的位置

除了两大支柱&#xff0c;我们必须要对整个精益之屋进行理解&#xff0c;才可以知道精益生产的全貌。精益之屋由4部分组成&#xff1a;地基、2个支柱和屋顶。 首先&#xff0c;地基就是5S活动、目视化管理、标准化作业来建立稳定性。 而标准化作业正正是大家都忽略&#xff0…

计算机网络408考研 2020

2020 湖科大教书匠的个人空间-湖科大教书匠个人主页-哔哩哔哩视频 计算机网络408考研 历年真题解析&#xff08;有字幕无背景音乐版&#xff09;_哔哩哔哩_bilibili 计算机网络408考研2020年真题解析_哔哩哔哩_bilibili 1 2 3 41 11 1

cmake 编译教程

一、只有一个源文件的程序编译 首先在当前目录下创建两个文件 hello.cpp CMakeLists.txt &#xff08;注意CMakeLists大小写&#xff0c;不要写错了&#xff09; cmake_minimum_required (VERSION 2.8)project (learn_cmake)add_executable(hello hello.cpp) 第一行意思是…

基于R语言绘制GGE双标图4

参考资料&#xff1a; https://cran.r-project.org/web/packages/GGEBiplots/GGEBiplots.pdf 1、数据整理 使用GGEBiplots包绘制双标图&#xff0c;分析用数据是二维数据表&#xff08;行表示品种或基因型&#xff0c;列表示试验点或环境&#xff09;。当我们的数据表是一维数…

ip地址是公网还是内网?内网电脑ip地址在哪看

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识符&#xff0c;扮演着至关重要的角色。然而&#xff0c;你是否知道IP地址是内网还是外网&#xff1f;对于内网电脑&#xff0c;我们又该如何快速准确地找到其IP地址呢&#xff1f;下面带着这些疑问跟着虎观代理小二一起深…

《python语言程序设计》2018版第6章第37题,随机生成字符,使用RandomCharacter生成100个小写字母,每行15个

一、正常输出方法设计的代码结构 老规矩用正常输出法设计代码结构 def getRandomCharacter(ch1, ch2):return chr(random.randint(ord(ch1), ord(ch2)))def getRandomLowerCaseLetter():return getRandomCharacter(a, z)count 0 for i in range(100):count 1a getRandomLowe…

深度学习实战(1):树叶分类pytorch

Classify Leaves | Kaggle 上面是数据集 数据导入与数据处理 %matplotlib inline import torch from torch.utils import data as Data import torchvision from torch import nn import torchvision.models as models from IPython import display import os import pandas…

leetcode69. x 的平方根,二分法

leetcode69. x 的平方根 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0…

培训第二十三天(mysql主从脚本与mysql详细语句介绍)

上午 在同步时&#xff0c;对删除和修改都比较慎重&#xff08;监控同步时&#xff09; mysql主从搭建 前提软件libaio&#xff0c;rsync 1、主2、从3、同步4、测试 注意&#xff1a;先执行从服务器的脚本&#xff0c;再执行主服务器脚本 master-mysql配置脚本 先要在主服务…

企元数智小程序合规分销系统赠送:迎接数字化时代商机

当今时代&#xff0c;随着科技的高速发展和数字化的普及&#xff0c;企业如何抓住数字化时代带来的商机&#xff0c;成为了业界关注的焦点。在这样一个竞争激烈的市场环境下&#xff0c;企业需要不断提高自身的竞争力和应变能力&#xff0c;以应对激烈的市场竞争&#xff0c;开…