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

前言

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

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

正文

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综艺圈",跟我一起学~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容