[数据结构] 排序#插入排序希尔排序

news2024/11/17 22:24:30

标题:[数据结构] 排序#插入排序&希尔排序

@水墨不写bug



目录

(一)插入排序

实现思路:

插入排序实现: 

(二)希尔排序

希尔排序的基本思想: 

希尔排序的实现:


正文开始:

        排序是日常生活中常见的对数据的需求,排序有多重不同的方法,每一种方法都有各自的优缺点,本文来为你介绍两个思路类似的排序方法:插入排序和希尔排序。

(一)插入排序

       

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

        空间复杂度:O(1)

        特点:元素越接近有序,插入排序的效率越高。

        稳定性:稳定

实现思路:

主要过程: 

        对于区间一个有序区间 [0,end] 将区间后的一个元素 nums[end+1] 插入到有序区间内。

由于nums[end+1]在移动元素时会被覆盖,需要一个临时变量tem暂时存储 nums[end+1],具体来说,将tem与nums[end]进行比较,如果

tem < nums[end]

则将end处的数据后移:

nums[end+1] = nums[end]

并将end--,继续比较。

如果

tem>=nums[end]

说明已经到达要插入的位置,直接break。

在出循环之后,将tem插入正确的位置即可:

nums[end+gap] = tem

整体实现注意事项:

        1.在实现过程中,可以先写内层循环,完成内层逻辑,再写外层循环。

        2.对于内层循环,进行循环的条件是 end>=0 ,由于外层循环end从0开始,如果内层进行循环的条件是end>0,那么如果end = 0,就无法进入循环。

        3.如何确定外层循环的区间?

        左区间从零开始;对于最大的区间,由于要将最后一个元素(size-1位置)插入到前面的区间 [0,size-2]内,所以end最大可取  size-2 。

        则区间为:

                [0,size-2](两闭区间)或者[0,size-1)(左闭右开区间)。

插入排序实现: 

#include<iostream>
#include<vector>
using namespace std;

void InsertSort(vector<int>& nums)
{
    //外层循环,end从0开始遍历
	for (int i = 0; i < nums.size()-1; i++)
	{
		//[0,end] end+1
		int end = i;
		int tem = nums[end + 1];
		//内层循环,end>=0时要进入循环
        while (end >= 0)
		{
			if (nums[end] > tem)
			{
				nums[end + 1] = nums[end];
				--end;
			}
			else
				break;
		}
		nums[end + 1] = tem;
	}
}
void Print(vector<int> v)
{
	for (const auto& e : v)
		cout << e << " ";
	cout << endl;
}
int main()
{
	vector<int> nums = { 55,9,8,6,7,59,75,89,12,50 };
	Print(nums);

	InsertSort(nums);
	Print(nums);
	return 0;
}

 


(二)希尔排序

        希尔排序简单来说就是对插入排序的优化,它与插入排序的整体思路是一致的。想要写好希尔排序,就必须要讲究一个层次感,你需要明白希尔排序的几层循环到底是在干什么


希尔排序的基本思想: 

分组:

        将数组中间距为gap的数据分为一组,如图所示:(gap == 3)

可以将一组数据分为gap组:

        我们将每一组数据看做是一个小组(group),对于每一个小组,想要将他们排序,自然需要移动,由于小组内部数据相距gap,所以移动的步幅也是gap。

希尔第一层次:

        也就是插入排序内层循环的逻辑,唯一不同的是将步幅从1改为gap。

实现的操作:

        将一个数据 nums[end+gap] 插入到已经有序的区间 [0,end] 内部,并在插入后使整个区间保持有序。

        由于nums[end+gap]在移动元素时会被覆盖,需要一个临时变量tem暂时存储 nums[end+gap],具体来说,将tem与nums[end]进行比较,如果

tem < nums[end]

则将end处的数据后移:

nums[end+gap] = nums[end]

并将end-=gap,继续比较。

如果

tem>=nums[end]

说明已经到达要插入的位置,直接break。

在出循环之后,将tem插入正确的位置即可:

nums[end+gap] = tem

实现参考:

int end;
int tem = nums[end + gap];
while (end >= 0)
{
	if (tem < nums[end])
	{
		nums[end + gap] = nums[end];
		end -= gap;
	}
	else
		break;
}
nums[end + gap] = tem;

 希尔第二层次:

        也就是插入排序外层循环的逻辑。

实现的操作:

        由于随着插入的进行,区间不断扩大,第二层次作用是不断改变区间的右端,和定位并保存需要插入的元素 nums[end+gap] 。

实现参考:

for (int i = 0; i < n - gap; i += gap)
{
	int end = i;
	int tem = nums[end + gap];
	while (end >= 0)
	{
		if (tem < nums[end])
		{
			nums[end + gap] = nums[end];
			end -= gap;
		}
		else
			break;
	}
	nums[end + gap] = tem;
}

希尔第三层次:

        前两层次实现了对一个group的排序,第三层就是要实现对所有group的排序。

实现的操作:

        外层创造循环变量j,对区间起点 i 制造偏移量:

for (int j = 0; j < gap; j++)
{
	for (int i = j; i < n - gap; i += gap)
	{
		int end = i;
		int tem = nums[end + gap];
		while (end >= 0)
		{
			if (tem < nums[end])
			{
				nums[end + gap] = nums[end];
				end -= gap;
			}
			else
				break;
		}
		nums[end + gap] = tem;
	}
}

 希尔第四层次:

        前三层次完成了对某一特定gap下的预排序。第四层次就是要通过gap来逐渐让数组接近有序。

        gap的意义是让数据跳动的步幅增大,不同的大小的gap拥有不同的效果:

        如果gap较大,数据跳动的步幅更大,数据的移动更快,但是更不容易接近有序。

        对于较小的gap,数据步幅减小,数据移动的较慢,但是更容易接近有序;当gap取可取得的最小值1时,整个排序逻辑就会退化为插入排序。

实现的操作:

        通过特定的策略逐渐减小gap。

        经过研究,gap每次除三效果最好,但是为了避免gap小于1,于是在每次除三后再加上1,这样就是一种gap的取值策略。


void ShellSort(vector<int>& nums)
{
	int n = nums.size();
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
        //....
	}
}

希尔排序的实现:


void ShellSort(vector<int>& nums)
{
	int n = nums.size();
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int j = 0; j < gap; j++)
		{
			for (int i = j; i < n - gap; i += gap)
			{
				int end = i;
				int tem = nums[end + gap];
				while (end >= 0)
				{
					if (tem < nums[end])
					{
						nums[end + gap] = nums[end];
						end -= gap;
					}
					else
						break;
				}
				nums[end + gap] = tem;
			}
		}
	}
}

完~

未经作者同意禁止转载

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

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

相关文章

数据结构(3.5)——队列的顺序实现

队列的顺序实现 #define MaxSize 10//定义队列中元素的最大个数 typedef struct {int data[MaxSize];//用静态数组存放队列元素int front, rear;//队头指针和队尾指针 } SqQueue;void testQueue() {SqQueue Q;//声明一个队列(顺序存储) } 队列的初始化操作和判空 //初始化队…

Vue异步操作发送AJAX请求

5. Vue异步操作 1 axios介绍 在Vue中发送异步请求&#xff0c;本质上还是AJAX。我们可以使用axios这个插件来简化操作&#xff01; 使用步骤 1.引入axios核心js文件。 2.调用axios对象的方法来发起异步请求。 3.调用axios对象的方法来处理响应的数据。 axios常用方法 代码…

centos执行yum相关命令报错的可能原因

文章目录 1. 执行yum命令是报下面一大帕拉2. 安装某个包报错&#xff0c;找不到这个包 1. 执行yum命令是报下面一大帕拉 最后一行报错&#xff0c;在repo文件中找不到空baseurl&#xff1a;xxx / x86_64 执行这行命令把这个找不到的 xxx 禁掉即可sudo yum-config-manager --di…

关于Unity粒子(2D序列帧粒子)的旋转、StartRotation值用脚本怎么动态设置

今天要用粒子做一个拖尾效果。由于对象的移动可以向任何方向&#xff0c;所以作为拖尾的粒子要根据方向做相应的旋转。 1.没有旋转的情况&#xff08;物体向下移动&#xff09;时&#xff0c;默认是下面这样的。 粒子发射器的形状是一个向上的长方形&#xff0c;粒子的移动方向…

[FreeRTOS 功能应用] 互斥量 功能应用

文章目录 一、基础知识点二、代码讲解三、结果演示四、代码下载 一、基础知识点 [FreeRTOS 基础知识] 互斥量 概念 [FreeRTOS 内部实现] 互斥量 本实验是基于STM32F103开发移植FreeRTOS实时操作系统&#xff0c;互斥量实战操作。 使用工具&#xff1a;Keil、串口工具 二、代码…

Android增量更新----java版

一、背景 开发过程中&#xff0c;随着apk包越来越大&#xff0c;全量更新会使得耗时&#xff0c;同时浪费流量&#xff0c;为了节省时间&#xff0c;使用增量更新解决。网上很多文章都不是很清楚&#xff0c;没有手把手教学&#xff0c;使得很多初学者&#xff0c;摸不着头脑&a…

【LabVIEW学习篇 - 2】:LabVIEW的编程特点

文章目录 LabVIEW的编程特点图形编程天然并行运行基于数据流运行 LabVIEW的编程特点 图形编程 LabVIEW使用图形化的图形化编程语言&#xff08;G语言&#xff09;&#xff0c;用户通过在程序框图中拖放和连接各种节点&#xff08;Nodes&#xff09;来编写程序。每个节点代表一…

C#Modbus通信

目录 1&#xff0c;辅助工具。 2&#xff0c;初识Modbus。 3&#xff0c;基于ModbusRTU的通信。 3.1&#xff0c;RTU与ASCII模式区别 3.2&#xff0c;Modbus存储区 3.3&#xff0c;报文格式 3.4&#xff0c;异常代码 3.5&#xff0c;详细文档连接 。 3.6&#xff0c;代…

mupdf加载PDF显示中文乱码

现象 加载PDF显示乱码,提示非嵌入字体 non-embedded font using identity encoding调式 在pdf-font.c中加载字体 调试源码发现pdf文档的字体名字居然是GBK&#xff0c;估计又是哪个windows下写的pdf生成工具生成pdf 字体方法&#xff1a; static pdf_font_desc * load_cid…

软通动力子公司鸿湖万联最新成果SwanLink AI亮相世界人工智能大会

7月4日&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海拉开帷幕&#xff0c;软通动力董事长兼首席执行官刘天文受邀出席开幕式。其间&#xff0c;软通动力携子公司鸿湖万联深度参与到大会各项活动中&#xff0c;并全面展…

详解AT_dp_l Deque(区间动态规划)

题目 思路 考虑模拟博弈过程。 题目可以看成:先手希望X - Y最大&#xff0c;后手希望X - Y最小。 显然游戏过程中剩下的数必然是连续的一段。设 dp[i,j]​ 表示剩下下标为 [i,j] 的数时&#xff0c;先手&#xff08;并非当前的先手而是开始时的先手&#xff0c;下同&#xf…

12 Dockerfile详解

目录 1. Dockerfile 2. Dockerfile构建过程 2.1. Dockerfile编写规则&#xff1a; 2.2. Docker执行Dockerfile的大致流程 2.3. 总结 3. Dockerfile指令 3.1. FROM 3.2. MAINTAINER 3.3. RUN 3.4. EXPOSE 3.5. WORKDIR 3.6. USER 3.7. ENV 3.8. VOLUME 3.9. ADD …

CVE-2023-30212(xss漏洞)

简介 OURPHP版本<7.2.0存在XSS漏洞&#xff0c;攻击路径为/client/manage/ourphp_out.php。 过程 打开靶场 访问攻击路径/client/manage/ourphp_out.php 得到flag{354c7c41-cc23-4de5-be73-79cbbf384aba}

Hasleo Backup Suite 一款专为Windows操作系统设计的免费数据备份与恢复软件,支持备份、恢复和克隆功能

数据安全是每位计算机用户都关心的重要问题。在日常使用中&#xff0c;我们经常面临文件丢失、系统崩溃或病毒感染等风险。为了解决这些问题&#xff0c;我们需要可靠且高效的数据备份与恢复工具。本文将介绍一款优秀的备份软件&#xff1a;Hasleo Backup Suite&#xff0c;它为…

Python数据分析案例49——基于机器学习的垃圾邮件分类系统构建(朴素贝叶斯,支持向量机)

案例背景 trec06c是非常经典的邮件分类的数据&#xff0c;还是难能可贵的中文数据集。 这个数据集从一堆txt压缩包里面提取出来整理为excel文件还真不容不易&#xff0c;肯定要做一下文本分类。 虽然现在文本分类基本都是深度学习了&#xff0c;但是传统的机器学习也能做。本案…

Python字符串处理常用的30种操作

我们平时编写代码时&#xff0c;经常需要对字符串进行处理&#xff0c;本文详细介绍Python处理字符串常用的30种操作&#xff0c;并给出了对应的代码。 分割 使用split()方法将字符串按照指定的分隔符进行分割。 s "Hello,World" result s.split(","…

解决分布式环境下session共享问题

在分布式环境下&#xff0c;session会存在两个问题 第一个问题:不同域名下&#xff0c;浏览器存储的jsessionid是没有存储的。比如登录时认证服务auth.gulimall.com存储了session&#xff0c;但是搜索服务search.gulimall.com是没有这个session的&#xff1b; 第二个问题&…

hdu物联网硬件实验2 GPIO亮灯

学院 班级 学号 姓名 日期 成绩 实验题目 GPIO亮灯 实验目的 点亮三个灯闪烁频率为一秒 硬件原理 无 关键代码及注释 const int ledPin1 GREEN_LED; // the number of the LED pin const int ledPin2 YELLOW_LED; const int ledPin3 RED…

E4.【C语言】练习:while和getchar的理解

#include <stdio.h> int main() {int ch 0;while ((ch getchar()) ! EOF){if (ch < 0 || ch>9)continue;putchar(ch);}return 0; } 理解上述代码 0-->48 9-->57 if行判断是否为数字&#xff0c;打印数字&#xff0c;不打印非数字

干冰运输与存储中的温度监测:确保药品安全与合规性

在制药行业&#xff0c;干冰对于运输和储存对温度敏感的药品&#xff0c;如原料药API、疫苗、冻干物质和人体组织样本等至关重要。虹科ELPRO LIBERO系列干冰温度记录仪&#xff0c;能够为您提供专业的解决方案&#xff0c;定期监测和记录干冰运输和存储过程中的温度&#xff0c…