数据结构与算法基础(王卓)(31):折半插入排序、希尔排序

news2024/11/13 10:20:17

目录

折半插入排序

 Project 1:

问题:缺少在插入元素之前的移动元素的操作

Project 2:(最终成品、结果)

希尔排序

 Project 1:(个人思路)

标准答案:(PPT答案)

解释说明:(在程序实际执行的时候的算法运行逻辑顺序实际上和王卓老师网课中所讲的有所不同)

(1):赋值阶段

(2):第一轮【第一次】比较

 (3):第二轮到第(d)轮【第一次】比较

(4):第一轮到第(d)轮【第2次及其后续的】比较

重点来了:

至于如何调整先后进行比较时,不同的间隔大小d的问题,这里标准答案给出的方法是:

王道答案:

本土化


折半插入排序


直接根据实际实例、根据草图写出如下程序: 

 Project 1:

void BinsertSort(SqList& L)
{
    int i ,low = 1, high = i - 1;
    for (i = 1; i < L.length; i++)
    {
        if (L.r[i].key < L.r[i - 1].key)
            L.r[0] = L.r[i];
        //if可以放到最高优先级
        for (int mid = (low + high) / 2; high > low; mid = (low + high) / 2)
        {
            if (L.r[0].key < L.r[mid].key)
                high = mid - 1;
            else //if (L.r[0].key > L.r[mid].key)
                low = mid + 1;
        }
        L.r[high + 1].key = L.r[0].key;
        //L.r[low - 1].key = L.r[0].key;
    }
}

binary insert;
binary:二进制的; 仅基于两个数字的; 二元的; 由两部分组成的;

问题:缺少在插入元素之前的移动元素的操作


Project 2:(最终成品、结果)

void BinsertSort(SqList& L)
//binary insert;
//binary:二进制的; 仅基于两个数字的; 二元的; 由两部分组成的;
{
    int i;
    for (i = 1; i < L.length; i++)
        //i表示位序
    {
        if (L.r[i].key < L.r[i - 1].key)
            L.r[0] = L.r[i];
int low = 1, high = i - 1;
        for (int mid = (low + high) / 2; high > low; mid = (low + high) / 2)
        {
            if (L.r[0].key < L.r[mid].key)
                high = mid - 1;
            else //if (L.r[0].key > L.r[mid].key)
                low = mid + 1;
        }
        for (int j = i; j >= high + 1; j--)
            L.r[j + 1].key = L.r[j].key;

        L.r[high + 1].key = L.r[0].key;
        //L.r[low - 1].key = L.r[0].key;
    }
}

希尔排序

直接根据实际实例、根据草图写出如下程序: 

 Project 1:(个人思路)

void ShellSort(SqList& L) 
{
    for (int i = 0; i <= L.length / 5; i++)
    {
        for (int i = 0; i <= L.length; i += 5)
        {
            每次都把数据存储到中序二叉树,再用中序遍历把这些元素全部都重新插回去
        }
        递归...
    }
}

标准答案:(PPT答案)

void ShellInsert(SqList& L, int d)
//distance:每次一步往后跨多远(5,3,1...)
{
    int i, j;
    for (i = d + 1; i < L.length; i++) 
    {
        if (L.r[i].key < L.r[i - d].key) 
            //比较的诸多元素里,第二个元素大于第一个元素
        {
            L.r[0] = L.r[i];  
            for (j = i - d; //第一个元素
                j > 0 && (L.r[0].key < L.r[j].key);
                j -= d)
                L.r[j + d] = L.r[j];  //记录后移
            L.r[j + d] = L.r[0];  
        }
    }
}
void ShellSort(SqList& L, int dlta[], int t)
//t:循环总共趟数
{
    for (int k = 0; k < t; k++)
        ShellInsert(L, dlta[k]); 
    //dlta[k]:增量(5, 3, 1...)
}

解释说明:(在程序实际执行的时候的算法运行逻辑顺序实际上和王卓老师网课中所讲的有所不同)


(1):赋值阶段

i 的初值为每次比较的第二个元素

比较的诸多元素里,若第二个元素大于第一个元素:开始循环


(2):第一轮【第一次】比较

第一轮比较的第一次操作,只比较前面选中的两个元素而已:


比较第1个和第(d+1)个元素

  1. 把第二个元素放进哨兵
  2. 第一个元素覆盖第二个元素
  3. 再把第二个元素从哨兵里转移到第一个元素的位置

然后:j-=d;    =>     j<0


第一轮比较结束

实际上完整的这个分块的排序没有结束

但是由于实际上希尔排序和老师讲的算法思路有所偏差

所以,对于:我们把数据分成d份,共进行d轮排序的第一轮算法,就在这里先暂停终止了


然后(在第一轮的比较结束后),我们进行的操作并不是像王老师所说:

去找下一个分块筛选出的,第三个以及后续的其他元素进行比较和排序

而是暂时中止这个分块算法操作,去找我们存储在数据内部的第二个元素:


 (3):第二轮到第(d)轮【第一次】比较

比较:

第2个和第(d+2)个,第3个和第(d+3)个,第4个和第(d+4)个......

直到比较到第(d)轮:第d个和第(d*2)个

现在,我们已经拥有了前2d个分门别类排序好的元素序列:

前d个元素(k:位序)

分别小于

后面的第(d+k)位元素


(4):第一轮到第(d)轮【第2次及其后续的】比较

类似(2)、(3)比较的步骤,继续往后比较,直到后续元素全部都被比较完为止:

 但是,这个地方(第四步)里面:

在每次比较完【通过我们定义的序列规则(每隔d个为一组)区分开来的】

里面的最后两个元素以后

我们还进行一个超越(2)、(3)步骤的操作:

对每一组的序列前面的所有元素全部都重新进行一遍遍历

也就是说:

每一组队列序列在比较完最后两个元素以后,继续向前逐个比较

如果/但凡  比较时后面的元素小于前面的元素,就把后面的元素放到前面去


重点来了:

总共比较的数据范围不止两个了以后,在每一轮每一次的比较时:每次都

继续拿【比较后较小的元素】不断和【再前面的一个序列里的元素】进行比较

由 i 新指向的元素开始,把整个该组序列前面的元素全部都比较个遍


在这个过程中,我们就完成了“排序”操作的整个/所有的流程(过程):

逐个比较

把小的元素调换到前面的位置(碰到小的往前面移)

大的元素调换到后面的位置(碰到大的往后面挪)

 而在比较的数据范围不止两个了以后,每次对元素进行比较时

都把前面所有的元素都比较个遍(遍历个遍)的操作,很简单,在程序每次比较的循环里加一句:

一直向前面一个元素进行比较,直到本序列前面所有元素都被比较完毕为止

这样就完成了 :

            for (j = i - d; //第一个元素
                j > 0 && (L.r[0].key < L.r[j].key);
                j -= d)

这一段程序执行的for语句设计代码

是这整一个算法程序的运行流程的框架构建核心和精妙之处所在 


至于如何调整先后进行比较时,不同的间隔大小d的问题,这里标准答案给出的方法是:

每次通过某一规则dlta[ ]

(函数?还是什么???他这里也没有给出每次的对应关系,我TM也不知道他在搞的是个什么东西)来进行某种有规律性的变化:

    for (int k = 0; k < t; k++)//t:循环总共趟数
        ShellInsert(L, dlta[k]); 

我这里都被他整得(搞得)有点迷糊了,我也不知道他在搞什么东西


既然觉得他写的这个控制方法是一坨大便,那么我们不妨来看看这个每次都将所有数据二分的操作实例:

王道答案:

//希尔排序
void ShellSort(int A[], int n)
{
    int d, i, j;
    //A[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
    for (d = n / 2; d >= 1; d = d / 2)
        //步长变化
        for (i = d + 1; i <= n; ++i)
            if (A[i] < A[i - d])
                //需将A[i]插入有序增量子表
            {
                A[0] = A[i];
                //暂存在A[0]
                for (j = i - d; j > 0 && A[0] < A[j]; j -= d)
                    A[j + d] = A[j];
                //记录后移,查找插入的位置
                A[j + d] = A[0];
            }//if
}

根据我们设立的前置条件,按照要求进行修改:(将程序本土化)

本土化:

void ShellSort(SqList& L)
{
    int  i, j;
    for (int d = L.length / 2; d >= 1; d = d / 2)
        //步长变化

        for (i = d + 1; i <= L.length; ++i)
            if (L.r[i].key < L.r[i - d].key)
            {
                L.r[0] = L.r[i];
                for (j = i - d; j > 0 && L.r[0].key < L.r[j].key; j -= d)
                    L.r[j + d] = L.r[j];
                L.r[j + d] = L.r[0];
            }//if
}

这样看来,其实(实际上),程序用来控制每次不断比较的补偿d的程序,也只是需要一段:

    for (int d = L.length / 2; d >= 1; d = d / 2)

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

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

相关文章

etcd的Watch原理

在 Kubernetes 中&#xff0c;各种各样的控制器实现了 Deployment、StatefulSet、Job 等功能强大的 Workload。控制器的核心思想是监听、比较资源实际状态与期望状态是否一致&#xff0c;若不一致则进行协调工作&#xff0c;使其最终一致。 那么当你修改一个 Deployment 的镜像…

数据结构篇三:双向循环链表

文章目录 前言双向链表的结构功能的解析及实现1. 双向链表的创建2. 创建头节点&#xff08;初始化&#xff09;3. 创建新结点4. 尾插5. 尾删6. 头插7. 头删8. 查找9. 在pos位置前插入10. 删除pos位置的结点11. 销毁 代码实现1.ListNode.h2. ListNode.c3. test.c 总结 前言 前面…

03-WAF绕过-漏洞利用之注入上传跨站等绕过

WAF绕过-漏洞利用之注入上传跨站等绕过 思维导图 一、sql注入绕过 使用sqlmap注入测试绕过 1.绕过cc流量 通过sqlmap对网站进行测试的时候&#xff0c;如果对方有cc流量防护&#xff0c;需要给sqlmap设置一个代理进行注入。 防cc拦截&#xff1a;修改user-agent头代理&…

ADB调试删除手机内置应用

前言 最近手机升级到了鸿蒙3系统&#xff0c;但是内置了两个输入法&#xff0c;我想删掉小艺输入法&#xff0c;于是就有了这篇记录。   本文在B站上ADB调试卸载应用的教程的基础上&#xff0c;去掉了内网穿透相关操作步骤。 前期准备 手机&#xff08;荣耀10青春版&#x…

3.4 只读存储器

学习目标&#xff1a; 学习只读存储器&#xff08;ROM&#xff09;的目标可以包括以下内容&#xff1a; 了解ROM的基本概念、分类以及适用场景。掌握ROM的电路原理、逻辑结构和读取方式。熟悉ROM的编程方式和编程工具。理解ROM与EPROM、EEPROM和闪存的区别和联系。了解ROM在计…

IPsec中IKE与ISAKMP过程分析(快速模式-消息1)

IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息1&#xff09;_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息2&#xff09;_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息3&#xff09;_搞搞搞高傲的博客…

[架构之路-181]-《软考-系统分析师》-19- 系统可靠性分析与设计 - 概览

前言&#xff1a; 可靠性工程是研究产品生命周期中故障的发生、发展规律&#xff0c;达到预防故障&#xff0c;消灭故 障&#xff0c;提高产品可用性的工程技术。 信息系统的可靠性是指系统在满足一定条件的应用环境中能够正常工作的能力&#xff0c;可以按一般工程系统的可靠性…

图像生成论文阅读:GLIDE算法笔记

标题&#xff1a;GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models 会议&#xff1a;ICML2022 论文地址&#xff1a;https://proceedings.mlr.press/v162/nichol22a.html 官方代码&#xff1a;https://github.com/openai/glide-…

【算法】回文数

目录 一.回文数 二.求回文数&#xff08;10000以内&#xff09; 代码&#xff1a; 翻译&#xff1a; 调试&#xff1a; 三.判断回文数 代码&#xff1a; 调试&#xff1a; 一.回文数 "回文数"是一种数字。 如&#xff1a;12321, 这个数字正读是12321,倒读也是…

C++的类

文章目录 class定义类声明和定义不分离成员函数声明与定义的分离 类的访问限定符类的实例化类对象的大小this指针 引入&#xff1a;什么是类呢&#xff1f; 在C语言阶段,结构体成员只能是它的属性,这个结构体就相当于张三,小时候它只被赋予了名字,性别,家庭住址等属性,但是他没…

docker Mysql部署主从集群

目录 1 docker安装 2 docker mysql 安装配置 远程连接 2.0 配置 2.0.1 文件夹 配置 2.0.2 主库文件配置 my.cnf -> 主库 id 和 开启二进制日志 2.0.3 从库文件配置 -> 从库 id 2.1 mysql 主 -> 第一个端口号和从库不一样 2.1.1 docker run 主库 2.1.2 查看主…

Postman创建项目 对接口发起请求处理

查看本文之前 您需要理解了解 Postman 的几个简单工作区 如果还没有掌握 可以先查看我的文章 简单认识 Postman界面操作 那么 掌握之后 我们就可以正式来开启我们的接口测试 我们先选择 Collections 我们点上面这个加号 多拉一个项目出来 然后 我们选我们刚加号点出来的项目…

用LangChain构建大语言模型应用

用LangChain构建大语言模型应用 自 ChatGPT 发布以来&#xff0c;大型语言模型 (LLM) 广受欢迎。尽管您可能没有足够的资金和计算资源从头开始训练自己的大语言模型&#xff0c;但您仍然可以使用预训练的大语言模型来构建一些很酷的东西&#xff0c;例如&#xff1a; 可以根据…

01-权限提升-网站权限后台漏洞第三方获取

权限提升-网站权限后台漏洞第三方获取 本节课内容主要是权限提升的思路&#xff0c;不涉及技术 当前知识点在渗透流程中的点 前期-中期-后期对应知识关系 当前知识点在权限提升的重点 知识点顺序&#xff0c;理解思路&#xff0c;分类介绍等 当前知识点权限提升权限介绍 …

Java8

Java8 &#xff08;一&#xff09;、双列集合&#xff08;二&#xff09;、Map集合常用api&#xff08;三&#xff09;、Map集合的遍历方式&#xff08;四&#xff09;、HashMap&#xff08;五&#xff09;、LinkedHashMap&#xff08;六&#xff09;、TreeMap&#xff08;七&a…

Steve:AI创建视频和动画的在线工具

【产品介绍】 steve.ai是一款利用人工智能技术创建视频和动画的在线工具&#xff0c;可以让任何人在几分钟内把文字转换成吸引人的视频。核心功能是根据用户输入的文本&#xff0c;自动选择合适的素材、音乐、字幕和动效&#xff0c;生成高质量的视频。还提供了多种模板、风格和…

Photoshop如何使用滤镜之实例演示?

文章目录 0.引言1.将普通照片制作成油画效果2.使用液化滤镜修出完美身材3.用镜头光晕滤镜制作唯美的逆光人像4.用Camera Raw滤镜对偏色风景照进行调色 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程》及其…

Servlet 笔记

1. HTTP 协议 1.1 HTTP协议简介 超文本传输协议&#xff08;英文&#xff1a;HyperText Transfer Protocol&#xff0c;缩写&#xff1a;HTTP&#xff09;是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-…

etcd原理剖析一

为什么Kubernetes使用etcd&#xff1f; 首先我们来看服务高可用以及数据一致性。单副本存在单点故障&#xff0c;而多副本又引入数据一致性问题。 为了解决数据一致性问题&#xff0c;需要引入一个共识算法。例如Raft等。etcd选择了Raft&#xff0c;它将复杂的一致性问题分解…

Maven 笔记

1. Maven 的简介 1.1 简介 Maven 这个词可以翻译为"专家","内行"。作为Apache 组织中的一个开源项目&#xff0c;主要服务于基于java平台的项目构建&#xff0c;依赖管理和项目信息管理。 无论是小型的开源类库项目&#xff0c;还是大型的企业级应用&am…