二分查找和折半插入排序一块说说-很合适~~~

前言

上一篇在聊时间复杂度和空间复杂度时,没有按指定格式显示(明明预览的时候没问题的),强迫症的我稍微优化了一下重新发布,目的就是让小伙伴看着舒服。

上次聊到的直接插入排序在比较有序数据和待插入数据时,是通过依次遍历的方式进行比较,当数据量比较大时,得考虑进一步优化;折半插入排序就是通过减少有序数据与待插入数据的比较次数,从而提升效率。

正文

1. 先来熟悉一下折半查找

1.1  折半查找算法思想

折半查找又称二分查找,仅适用于有序的顺序表

思想(假设顺序表是升序的):

  • 首先将指定值与顺序表中中间位置元素进行比较;

  • 若相等,代表找到,则返回该元素的位置;

  • 若不等,需继续查找;

    若指定的值小于顺序表中中间元素,则查找前半部分;

    若指定的值大于顺序表中中间元素,则查找后半部分;

重复以上过程,直到找到元素为止;或者找完所有数据为止,即查找失败;

1.2 折半查找实现及解析

算法代码如下(在升序顺序表中查数据)

image-20210327174929319

执行结果如下:

image-20210327175057909

解析查找步骤过程,如下:

图中分别使用红、绿、黄箭头所指的数据分别高、中、低索引位,蓝色为需要在顺序表中查找的数。

能查到数据的步骤:

image-20210328000114746

上图步骤说明:

  • 第1步将low初始为0,high初始赋值为顺序表中的元素个数减1,这里为5;当循环进来时将mid赋值为(low+high)/2,因为mid为int类型,会取整,这里就得到mid为2;然后将索引位为2的数据66与需要查找的数据92进行比较,发现92大于66,需继续在后半部分查找,所以将low的值改为mid+1,即为3;

  • 第2步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为3,high的值不变,还是为5,所以得出的mid值为4,然后将索引位为4的数据92与需要查找的数据92进行比较,两者相等,代表已经找到,返回当时找到的位置mid。

查找失败时的情况:

image-20210328000247255

上图步骤说明:

  • 第1步将low初始为0,high初始赋值为顺序表中的元素个数减1,这里为5;当循环进来时将mid赋值为(low+high)/2,因为mid为int类型,会取整,这里就得到mid为2;然后将索引位为2的数据66与需要查找的数据921进行比较,发现921大于66,需继续在后半部分查找,所以将low的值改为mid+1,即为3;

  • 第2步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为3,high的值不变,还是为5,所以得出的mid值为4,然后将索引位为4的数据92与需要查找的数据921进行比较,发现921大于92,需继续在后半部分查找,所以将low的值改为mid+1,即为5;

  • 第3步进入循环,继续将mid的赋值为(low+high)/2,因为上一步low的值为5,high的值不变,还是为5,所以得出的mid值为5(这里高、中、低都指向同一位置),然后将索引位为5的数据100与需要查找的数据921进行比较,发现921大于100,需继续在后半部分查找,所以将low的值改为mid+1,即为6;

  • 第4步进入循环时,low在第3步时变为6,high还是没变,依然是5,low大于high,不满足循环条件,代表已经查询完成,但没有查询到数据,跳出循环,返回-1;

1.3 分析折半查找算法性能

时间复杂度

如果传入的数据规模为n,即有n个元素;第一次在 n/2个元素中查找,第二次在n/(22)个元素中查找,第三次在n/(23)个元素中查找,假如经过x次查找到元素,则得到时间复杂度为O(log2n);

空间复杂度

因为在查找过程中,用到了固定的几个中间变量(low,mid,high),所以算法过程中消耗的内存是一个常量级别的,则空间复杂度为O(1);

稳定性

由于在算法过程中只是查找,不改变元素的位置,则折半查找算法是稳定的。

综上所述,插入排序的时间复杂度为O(log2n),空间复杂度为O(1),是稳定算法;

2. 搞明白折半插入排序

2.1 折半插入排序算法思想

折半插入排序是对直接插入排序的优化,直接插入排序在比较过程中依次遍历有序列表中的元素和待插入数据比较,而折半插入排序是将原来的依次遍历有序列表换成折半查找算法,提升比较效率,找到合适位置之后,对应的元素需要向后移位,然后将待插入元素插入到腾出的空位即可;重复到排序完成为止。

2.2 折半插入排序算法实现与解析

代码实现(升序):

image-20210329104257982

运行效果如下:

image-20210329104425770

步骤解析如图:

image-20210329123521476

步骤说明:

图中绿线框部分代表是已经排好序的列表,箭头指的元素是下一个待插入的元素,黄线框部分为剩下的无序元素。黄方块为每次折半查找到的mid位置,绿方块表示最后有序列表腾出的位置。

  • 将原始数据array复制到新数组中arrayb中,这步的主要目的是后续不需要声明额外临时变量,也为了后续核心代码实现逻辑简单易懂,减少过多的判断;

  • 第1步将第一个元素作为有序列表(第一元素为2),下一个待插入的元素为5,将5放入哨兵位置,即索引为0的位置;然后折半查找,初始low为1,high为第一次也为1;因为刚开始有序列表中只有一个元素,则找到就是2,与哨兵位的值5比较,2小于5,需要继续在有序列表的后半部分查找,改变low为mid+1,此时为2,大于high,跳出循环;不需要移动位置,保持当前位置不变。

  • 第2步时,有序列表中的元素为2、5,下一个待插入的元素为6,将6放入哨兵位置,即索引为0的位置;然后折半查找:

    第2-1步 初始low为1,此时计算出high的值为2;根据low和high计算出mid为1(因为是mid是整数,所以3除以2,取整为1),将mid位的值2与待插入元素6比较,2小于6,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为2;

    第2-1步 上一步得到low为2,high的值仍然为2;根据low和high计算出mid为2,将mid位的值5与待插入元素6比较,5小于6,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为3;不满足循环条件,退出折半;不需要移动位置,保持当前位置不变;

  • 第3步时,有序列表中的元素为2、5、6,下一个待插入的元素为1,将1放入哨兵位置,即索引为0的位置;然后折半查找:

    第3-1步 初始low为1,此时计算出high的值为3;根据low和high计算出mid为2,将mid位的值5与待插入元素1比较,5大于1,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为1;

    第3-2步 初始low为1,上一步计算出high的值为1;根据low和high计算出mid为1,将mid位的值2与待插入元素1比较,2大于1,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为0;继续循环是low大于high,不满足条件,跳出循环;

    第3-3步 根据折半查找比较,得出合适位置为high+1,即需要将待插入元素插入到1位置,需要将2、5、6三个元素依次向后移位,腾出索引位1的位置,将待插入元素1插入到此索引位。

  • 第4步时,有序列表中的元素为1、2、5、6,下一个待插入的元素为9,将9放入哨兵位置,即索引为0的位置;然后折半查找:

    第4-1步 初始low为1,此时计算出high的值为4;根据low和high计算出mid为2(因为是mid是整数,所以5除以2,取整为2),将mid位的值2与待插入元素9比较,2小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为3;

    第4-2步 上一步计算出low为3,high的值仍然为4;根据low和high计算出mid为3(因为是mid是整数,所以7除以2,取整为3),将mid位的值5与待插入元素9比较,5小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为4;

    第4-3步 上一步计算出low为4,high的值仍然为4;根据low和high计算出mid为4,将mid位的值6与待插入元素9比较,6小于9,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid+1,得到low为5;继续循环是low大于high,不满足条件,跳出循环;

  • 第5步是,有序列表中的元素为1、2、5、6、9,下一个待插入的元素为3,将3放入哨兵位置,即索引为0的位置;然后折半查找:

    第5-1步 初始low为1,此时计算出high的值为5;根据low和high计算出mid为3,将mid位的值5与待插入元素3比较,5大于3,需要继续在有序列表中的前半部分继续查找,则改变high的值,为mid减1,得到high为2;

    第5-2步 初始low为1,上一步计算出high的值为2;根据low和high计算出mid为1(3除以2取整得1),将mid位的值1与待插入元素3比较,1小于3,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为2;

    第5-3步,上一步计算出low为2,第5-1步计算出high为2;根据low和high计算出mid为2,将mid位的值2与待插入元素3比较,2小于3,需要继续在有序列表中的后半部分继续查找,则改变low的值,为mid加1,得到low为3;继续循环,不符合循环条件,循环终止

    第5-4步 根据折半查找比较,得出合适位置为high+1,即需要将待插入元素插入到3位置,需要将5、6、9三个元素依次向后移位,腾出索引位3的位置,将待插入元素3插入到此索引位。最终得到排序结果1、2、3 、5 、6 、9;

2.3 折半插入排序算法分析

时间复杂度

在算法过程中有两层循环,第一层需要遍历所有元素,则时间复杂度为O(n);第二层循环中包含两部分算法,第一步是通过折半算法找位置,时间复杂度在刚开始已经分析,为O(log2n);第二步是找到位置之后需要腾出空位,需要将对应元素移位,时间复杂度为O(n);则整体算法的时间复杂度为外层循环的时间复杂度乘以内层循环的时间复杂度,去掉系数和常数,取大的,得出结果为O(n2);

空间复杂度

在算法核心部分只采用了固定的几个中间变量(i,j,low,mid,high,arrayb[0]),所以算法过程中消耗的内存是一个常量,则空间复杂度为O(1);

稳定性

由于在算法过程中采用折半算法找位置的,使用大于符号进行比较值,所以当遇到相等数据时,位置不会受到改变,则折半插入算法是稳定的。

综上所述,折半插入排序的时间复杂度为O(n2),空间复杂度为O(1),是稳定算法;

总结

这里说到两种算法,折半查找(二分查找)算法,折半插入排序算法;最终关于插入排序算法的思想没变,只是在比较有序列表时做了优化;对于小数据量的排序,感觉不到优化,当数据量大时,比较效率就明显提升啦;如果不明白的小伙伴调试代码试试,再不行可以留言,有时间会及时回复。

感谢小伙伴的:点赞收藏评论,下期继续~~~

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~

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

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

相关文章

用Python更加了解微信好友

用了微信几年了,微信号有也不少了,但是真正了解自己的好友吗?好友最多的城市是哪个?好友男女比例是多少?好友签名都是什么?今天我们来充分了解自己的微信好友。运行平台: Windows Python版本&a…

Linux下配置DNS

Linux下配置DNS一、配置环境1.Linux操作系统版本:RedHat AS 52.网络环境设置:IP:192.168.1.1 NetMark:255.255.255.0 Getway:192.168.1.13.软件包的准备:1)bind-9.3.3-7.el5.i386.rpm …

python用pandas提取行列_python- pandas 不删除符合条件的行和列

我正在尝试建立一个回归模型,以便根据出现的单词来预测收视率(1-5)(回归本身并不一定表现良好,更多的是关于所采用的方法).我使用以下代码创建了一个词频矩阵:bow df.Review2.str.split().apply(pd.Series.value_counts)看起来像这样:我现在有兴趣删除在…

中国宜坚持发展自主操作系统

一直以来,我国IT产业存在“缺芯少魂”的问题,芯指的是芯片,魂指的是操作系统。操作系统是连接硬件和应用软件的媒介和桥梁。如果无法在操作系统方面实现安全可控,整个信息安全就无从谈起,而恰恰当下国内桌面操作系统市…

老板啥都懂,还天天套路我?!

今天我被老板叫到办公室进行了一场“推心置腹”的对话▼来源:特大号文章版权归原作者所有,转载仅供学习使用,不用于任何商业用途,如有侵权请留言联系删除,感谢合作。

如何提高电脑办公效能

其实你只要花一点点的时间,就可以使你的生活变得更好。在电脑办公上,记忆几个快捷键、安装一些实用的软件等绝对会让你的效率翻倍! 在此弥缝分享几条我常常使用到的技巧和软件: 熟练一些快捷键 熟练的快捷键越多,做事越…

BeetleX.Http.Clients访问https服务

最近在做数据分析平台,那在做这个产品的时最需要的自然是测试数据,自己去构建行业测试数据比较麻烦,看到有同行产品的演示数据当然不能错过。由于采集过程中使用到BeetleX.Http.Clients去抓取第三方的Https接口数据,所以顺便记录一…

这一次,用数据解读玩家行为,用实力拿下预测大奖!

如今,大数据落地应用已十分广泛,除了政务、金融、医疗、旅游等传统行业外,在游戏行业中的应用也逐渐受人瞩目。那么,当大数据遇上游戏产业,会产生哪些变革和创新呢?众所周知,全球游戏市场规模庞…

如何在 C# 中使用隐式和显式操作符

C# 有一个鲜为人知的特性是通过定义 显式和隐式操作符 实现类型之间的转换,这篇文章我们将会讨论如何使用这些 显式 和 隐式 操作符。什么是显式,什么是隐式 隐式类型转换 它是运行时自动帮你完成的,言外之意就是你不需要人为干预&#xff0c…

SUSE10下配置FTP服务

SUSE10 liuux下配置FTP和SUSE9有不同之处,大家请注意。下面为SUSE10下ftp服务配置具体步骤。 Linux 系统安装完成后,默认不会开启FTP 服务,需要在yast界面下进行手动启动: 说明:如果未安装FTP 包,则需要先行安装FTP 软…

java gzip 解压文件_Java实现文件压缩与解压[zip格式,gzip格式]

原文:http://www.cnblogs.com/visec479/p/4112881.html#3069573Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例。zip扮演着归档和压缩两…

来看一场 AI 重建的 3D 全息世界杯比赛!

世界杯来了!央视名嘴白岩松调侃 “俄罗斯世界杯,中国除了足球队没去,其他的都去了”,这届世界杯,中国球迷购买球票的数量在所有国家中排名第 9,可见球迷对世界杯的热情。那么,除了准备好小龙虾在…

编译Linux 2.6内核

编译内核易如反掌。让人叹为观止的是,这实际上比编译和安装像glibc这样的系统级组伴还要简单。2.6内核提供了一套新工具,使编译内核更加容易,比早期发布的内核有了长足的进步。 2.3.1 配置内核 因为Linux源码随手可得,那就意味着在…

获取父线程 java_java子线程中获取父线程的threadLocal中的值

我们都知道线程本地变量表也就是ThreadLocal在我们做线程级的数据隔离时非常好用,但是有时候我们会想如何让子线程获取到父线程的ThreadLocal,其实在线程中除了ThreadLocal外还有InheritableThreadLocal,顾名思义,可继承的线程变量…

源码分享,送你一份Google Python class源码

几年前,Google推出Python课堂。Google Python课堂:https://developers.google.com/edu/python/小编也整理了一下Google Python课堂的源码,里面有四个例子。logpuzzle这个例子主要是利用urllib模块做一个图片拼接的小游戏,主要是从一大堆的网页里面解析分…

用YARP当网关

Yarp是微软开源的一个用.net实现的反向代理工具包,github库就叫reverse-proxy(反向代理)(吐槽一下微软起名字233333)nuget包preview9之前都叫Microsoft.ReverseProxy,preview10变成Yarp.ReverseProxy了放上…

从生物神经网络到人工神经网络

如今提及人工智能,大家期待的一定是某种可以“学习”的方法,这种方法使用数学模型从数据中获取模式的某种表示。在众多“学习”方法中,获得最多关注,承载最多期望的非“神经网络”莫属。既然我们将这种数学方法称作神经网络&#…

很遗憾,我们正在逐渐丧失专注阅读的能力

这是头哥侃码的第238篇原创最近生活没什么规律,睡得晚,起得早,似乎除了工作之外,其余所有的节奏都有点乱了。前几天去体检,没想到像我这样的 “老司机”,居然会忘记 “要空腹” 的规定,愣是在体…

陶哲轩的10岁与30岁

Terence Tao(陶哲轩),1975年7月17日出生于澳大利亚Adelaide(阿德莱德)。本讲话作于1985年上半年,即陶哲轩尚未满10周岁时所作,一个稚气儿童,给大学生和教授们作报告,少见…

NET问答: 重写了 Equals,还有必要重写 GetHashCode 吗?

咨询区 David Basarab:直入主题,参考如下代码:public class Foo {public int FooId { get; set; }public string FooName { get; set; }public override bool Equals(object obj){Foo fooItem obj as Foo;if (fooItem null) {return false;…