【排序算法】二、希尔排序(C/C++)

news2024/11/15 20:32:06

「前言」文章内容是排序算法之希尔排序的讲解。(所有文章已经分类好,放心食用)

「归属专栏」排序算法

「主页链接」个人主页

「笔者」枫叶先生(fy)

目录

  • 希尔排序
    • 1.1 原理
    • 1.2 代码实现(C/C++)
    • 1.3 特性总结

希尔排序

1.1 原理

希尔排序是一种基于直接插入排序的排序算法,也称为“缩小增量排序”

希尔排序法的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序

希尔排序:基于数组(顺序表)的结构进行排序

希尔排序的由来

希尔排序是按其设计者希尔的名字命名的

他对普直接入排序的时间复杂度进行分析,得出了以下结论:

  1. 直接插入排序的时间复杂度最坏情况下为O(N^2),此时待排序列为逆序,或者说接近逆序
  2. 直接插入排序的时间复杂度最好情况下为O(N),此时待排序列为升序,或者说接近升序

于是希尔就想:若是能先将待排序列进行一次预排序,使待排序列接近有序(接近我们想要的顺序),然后再对该序列进行一次直接插入排序,此时已经排好序了,并且时间复杂度也降低了

希尔排序 = 预排序 + 一次直接插入排序

因为此时直接插入排序的时间复杂度为O(N)(直接插入排序对排序的数组接近有序的时候,时间复杂度为O(1)),那么只要控制预排序阶段的时间复杂度不超过O(^2),那么整体的时间复杂度就比直接插入排序的时间复杂度低了

希尔排序的步骤如下:

  1. 首先选择一个增量序列,通常选择增量序列gap为n/2,n/4,n/8...1,其中n为数组的长度
  2. 根据增量序列将数组分成若干个子序列,对每个子序列进行插入排序
  3. 逐渐缩小增量序列,重复步骤2,直到增量为1,即对整个数组进行一次插入排序

例如,对该数组使用希尔排序进行排序(升序)
在这里插入图片描述

取第一次增量gap为:gap = 10/2,10为数组大小,此时相隔距离为5的元素被分为一组(共分了5组,每组有2个元素),然后分别对每一组进行直接插入排序
在这里插入图片描述
取第二次增量gap为:gap = 5/2,5为第一次增量值,此时相隔距离为2的元素被分为一组(共分了2组,每组有5个元素),然后再分别对每一组进行直接插入排序
在这里插入图片描述
取第三次增量gap为:gap = 2/2,2为第二次增量值,此时gap为1,即整个序列被分为一组,进行一次直接插入排序(对整个数组)
在这里插入图片描述
动图演示如下:
在这里插入图片描述

为什么要让gap由大到小?

  • gap越大,数据挪动得越快;gap越小,数据挪动得越慢
  • 前期让gap较大,可以让数据更快得移动到自己对应的位置附近,减少挪动次数

:一般情况下,取序列的一半作为增量,然后依次减半,直到增量为1(也可自己设置)

希尔排序的时空复杂度

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在不同的书中给出的希尔排序的时间复杂度都不固定
在这里插入图片描述
在这里插入图片描述
Knuth序列是一种希尔排序中常用的增量序列,由Donald Knuth提出。Knuth序列的计算公式为:h = 3h + 1,其中h是增量序列的值,下面代码gap使用这个公式(有兴趣自己了解)

Knuth进行了大量的试验统计,暂时就按照:O(N^1.25)O(1.6 * N^1.25)来算,按O(N^1.3)计算(最好情况下)

  • 希尔排序时间复杂度O(N*logN) ~ O(N^2),以2为底,最好O(N^1.3),最坏 O(N^2)
  • 希尔排序空间复杂度O(1)

1.2 代码实现(C/C++)

C语言代码如下:(升序)

// 希尔排序(基于直接插入排序)
void ShellSort(int* arr, int n) // arr:需要排序的数组; n:数组的大小
{
	int gap = n;
	while (gap > 1)
	{
		// gap 大于 1, 进行预排序
		// gap == 1, 相当于直接插入排序(注:循环进来 gap 经过 gap = gap / 3 + 1 这才变成 1 )
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i; // 记录有序列的最后一个下标
			int tmp = arr[end + gap]; // 保存等待插入的值

			while (end >= 0)
			{
				if (arr[end] > tmp) // arr[end]比要插入的数大,向后移动
				{
					arr[end + gap] = arr[end]; // 向后移,进行覆盖,tmp已经保存被覆盖的值
					end -= gap;
				}
				else // arr[end]比要插入的数小,已有序,跳出循环
				{
					break; 
				}
			}
			arr[end + gap] = tmp; // 进行插入
		}
	}
}

C++代码:(升序)

// 希尔排序(基于直接插入排序)
void ShellSort(vector<int>& arr)
{
	int n = arr.size();
	int gap = n;
	while (gap > 1)
	{
		// gap 大于 1, 进行预排序
		// gap == 1, 相当于直接插入排序(注:循环进来 gap 经过 gap = gap / 3 + 1 这才变成 1 )
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i; // 记录有序列的最后一个下标
			int tmp = arr[end + gap]; // 保存等待插入的值

			while (end >= 0)
			{
				if (arr[end] > tmp) // arr[end]比要插入的数大,向后移动
				{
					arr[end + gap] = arr[end]; // 向后移,进行覆盖,tmp已经保存被覆盖的值
					end -= gap;
				}
				else // arr[end]比要插入的数小,已有序,跳出循环
				{
					break;
				}
			}
			arr[end + gap] = tmp; // 进行插入
		}
	}
}

1.3 特性总结

希尔排序的特性总结

  • 希尔排序是对直接插入排序的优化
  • gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。整体而言,可以达到优化的效果
  • 希尔排序时间复杂度O(N*logN) ~ O(N^2),以2为底
  • 空间复杂度O(1)
  • 稳定性:不稳定

--------------------- END ----------------------

「 作者 」 枫叶先生
「 更新 」 2024.1.9
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
          或有谬误或不准确之处,敬请读者批评指正。

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

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

相关文章

spring Security源码讲解-WebSecurityConfigurerAdapter

使用security我们最常见的代码&#xff1a; Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().permitAll();http.authorizeRequests().antMatcher…

【Python】DataFrame 使用 concat 横向拼接出现两行问题

问题 在使用 DataFrame 中 concat 横向拼接两个只有一行的 DataFrame 时&#xff0c;最终的结果有两行。 如下图&#xff1a; 原始的 df 分别为&#xff1a; 指定横向合并后是&#xff1a; 这里可以看到是横向拼接了&#xff0c;但是并没有真正意义的横向拼接&#xff0c;而…

AI数字人虚拟现实产业的发展现状与展望

AI数字人虚拟现实产业是当今科技领域备受瞩目的发展方向之一。随着人工智能和虚拟现实技术的迅猛发展&#xff0c;人们对于数字形象的需求不断增加&#xff0c;AI数字人虚拟现实产业正应运而生。本文将从产业现状和未来展望两个方面来描绘AI数字人虚拟现实产业的发展。 首先&a…

编程学习课前准备

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 浏览器和文本编辑器安装 数据分析三大软件安装 操作系统要求 查看Windows系统版本和位数 查看操作系统账户信息 Windows目录显式设置 命令行界面使用 打开命令行 方法一&#xff1a; 方法二&#xff1a; 方法…

MT6762芯片性能参数介绍_MTK联发科处理器

MT6762采用台积电 12 nm FinFET 制程工艺&#xff0c;8* Cortex-A53架构&#xff0c;搭载Android9.0/11.0/12.0操作系统&#xff0c;主频最高达2.0GHz&#xff0c;提供更高阶的功能和出色的体验。 搭载PowerVR GE8329 GPU&#xff0c;运行频率高达 650MHz&#xff0c;实现 20&a…

小游戏选型(一):游戏化设计助力直播间互动和营收

一、社交直播间小游戏火爆 大家好&#xff0c;作为一个技术宅和游戏迷&#xff0c;今天来聊聊近期爆火的社交直播间小游戏的潮流。喜欢冲浪玩社交产品的小伙伴会发现&#xff0c;近期各大平台都推出了直播间社交小游戏&#xff0c;直播间氛围火爆&#xff0c;小游戏玩法简单&a…

Java程序员面试-场景篇

前言 裁员增效潮滚滚而来&#xff0c;特总结一些实际场景方案的面试题&#xff0c;希望对大家找工作有一些帮助。 注册中心 题目&#xff1a; 有三台机器&#xff0c;分别部署了微服务A、微服务B、注册中心&#xff0c;其中A和B都有服务接口提供并正常注册到了注册中心&…

Halcon 模板匹配基于轮廓(形状)

文章目录 halcon 案例 基于缩放比halcon 案例 测单个剃须刀片Halcon 案例创建匹配模板Halcon 通过图像处理创建模型 ROI模型Halcon 亚像素识别Halcon 识别不等比例的图像Halcon 匹配包装袋案例Halcon 创建模板进行匹配Halcon 案例模板匹配与测量Halcon 多模板与多图像的匹配 ha…

CMake入门教程【核心篇】导入外部库Opencv

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 环境准备示例:在Windows上配置OpenCV路径示例:在Linux上配置OpenCV路径环境准备 首先确保你的系统中安装了CMake。可以通过以下命令安装: Windows: 下载并…

猴子选大王

思路&#xff1a;首先举个例子&#xff1a;当N 5 时 1 2 3 4 5 3 3 3 3 输出4 请观看代码 …

光纤知识总结

1光纤概念&#xff1a; 光导纤维&#xff08;英语&#xff1a;Optical fiber&#xff09;&#xff0c;简称光纤&#xff0c;是一种由玻璃或塑料制成的纤维&#xff0c;利用光在这些纤维中以全内反射原理传输的光传导工具。 微细的光纤封装在塑料护套中&#xff0c;使得它能够…

定时器中断控制的独立式键盘扫描实验

#include<reg51.h> //包含51单片机寄存器定义的头文件 sbit S1P1^4; //将S1位定义为P1.4引脚 sbit S2P1^5; //将S2位定义为P1.5引脚 sbit S3P1^6; //将S3位定义为P1.6引脚 sbit S4P1^7; //将S4位定义为P1.7引脚 unsigned char keyval; /…

在黑马程序员大学的2023年终总结

起笔 时间真快&#xff0c;转眼又是年末。是时候给2023做个年终总结了&#xff0c;为这一年的学习、生活以及成长画上一个圆满的句号。 这一年相比去年经历了很多事情&#xff0c;接下来我会一一说起 全文大概4000字&#xff0c;可能会占用你15分钟左右的时间 经历 先来给大…

Python学习之路-Hello Python

Python学习之路-Hello Python Python解释器 简介 前面说到Python是解释型语言&#xff0c;Python解释器的作用就是用于"翻译"Python程序。Python规定了一个Python语法规则&#xff0c;根据该规则可编写Python解释器。 常见的Python解释器 CPython&#xff1a;官方…

哈希-力扣01两数之和

题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺…

云仓酒庄的品牌雷盛红酒LEESON分享什么是“小农香槟”?

云仓酒庄的品牌雷盛红酒LEESON分享说起香槟&#xff0c;第一时间会想到法国&#xff0c;因为只有法国的起泡酒才能叫“香槟”。那么&#xff0c;什么又是“小农香槟”呢&#xff1f; 小农香槟是相对大厂香槟而命名的&#xff0c;是指葡萄果农自产、自酿、自销的香槟&#xff0…

TS中的类

目录 ES6的类 类的概念 类的构成 类的创建 声明 构造函数 定义内容 创建实例 TS中的类 类声明 构造函数 属性和方法 实例化类 继承 访问修饰符 public private protected 成员访问修饰符的使用原则 访问器 只读成员与静态成员 readonly static 修饰符总…

MySQL之导入导出远程备份

目录 一. navicat导入导出 二. mysqldump命令导入导出 导入 导出 三. load data infile命令导入导出 导入 导出 四. 远程备份 导入 导出 思维导图 一. navicat导入导出 导入&#xff1a;右键➡运行SQL文件 导出&#xff1a;选中要导出的表➡右键➡转储SQL文件➡数据和结…

【PB续命07】JDBC连接达梦数据库

JDBC(Java DataBase Connectivity) 称为Java数据库连接&#xff0c;它是一种用于数据库访问的应用程序API&#xff0c;由一组用Java语言编写的类和接口组成&#xff0c;有了JDBC就可以用同一的语法对多种关系数据库进行访问&#xff0c;而不用担心其数据库操作语言的差异。 有了…

基于Python的货币识别技术实现

目录 介绍本文的目的和意义货币识别技术的应用场景 货币识别的基本原理图像处理技术在货币识别中的应用特征提取方法&#xff1a;SIFT、HOG等支持向量机&#xff08;SVM&#xff09;分类器的使用 实现过程数据集的收集和预处理特征提取和训练分类器 参考文献 介绍 本文的目的和…