(排序2)希尔排序

写希尔排序注意:

  1. 写新元素融入有序数组的过程(end&tmp)
  2. 将这个过程给多次类比到需要排序的一串数据中 (for&while)
  3. 排完一组不够,需要排gap组 (再来for)
  4. 敲定gap
  5. 下标关系:在这里插入图片描述

希尔排序与直接插入排序的区别与联系

  1. 希尔排序的话也叫做缩小增量插入排序
  2. 他其实也是一种插入排序,只不过是在原先那种朴素的插入排序的基础之上给他优化了一下而已。
  3. 因为像之前就已经知道这个插入排序的话最坏的情况,时间复杂度为O(N^2),然后最好的情况的话,时间复杂度就是O(N)。这边就可以发现一个规律,就是说如果说你原先这个数组越接近顺序有序的话,插入排序就越快。然后希尔排序的话就是借助于这一点。他一上来的话不直接进行插入排序,而是先进行一下预排序。
  4. 怎么个预排序法呢?就是说分组插排。这个预排序的目的就是说先让这个数组尽可能的接近于顺序有序,这样子的话,等会儿下一步进行插入排序的话就会快不少。

预排序

  1. 预排序的话就是将总数据先按间隔(gap-1)被分成gap组。 (gap为1的时候其实就是直接插入排序)
  2. 关于这个“gap”里面蕴含的数量关系
    1. 被分成gap组。
    2. 每组的成员下表只要再加上gap就会跳到下一个同组成员(当然也是同一组的)。
    3. 在每组当中,成员与成员之间隔着gap-1个元素。
    在这里插入图片描述
  3. 然后对这个每一组进行单独的插入排序(此时每一组之间的元素都是不连续的,他们之间的间隔是gap-1)。
  4. 这样子预处理完了之后,整个数组看起来的话就会更加的接近于顺序有序。因为比如说我需要升序,然后最大的一个数在数组的开头,如果说按原先直接插入排序的话,这个最大的数是一步一步向后挪的。然后如果我进行这个预排序优化的话,它挪动的速度可以变得更加快,因为他现在一次的话挪动gap步(在预排序阶段)。
  5. 在最开始的话,还是把插入排序那个抽象出来的过程先给他代码写出来,但这边的话又与直接插入排序是有一定的区别的。道理还是一样的,这个end表示已经有序的数组的右边疆下标,然后这个tmp表示即将要插入到这个有序数组的数值
int gap;
int end;
int tmp ;
while (end >= 0)
{
	if (arr[end] > tmp)
	{
		arr[end + gap] = arr[end];
		end -= gap;
	}
	else
	{
		break;
	}
}
arr[end + gap] = tmp;
  1. 然后上面这段代码仅仅表示当有一个数据想要新融入到已经有序的数组当中的一个过程, 然后再把这个过程给多次类比到你需要排序的一串数据当中,于是代码如下:
int gap;
for (int i = 0; i < n - gap; i += gap)
{
	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;
}
  1. 然后之前不是提到在预处理阶段有分成了gap组数据嘛,上面的代码只是对一组数据进行了直接插入排序预处理,然后接下来就是把之前所有分好的gap组数据全部都直接插入排序一下:
int gap;
for (int j = 0; j < gap; j++)
{
	for (int i = j; i < n - gap; i += gap)
	{
		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;
	}
}

gap的确定与预排序完最终直接插入排序

  1. gap越大,相当于就是说他跳的越快,这样子的话就越不接近有序。但是也有好处,就是说如果大了的话,就可以尽快的向后跳。反之也一样。
  2. 那到底这个gap到底是取多少比较合适?实际上的话,这个gap的话在希尔排序当中也是在不断发生变化的,并不是定死的。
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap /= 2; //或者gap = gap/3 + 1;
		for (int j = 0; j < gap; j++)
		{
			for (int i = j; i < n - gap; i += gap)
			{
				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;
			}
		}
	}
}
  1. 注意看上面的while循环结束的条件,当这个gap>1的时候就进入到这个循环内部,然后注意看这个while循环里面的第一条语句,先把这个gap/2,这样子无论如何的话,最终必须有一次这个gap肯定是一(也就变成了直接插入排序)。当然也不一定需要,这样也可以把gap/3+1,为什么这边需要加上一呢?这是因为一定一定要在最后一次,在预排序完之后再进行一次直接插入排序,直接插入排序的话就相当于gap为1,因此在gap为1的情形下必须要去走一遭。但是当把这个gap除以三之后可能变成0了,为了确保他gap必须要有一个1, 所以说需要加1.

具体代码示例

void PrintArray(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap /= 2;
		for (int j = 0; j < gap; j++)
		{
			for (int i = j; i < n - gap; i += gap)
			{
				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;
			}
		}
	}
}


int main()
{
	int arr[] = { 1,2,5,3,6,7,9,1,2,4,0,9,3,2 ,12,88,32,10,9 };
	PrintArray(arr, sizeof(arr) / sizeof(int));
	ShellSort(arr, sizeof(arr) / sizeof(int));
	PrintArray(arr, sizeof(arr) / sizeof(int));
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

刷题笔记【3】| 快速刷完67道剑指offer(Java版)

本文已收录于专栏&#x1f33b;《刷题笔记》文章目录前言&#x1f3a8; 1、斐波那契数列题目描述思路一&#xff08;递归&#xff09;思路二&#xff08;循环&#xff09;&#x1f3a8; 2、跳台阶题目描述思路一&#xff08;递归&#xff09;思路二&#xff08;循环&#xff09…

03-03 周五 镜像安装sshd和jupyter以及修改密码

03-03 周五 镜像安装sshd和jupyter以及修改密码时间版本修改人描述2023年3月3日15:34:49V0.1宋全恒新建文档 简介 由于在镜像中需要进行jupyter和sshd的安装&#xff0c;并且需要进行密码的修改&#xff0c;因此在该文档中记录了这两个交互方式的工程设计。 在线加密 在线加密…

Pycharm创建自定义代码片段

简介 PyCharm允许您创建自定义代码片段&#xff0c;也称为代码模板&#xff0c;以提高您的开发效率 实现步骤 1.添加代码模板 打开PyCharm并导航到File->Settings&#xff0c;或者按快捷键ctrl alt s 打开设置 ​ 按照如下序号步骤进行点击&#xff0c;点击“”按钮以…

基于canvas画布的实用类Fabric.js的使用Part.3

目录一、基于canvas画布的实用类Fabric.js的使用Part.1Fabric.js简介 开始方法事件canvas常用属性对象属性图层层级操作复制和粘贴二、基于canvas画布的实用类Fabric.js的使用Part.2锁定拖拽和缩放画布分组动画图像滤镜渐变右键菜单删除三、基于canvas画布的实用类Fabric.js的使…

gcc在Linux下如何运行一个C/C++程序

安装gcc&#xff1a;sudo apt-get install gcc&#xff08;之后输入密码即可&#xff09; 绝对路径的方式进入usr目录&#xff1a; cd /home /home/&#xff1a;是普通用户的主目录&#xff0c;在创建用户时&#xff0c;每个用户要有一个默认登录和保存自己数据的位置&#x…

【数据结构刷题集】链表经典习题

&#x1f63d;PREFACE&#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐ 评论&#x1f4dd;&#x1f4e2;系列专栏&#xff1a;数据结构刷题集&#x1f50a;本专栏涉及到题目是数据结构专栏的补充与应用&#xff0c;只更新相关题目&#xff0c;旨在帮助提高代码熟练度&#x…

第14章_视图

第14章_视图 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某公司…

Python 自动化指南(繁琐工作自动化)第二版:六、字符串操作

原文&#xff1a;https://automatetheboringstuff.com/2e/chapter6/ 文本是程序将处理的最常见的数据形式之一。您已经知道如何用操作符将两个字符串值连接在一起&#xff0c;但是您可以做得更多。您可以从字符串值中提取部分字符串&#xff0c;添加或删除空格&#xff0c;将字…

【新2023Q2模拟题JAVA】华为OD机试 - 找数字 or 找等值元素

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:找数字 or 找等值元素 题目 …

华为OD机试 用java实现 -【重组字符串】

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:重组字符串 题目 给定一个非…

计算机网络 第一章 概述小结

计算机网络 第一章 概述 1.1 因特网概述 名词解释&#xff1a;因特网服务提供者ISP&#xff08;Internet Service Provider&#xff09; 1.2 三种交换方式 电路交换&#xff1a; 优点&#xff1a;通信时延小、有序传输、没有冲突、适用范围广、实时性强、控制简单&#x…

【美赛】2023年MCM问题Y:理解二手帆船价格(代码思路)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

新导则下的防洪评价报告编制方法及洪水建模实践技术

目录 1、《防洪评价报告编制导则解读河道管理范围内建设项目编制导则》&#xff08;SL/T808- 2021&#xff09;解读 2、防洪评价相关制度与解析 3、防洪评价地形获取及常用计算 4、HEC-RAS软件原理及特点 5、HEC-RAS地形导入 6、一维数学模型计算 7、基于数学模型软件的…

用 云GPU 云服务器训练数据集--yolov5

目录 为何使用云GPU训练我们数据集&#xff1f; 云服务器训练数据集教程&#xff1a; 1.创建实例 2.上传数据&#xff08;OSS命令&#xff09; 以下是oss的操作过程 训练模型时可能出现的报错&#xff1a; 为何使用云GPU训练我们数据集&#xff1f; 我们总是花费长达十几个…

ISO文件内添加kickstart完成自动安装

目录 将待制作的centos iso文件挂载到/mnt/目录 将/mnt/下的所有文件复制到新的目录/tmp/mycentos 创建kickstart文件 修改启动文件 重新制作ISO文件 制作完成 kickstart可以实现根据配置自动安装操作系统&#xff0c;本文主要讲解如何让机器读取到iso文件后自动完成操作…

vue尚品汇商城项目-day02【11.对axios二次封装+12.接口统一管理】

文章目录11.对axios二次封装11.1为什么需要进行二次封装axios&#xff1f;11.2在项目当中经常有API文件夹【axios】12.接口统一管理12.1跨域问题12.2接口统一管理12.3不同请求方式的src/api/index.js说明本人其他相关文章链接11.对axios二次封装 安装命令&#xff1a;cnpm inst…

移动端滑动(touch)选项并实现多选效果

移动端滑动选项实现多选效果通过 touchstart、touchmove、 touchend、touchcancel 事件实现通过父元素代理事件的方式实现子组件点击选中选项如果选项添加 disabled 属性将不会被选中移动端拖拽 .box 和 .options 元素时&#xff0c;是有拖拽效果的&#xff0c;去除拖拽效果有两…

文件操作-C语言实现图片、压缩包等文件的“复制粘贴“过程

大部分参考自&#xff1a; 文件操作-C语言实现图片的“复制粘贴“过程_一个图像一部分复制到另一个图像中c语言_philippe coutinho的博客-CSDN博客 #define _CRT_SECURE_NO_WARNINGS的作用参考&#xff1a; https://mp.csdn.net/mp_blog/creation/editor/new/129414996 首先我们…

线程池的优点

线程池的优点&#x1f50e;优点1(降低资源消耗)&#x1f50e;优点2(提高响应速度)&#x1f50e;优点3(可管理性)&#x1f50e;结尾&#x1f50e;优点1(降低资源消耗) 有了线程池后,创建线程不再是向系统申请,而是从线程池中拿 当线程不再使用后,再还给线程池 线程的创建,虽然相…

47了解公有云平台 GCP 的基本服务和使用方法,包括 Compute Engine、Cloud Storage

GCP Compute Engine Google Cloud Platform (GCP) 的 Compute Engine 是一个可扩展的云计算平台&#xff0c;可以让您快速启动虚拟机实例来运行您的应用程序。它提供了一种灵活的方式来管理您的计算资源&#xff0c;并支持多种操作系统、应用程序框架和开发工具。以下是一些基本…