插入排序算法及其变例分析

Posted Python算法之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了插入排序算法及其变例分析相关的知识,希望对你有一定的参考价值。

说在前面

本文源于“选考VB算法解析”知识星球一个老师的提问,她说她在做《2019学年第一学期浙南名校联盟第一次联考》第15题时感觉有点怪怪的,尤其是第一空,似乎有点问题,但是又不知道错在哪里。我仔细研究了一下题目,发现这位老师的直觉是很灵敏的,这里确实有一些问题。

本题考查的是插入排序算法的一个变例。插入排序算法在中隐隐出现过,其他各种模拟卷中也多次出现,因此很有必要对其进行深入研究,搞清楚它的基本模型、变例和优化途径,甚至连也有必要有所了解。


2019 学年第一学期浙南名校联盟第一次联考第15题解析(勘误前)

题目

15.小明学了排序和查找算法后,编写了一个处理成绩的程序。单击“获取成绩”按钮得到 n 个非降序数保存在数组 a(1)a(n)中,并显示在 List1 中。在文本框 Text1 中输入成绩 key,单击“查找”按钮,则在标签 label1 中显示共有多少位同学的成绩大于等于该成绩。

插入排序算法及其变例分析

1)加框1处的程序代码有错,应改为                      

2)请在划线处填入合适代码:

Dim a(1000) As Integer, n As Integer

Private Sub Command1_Click()

'从数据库获取 n 个成绩存储在 a(1)---a(n)组中,代码略

    For i = 2 To n  '排序

        tmp = a(i)

        j = 1

        Do While tmp > a(j)'勘误后改为tmp>=a(j)

            j = j + 1

            If      ①      Then Exit Do

        Loop

        For k = i To j + 1 Step -1

            a(k) = a(k - 1)

        Next k

  a(k-1) = tmp   '改错 1

    Next i

    For i = 1 To n

        List1.AddItem Str(a(i))

    Next i

End Sub

Private Sub Command2_Click()

    Dim key As Integer, i As Integer, j As Integer, m As Integer

    key = Val(Text1.Text)

    i = 1: j = n

    Do While i <= j

        m = (i + j) \ 2

 If     ②       Then

            j = m - 1

        Else

            i = m + 1

        End If

    Loop

    Label1.Caption = "共有" +     ③      + "位同学大于等于该成绩。"

End Sub

考查知识点

插入排序及其变例、对分查找算法。要求学生熟练掌握插入排序和对分查找算法的基本思想,并在经典算法的基础上理解其变例。

解析

本题是一道实用性很强的程序题,题目提供的代码总体来说是很精彩的,尤其是使用对分查找算法统计满足条件的同学数量,效率很高。遗憾的是出题老师对插入排序算法的改编不是很成功。

经典的插入排序算法是从右向左,边比较边移动元素,找到不大于tmp的元素后,在其右侧插入tmp,相关代码如下(算法1):

For i = 2 To n

        tmp = a(i): j = i - 1

        Do While tmp < a(j) 边比较边移动元素

            a(j + 1) = a(j): j = j - 1

            If j = 0 Then Exit Do

        Loop

        a(j + 1) = tmp

Next i

一个常见的变例是先向左扫描找到插入位置,再逐个右移元素,腾出插入位置,最后用tmp覆盖该元素,相关代码如下(算法2):

For i = 2 To n

        tmp = a(i): j = i - 1

        Do While tmp < a(j) 向左扫描寻找插入位置,最终j+1指向插入位置

            j = j - 1

            If j = 0 Then Exit Do

        Loop

        For k = i - 1 To j + 1 Step -1 逐个右移元素,腾出插入位置

            a(k + 1) = a(k)

        Next k

        a(k + 1) = tmp

Next i

向左扫描时,因为j有可能取到0,要考虑数组下标越界的问题,所以循环体中需要加入语句:If j = 0 Then Exit Do

本题也采用了先查找插入位置,再逐个右移元素,腾出插入位置的方法,与算法2的区别在于扫描方向不同,题目是从左向右扫描查找插入位置。因为tmp = a(i),故j最大取到i,无需考虑下标越界的情况。但出题老师由于思维惯性,还是给出了语句If j = i Then Exit Do,并将其作为问题的第一空,这显然不够妥当。

事实上当j=i时, Do While tmp > a(j)的循环条件不满足,不会执行循环体内的语句,所以第一空所在的语句纯属画蛇添足。我们可以写出更简洁的代码(算法3):

For i = 2 To n

        tmp = a(i): j = 1

        Do While tmp > a(j)向右扫描寻找插入位置,最终j指向插入位置

            j = j + 1

        Loop

        For k = i - 1 To j Step -1 逐个右移元素,腾出插入位置

            a(k + 1) = a(k)

        Next k

        a(k + 1) = tmp

Next i


本题使用For k = i To j + 1 Step -1循环来实现右移元素,腾出插入位置功能,当循环结束时,k=j,因为此时j指向插入位置,所以改错题的答案为:a(j) = tmp或者a(k) = tmp

本题中出现的对分查找算法也和经典的对分查找不一样,它不是查找与key值相等的元素位置,而是查找第一个不小于key值的元素位置,故当a(m)>=key时,需要修改右边界的值j=m-1。因为循环条件是i<= j,所以当循环结束时i=j+1a(i)就是要找的那个元素,故满足条件的同学数量为n-j或者n-i+1

答案

1a(k)=tmp 或者 a(j) = tmp  

2 j=i                

         a(m)>=key           

     ③  str(n-j)  或者 str(n-i+1)  
拓展思考
本题采用的对分查找算法相当巧妙,可以高效地找到第一个不小于key值的元素位置,这种思想也可以用在插入排序算法中,先对分查找到插入位置,再将元素右移,腾出插入位置。我们可以把这个算法写成一个函数的形式,那么在本题中就有2个地方可以调用该函数了。
相关代码如下,请将缺失处的代码补充完整:

Dim a(1000) As Integer, n As Integer

'对分查找返回第一个不小于key的元素位置,ij分别代表待查找区域的左右边界

Function BinarySearch(ByVal key As Integer, ByVal i As Integer, ByVal j As Integer) As Integer

    Dim m As Integer

    Do While i <= j

        m = (i + j) \ 2

        If a(m) >= key Then

            j = m - 1

        Else

            i = m + 1

        End If

    Loop

    BinarySearch =      ①     '返回第一个不小于key的元素位置

End Function


Private Sub Command3_Click()

    Dim i As Integer, j As Integer, k As Integer

    Dim tmp As Integer

    For i = 2 To n '插入排序

        tmp = a(i)

        j = BinarySearch(    ②            )

        For k = i To j + 1 Step -1

            a(k) = a(k - 1)

        Next k

        a(k) = tmp

    Next i

    For i = 1 To n

        List1.AddItem Str(a(i))

    Next i

End Sub


Private Sub Command4_Click()

    Dim i As Integer

    i = BinarySearch(Val(Text1.Text), 1, n)

    Label1.Caption = "共有" +     ③      + "位同学大于等于该成绩。"

End Sub

拓展思考答案

i   

tmp, 1, i - 1    

Str(n - i + 1)

写在后面

为了保证解析的原创性和思维的独特性,我都是独立解题后,先不看答案(除非题目不会做),直接把解析写好,再去看答案。

当然,如果发现参考答案有更好的思路,我还是很乐于学习和借鉴的。同时,由于本人水平有限,解析中难免出现疏漏甚至错误之处,敬请谅解。

无论是赞同还是反对我的看法,都请你给我留言。如果你有新的想法,千万不要憋在心里,请发出来大家一起讨论。让我们相互学习,共同进步!


需要本文word版的,可以加入“选考VB算法解析”知识星球参与讨论和下载文件,“选考VB算法解析”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注选考VB算法,感兴趣就一起来!



相关优秀文章:


以上是关于插入排序算法及其变例分析的主要内容,如果未能解决你的问题,请参考以下文章

插入排序的具体实现及其原理

希尔排序的具体实现及其原理

算法1 由插入排序看怎样分析和设计算法

详解数据结构八大排序(源码实现)(动图分析)

九大排序算法及其实现- 插入.冒泡.选择.归并.快速.堆排序.计数.基数.桶排序

算法与数据结构