综合分析一下各个排序算法_插入排序算法及其变例分析

7f6df038dcd84a7763b3d48bbfea5393.png 说在前面

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

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

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

题目

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

7762eb2e1ac3f05eaf7725ca6ff40ffb.png

(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+1,a(i)就是要找的那个元素,故满足条件的同学数量为n-j或者n-i+1。

答案

(1)a(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的元素位置,i和j分别代表待查找区域的左右边界

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算法,感兴趣就一起来!

9cc29f14f3a4b127f5d752fa8c699229.png

相关优秀文章:

阅读代码和写更好的代码

最有效的学习方式

选考VB算法解析之2018年11月高考真题卷第16题

选考VB算法解析之2018年11月高考真题卷第17题

选考VB算法解析之2019年4月高考真题卷第16题

e67f0b332fb2b05c3122506ced0f927a.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值