【数据结构】希尔排序(最小增量排序)

news2024/10/6 6:42:11

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:数据结构
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵
希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、希尔排序的由来
  • 二、算法思路
  • 三、预排序代码实现
  • 四、如何选择gap
  • 五、代码实现(完整版)
  • 六、性能分析

一、希尔排序的由来

  • 从直接插入排序中,我们总结了:(假定要求升序)当原数组是逆序的时候,时间复杂度为O(N2),效率极低。博客地址:点击跳转
  • 当原数组是接近升序或者已经是有序的,那么时间复杂度就是O(N),此时效率最高。

因此,又一位名叫希尔的大佬发现,如果一开始就让数组内的元素接近有序的话,那插入排序的效率不就大大提升了吗?所以,希尔排序是插入排序的优化

二、算法思路

  1. 预排序首先让序列中的元素接近有序

那么如何进行预排序呢?(重点)

其运用了 分组插排 的思想:定义一个变量gap,间隔为gap分为一组进行插入排序

  1. 最后再对数组进行插入排序即可

【画图演示】

在这里插入图片描述

通过以上图片,我们还可以总结一个规律:gap为几,就代表预排序有几组

接下来我们简单实现预排序的代码。

三、预排序代码实现

void ShellSort(int a[], int n)
{
    // 假设gap为3
    int gap = 3;
    // 1. gap是几,就代表有几组
    for (int i = 0; i < gap; i++)
    {
        // 2. 间隔为gap为一组进行插入排序
        for (int j = i; j < n - gap; j += gap)
        {
        	// 下面基本都是插入排序的代码(类似)
            int end = j;
            int temp = a[j + gap];
            while (end >= 0)
            {
                if (temp < a[end])
                {
                    a[end + gap] = a[end];
                    end -= gap;
                }
                else
                {
                    a[end + gap] = temp;
                }
            }
            a[end + gap] = temp;
        }
    }
}

那么最后就要对整体进行插入排序,这样就能完美实现希尔排序了。但是我们难道还要重新再其后再手搓一个插入排序吗?理论上是可以的,但是没必要。注意看:当间隔gap1时,不就是插入排序了吗?因此,普通插入排序和gap是有关系的。那么应该如何选择gap呢?

四、如何选择gap

gap越大,跳的越快,越不接近有序;gap越小,跳的越慢,越接近有序。

可以为大家验证一下:

  • gap = 3

在这里插入图片描述

是不是越接近有序!

  • gap = 5

在这里插入图片描述

虽然也接近有序,但是没有比gap = 3更接近有序!

那么gap到底取多少合适呢?

解答:gap应该要不断在变化。为什么呢?开头的结论:gap越大,跳的越快,越不接近有序;gap越小,跳的越慢,越接近有序。如果gap是固定大小,给大了越不接近有序,给小了接近有序,但是跳的慢。因此,预排序的为了让更大的数更快的跳到后面,越小数越快跳到前面。这就是为什么gap应该要不断的变化。

  • 最初希尔大佬提出取gap /= 2,为什么呢?因为一个数不断/2,最后的结果一定为1,那么在上面我们说过,当gap = 1,就可以满足整体的插入排序,就不需要再手搓普通插入排序了。

  • 后来Knuth提出取gap = gap / 3 + 1+1为了保证最后gap一定为1,还有人提出取奇数好,也有人提出gap互质好。但无论哪一种主张都没有得到证明。其实都是ok的

五、代码实现(完整版)

void ShellSort(int a[], int n)
{
	// 3. 如何取gap
    // gap最大可以取到整个数组的长度n
    int gap = n;
    while (gap > 1)
    {
        // gap = gap / 3 + 1; // 这也是okk的
        gap /= 2;
        //  1. gap是几,就代表有几组
        for (int i = 0; i < gap; i++)
        {
            // 2. 间隔为gap为一组进行插入排序
            for (int j = i; j < n - gap; j += gap)
            {
                int end = j;
                int temp = a[j + gap];
                while (end >= 0)
                {
                    if (temp < a[end])
                    {
                        a[end + gap] = a[end];
                        end -= gap;
                    }
                    else
                    {
                        break;
                    }
                }
                a[end + gap] = temp;
            }
        }
    }
}

【结果展示】

在这里插入图片描述

六、性能分析

  • 时间复杂度

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算。Knuth大佬进行了大量的试验统计,计算出希尔排序的时间复杂度大约为O(N^1.3)

但是我们可以用代码进行性能测试的对比

在这里插入图片描述

如图,当数据个数是10w时,插入排序和希尔排序时间效率如下所示

在这里插入图片描述

由此看出,希尔排序还是非常的牛逼的~

  • 有人想:希尔排序在预排序的时候不是运用到很多的插入排序,为什么其效率还是比插入排序高?

原因是:其实gap的取值决定数组内的元素是否接近有序,gap越大,排的也越快,但越不接近有序;gap越小,排的也就越慢,但越接近有序。所以一开始gap的值可以设为数组元素个数(gap一定不可能超过数组元素个数),每次进行/2,不断缩小gap,其实最后发现,希尔排序的插入排序的次数其实是小于直接排序的插入次数的。

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

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

相关文章

【C++面向对象】11. 数据抽象*

文章目录 【 1. 访问标签强制抽象 】【 2. 设计策略 】 数据抽象 是指只向外界提供关键信息&#xff0c;并隐藏其后台的实现细节&#xff0c;即只表现必要的信息而不呈现细节。数据抽象是一种依赖于接口和实现分离的编程&#xff08;设计&#xff09;技术。数据抽象的好处&…

【面试经典150 | 位运算】数字范围按位与

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;公共前缀方法二&#xff1a;n & (n-1) 写在最后 Tag 【位运算】 题目来源 201. 数字范围按位与 题目解读 计算给定区间内所有整数的按位与的结果。 解题思路 本题朴素的方法是直接将区间内的所有整数按位与&…

FindMy技术定位身份证

身份证是我们日常生活中不可缺少的重要证件。无论是购买房产、车辆&#xff0c;还是乘坐飞机、火车、汽车等交通工具&#xff0c;甚至是办理银行业务等&#xff0c;都需要提供身份证原件。因此&#xff0c;身份证对于我们来说&#xff0c;其重要性不言而喻&#xff0c;一旦丢失…

Python如何使用Pyecharts+TextRank生成词云图?

Python如何使用PyechartsTextRank生成词云图&#xff1f; 1 应用场景2 关于Pyecharts2.1 Pyecharts简介2.2 Pyecharts安装2.3 Pyecharts支持的图形2.4 Pyecharts的一个示例 3 关于TextRank3.1 TextRank简介3.2 TextRank安装 4 词云图的生成过程4.1 导入需要的包4.2 目标文件4.3…

2023.11.16 hivesql之条件函数,case when then

目录 一.Conditional Functions条件函数 二.空值相关函数 三&#xff1a;使用注意事项 3.1 then后面不能接子查询 3.2 then后面只能是结果值 3.3 then后面能不能接两列 四.用于建表新增字段使用场景 一.Conditional Functions条件函数 -- 演示条件函数 -- if(条件判断,t…

【软考篇】中级软件设计师 第三部分(一)

中级软件设计师 第三部分&#xff08;一&#xff09; 十七. I/O管理软件十八. 输入/输出技术十九. 总线系统二十. 磁盘管理20.1 移臂调度算法20.2 缓冲区 二十一. 操作系统二十二. 数据库22.1 三级模式-两级映射22.2 数据库设计22.3 规范化理论22.4 范式判断22.5 模式分解 十七…

探索arkui(1)--- 布局(线性/层叠/弹性)

前端开发布局是指前端开发人员宣布他们开发的新网站或应用程序正式上线的活动。在前端开发布局中&#xff0c;开发人员通常会展示新网站或应用程序的设计、功能和用户体验&#xff0c;并向公众宣传新产品的特点和优势。前端开发布局通常是前端开发领域的重要事件&#xff0c;吸…

如何用SaleSmartly集成WhatsApp账号(内含WhatsApp个人号、商业号、API号对比图)

用SaleSmartly集成WhatsApp账号 如果企业有多个WhatsApp账号&#xff0c;无论是个人账号还是工作账号&#xff0c;员工操作起来可能会觉得难以管理和切换。SaleSmartly就可以解决这个问题&#xff0c;让员工在一个平台上同时使用多个WhatsApp账号&#xff0c;不需要频繁地登录和…

C++初阶,详解类和对象(2)

详解类和对象&#xff08;2&#xff09; 一&#xff0c;前言二&#xff0c;构造函数2.1构造函数概念2.2构造函数特性 三&#xff0c;析构函数3.1析构函数概念3.2析构函数特性 一&#xff0c;前言 上一篇我们讲了类的大体框架&#xff0c;这篇内容我们要重点来说一说类的几个默…

iis特殊字符的轉義問題解決

今天發現有個問題&#xff0c;部分圖片的靜態資源帶有號&#xff0c;導致無法直接在瀏覽器獲取圖片&#xff0c;百度了一下&#xff0c;修改了注冊表&#xff0c;發現沒什麽軟用&#xff0c;最後找到一篇博客&#xff0c;解決了 解決

k8s的error: metrics not available yet问题处理

kubectl top node报错处理 解决步骤环境说明问题现象初次排查问题解决版本兼容性metric-server.yaml 问题验证 解决步骤 因项目要求&#xff0c;需在k8s集群中使用 kubectl top node命令&#xff0c;但是一直报error: metrics not available yet错误。为了更好的复现问题&…

【知识增强】A Survey of Knowledge-Enhanced Pre-trained LM 论文笔记

A Survey of Knowledge-Enhanced Pre-trained Language Models Linmei Hu, Zeyi Liu, Ziwang Zhao, Lei Hou, Liqiang Nie, Senior Member, IEEE and Juanzi Li 2023年8月的一篇关于知识增强预训练模型的文献综述 论文思维导图 思维导图网页上看不清的话&#xff0c;可以存…

如果使用Vue要做根据已有的图形填入到指定的单元格中,你会怎么做?

这里写自定义目录标题 如果使用Vue要做根据已有的图形填入到指定的单元格中&#xff0c;你会怎么做&#xff1f;先看效果图上代码 如果使用Vue要做根据已有的图形填入到指定的单元格中&#xff0c;你会怎么做&#xff1f; 先看效果图 上代码 <template><div class&q…

算法--搜索与图

这里写目录标题 主要内容DFS思想 BFS思想 DFS与BFS的比较一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 主要内容 DFS 思想 会优先向深处搜索 一旦到达最深处 那么会回溯 但是在回溯的过程中 会边回溯边观察是否有能继…

Springboot项目返回数据统一封装

Springboot项目返回数据统一封装,支持swagger。 正常swagger会根据数据库表的注释显示对应的参数释义等。但当我们使用统一接口返回map时&#xff0c;部分注释等信息会被掩盖消失。在此提供三个java类即可满足统一封装返回接口&#xff0c;也可显示对应的swagger释义等。 1.Er…

Arthas应用诊断

一、介绍 rthas 是一款线上监控诊断产品&#xff0c;通过全局视角实时查看应用 load、内存、gc、线程的状态信息&#xff0c;并能在不修改应用代码的情况下&#xff0c;对业务问题进行诊断&#xff0c;包括查看方法调用的出入参、异常&#xff0c;监测方法执行耗时&#xff0c…

全数字系列-麦克风K歌模组-搭配投影仪专业方案

麦克风学名传声器&#xff0c;是将声音信号转换为电信号的能量转换器件&#xff0c;也称话筒、微音器&#xff1b;主要包括拾音面和信号放大电路&#xff1b;利用微机械加工技术制作出来的电能换声器&#xff0c;具有体积小、频响特性好、噪声低、高集成度和适于大批量生产的特…

每日一题----昂贵的婚礼

#include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <vector> using namespace std; //本题酋长的允诺也算一个物品,最后一定要交给酋长&#xff0c;那么等级不能超过酋长的等级范围const int N 150 * 15…

简单理解路由重分发(用两路由器来理解)

相关命令&#xff1a; default-information originate //*重分发默认路由 redistribute rip subnets //*重分发rip redistribute ospf 1 metric 3 //*重分发ospf&#xff08;其中&#xff1a;1是ospf进程id 3是跳数&#xff09; redistribute sta…

asp.net core mvc之 过滤器

过滤器允许我们在Action执行之前和执行之后去执行一下业务代码 一、过滤器的作用域 1、全局过滤器&#xff0c; 在Startup.cs文件中注册 2、控制器过滤器&#xff0c; 在控制器类上面使用标注 3、action过滤器 二、全局过滤器使用 1、在 core 目录&#xff0c;添加 TestA…