当前位置: 首页 > article >正文

第15课 算法(下)

掌握冒泡排序、选择排序、插入排序、顺序查找、对分查找的的基本原理,并能使用这些算法编写简单的Python程序。

一、冒泡排序

1、冒泡排序的概念

冒泡排序是最简单的排序算法,是在一列数据中把较大(或较小)的数据逐次向右推移的一种排序技术。

冒泡排序过程容易理解,每一轮加工都是将本轮最大(或最小)的数据移动至右端。每个数如同水中的气泡一样,小的气泡上升,被排到最上面;大的气泡依次排在下面,这样的过程可以比喻成“冒泡”。

2、冒泡排序的基本思想(以升序为例)

依次比较相邻的两个数,将小数放在前面,大数放在后面。

第一轮从第1个元素开始,让它和第2个元素进行比较,若出现反序(大数在前,小数在后)则交换;然后让第2个元素与第3个元素进行比较,若出现反序则交换;依次类推,直到比较完最后一对元素为止。第一轮排序结束时,最后一个元素为所有元素中的最大值。

接下来进行第二轮比较。还是从第1个元素开始,让它和第2个元素比较,若出现反序则交换;然后让第2个元素和第3个元素进行比较,若出现反序则交换;依次类推,直到比较完最后一对元素(即倒数第二对数)为止。这样,倒数第二个数为第二大的数。

依次排序下去,n个数排序共需要进行n-1轮。

示例模拟:

5  8  4  3  7
5  8  4  3  7  将5和8比较,不交换位置
5  4  8  3  7  将8和4比较,交换位置
5  4  3  8  7  将8和3比较,交换位置
5  4  3  7  8  将8和7比较,交换位置,8被移至末尾

3、冒泡排序算法框架(伪代码)

冒泡排序采用双层嵌套循环来实现,外侧循环控制排序的轮数,内层循环控制排序元素下标的变化、以及数据对的比较。

for i (0 ~ n-1)       # 共进行n-1轮排序
    for j (0 ~ n-1-i) # 第i轮排序(次数)
        if 数据对反序,则:
            数据交换

4、冒泡排序程序的实现(升序)

a = [1, 3, 2, 5, 8, 7, 6]
count = len(a)
for i in range(0, count-1):
    for j in range(0, count-1-i):
        if a[j] > a[j+1]:
            a[j], a[j+1] = a[j+1], a[j]
print(a)

运行结果如下:

[1, 2, 3, 5, 6, 7, 8]

思考一下,若要将列表中的元素降序排列,应该如何修改程序?

是不是只需要将上述代码中的大于号改成小于号即可?

5、思考题

(1)某书店在5所学校的流动售书量(单位为本)分别是80、125、64、68、46。采用冒泡排序对其进行升序排列,完成第二轮时的结果是( )

(2)有一组原始数据:23、25、18、63、84、77、65、9、33、17。使用冒泡排序算法进行从小到大排序,最多需要进行( )轮加工,才可以完成整个数据的排序。

A、5 B、6 C、8 D、9

二、选择排序

1、选择排序的概念

选择排序算法是对冒泡排序算法的改进。

选择排序是在参加排序的所有元素中找出数值最小(或最大)的元素,如果它不是在左侧第一个元素,就让它和最左侧第一个元素互换位置;然后在余下的元素中找出数值最小(或最大)的元素,如果它不在左侧第二个元素,就让它和最测第二个元素叫唤位置;以此类推,直到所有元素成为一个有序的序列。

选择排序算法符合人们日常的排序习惯。

在对n个元素排序的时候,选择排序算法和冒泡排序算法的比较次数是相同的,但交换次数比冒泡排序要少,因此它具有更高的效率。

2、选择排序的基本思想

n个数排序共需要进行n-1轮。以从小到大排序为例:

第一轮,从第1个元素到第n个元素中找出一个最小的元素,如果它不是第1个元素,就让它和第1个元素交换位置。第一轮排序结束时,第1个元素就是最小的元素。

第二轮,从第2个元素到第n个元素中找出一个最小元素,如果它不是第2个元素,就让它和第2个元素交换位置。第二轮排序结束时,第2个元素就是第2小的元素。

以此类推,第i轮排序,中第i个元素到第n个元素中找出一个最小的元素,最小元素的索引记作k,如果最小元素不在第i位上,即k!=i,就把最小元素和第i个元素叫唤位置,即:序列[i], 序列[k] = 序列[k], 序列[i]。

直到只剩下最后一个元素,排序结束。最后一个元素就是最大的元素。

3、选择排序算法框架(伪代码)

选择排序算法同样采用双层嵌套循环来实现,外侧循环用来控制排序的轮数,内层循环用来控制排序元素的下标变化范围。每一轮排序过程中,都需要一个临时变量存储本轮排序中最小元素(或最大元素)的下标。

for i in (0 ~ n-1)      # 共进行n-1轮排序
    k = i
    for j in (i+1, n)   # 第i轮排序(次数)
        if 找到一个比k位置更小的元素,则:
            用k记录j的位置
    if i != k, 则:
        交换i和k位置上的数据

4、选择排序程序的实现(升序)

a = [3, 4, 1, 2, 0, 9, 10]
count = len(a)
for i in range(0, count-1):
    k = i
    for j in range(i+1, count):
        if a[k] > a[j]:
            k = j
    if k != i:
        a[k], a[i] = a[i], a[k]
print(a)

运行结果如下:

[0, 1, 2, 3, 4, 9, 10]

思考一下,如果按照降序排列,该如何修改程序?

体会变量k的用意。

与冒泡排序相比,选择排序的优劣是什么?

5、思考题

(1)用选择排序算法对一组学生的身高数据进行升序排序,已知第一轮排序结束后的数据序列为:166、169、177、175、172,则下列选项中可能是原始数据序列的是( )。

A、175、177、169、166、172
B、177、169、166、175、172
C、166、177、169、175、172
D、166、169、172、175、177

(2)某校要采购一套多媒体教学设备,有5个参考价位,分别如下:18万元、17万元、23万元、15万元、16万元。若采用选择排序算法对价格从高到低排序,需要进行数据交换的次数是( )。

A、1 B、3 C、4 D、5

(3)下列关于排序的说法,错误的是( )。

A、相对而言,选择排序算法的效率比冒泡排序算法的效率高

B、冒泡排序算法和选择排序算法都需要用到双循环结构

C、对于n个无序数据,不管是冒泡排序还是选择排序,都需要经过n-1轮加工

D、冒泡排序算法的程序实现一般要用到数组变量k,而选择排序则不需要

三、插入排序

1、插入排序的概念

插入排序算法过程如下:先将待排序数列中的第1个元素看成一个有序的子序列,然后从第2个元素起,将其依次(从小到大或从大到小)逐个插入这个有序的子序列中,以此类推到最后一个元素。这很像完扑克牌时一边抓牌一边理牌的过程,每抓到一张牌,就把它插到应处的位置。

2、插入排序的基本思想

先将列表中的前两个元素按顺序排列(以升序为例)。

然后,每次将下一个待排序元素,按其大小插入到前面已经排好顺序的序列中,使序列依旧有序,直到所有待排序元素全部插入完成。

3、实例演示

已知列表a=[5, 3, 5, 2, 8],对其升序排列。
在这里插入图片描述

第一轮插入(只要将第2个元素与第1个元素比较)

(1)先将待插入的元素a[1]暂存到变量key中;

(2)将key与前面已经排序好的元素比较,key<a[0]成立,说明key要插入到a[0]前面,将a[0]往后移一个位置,放到a[1]中;

(3)将key放入a[0]中。
在这里插入图片描述

第二轮插入(将第3个元素插入前面已排好的两个元素序列中)

(1)先将待插入的元素a[2]暂存到变量key中;

(2)将key与前面已经排好序的元素比较,key<a[1]不成立,说明key要插入到a[1]后面,即a[2]中;

(3)将key放入a[2]中。
在这里插入图片描述

第三轮插入(将第4个元素插入到前面已排好的三个元素序列中)

(1)先将待插入的元素a[3]暂存到变量key中;

(2)将key与前面已经排序序的序列比较,key<a[2]成立,说明key要插入到a[2]前面,将a[2]后移一位,放到a[3]中;

(3)再比较前一个元素,key<a[1]成立,说明key要插入到a[1]前面,将a[1]后移一位,放到a[2]中;

(4)再比较前一个元素,key<a[0]成立,说明key要插入到a[0]前面,将a[0]后移一位,放到a[0]中;

(5)将key放入a[0]中。
在这里插入图片描述

第四轮插入(将第5个元素插入到前面已排好的4个元素序列中)

与第二次插入类似,第个元素比a[3]大,应该插入到a[3]后面,即位置保持不变。至此,插入排序完成。

4、插入排序程序实现

示例程序(1)

a = [5, 3, 5, 2, 8]    # 初始化一个列表
for i in range(1, len(a)):    # 设定插入的轮数
    key = a[i]    # 将待排序元素暂存到变量key中
    j = i - 1    # 将待比较元素的索引存入变量j中
    while j >= 0 and a[j] > key:  # 元素比较
        a[j+1] = a[j]    # 将大元素往后移动
        j -= 1          # 更新待比较元素的索引
        a[j+1] = key    # 将待插入元素往前移动
print(a)              # 打印最终结果

运行结果:

[2, 3, 5, 5, 8]

示例程序(2)

a = [5, 3, 5, 2, 8]    # 初始化一个列表
for i in range(1, len(a)):    # 设定插入的轮数
    j = i -1    # 将待比较元素的索引存入变量j中
    while j >= 0 and a[j] > a[i]:  # 元素比较
        j -= 1
    if j == 0:  # 如果待插入元素最小,将其插入到最前面
        a.insert(0, a[i])
    else:  # 如果待插入元素不最小,将其插入到j+1索引前
        a.insert(j+1, a[i])
    a.pop(i+1)  # 最后将待插入的原始数据删除
print('a =, a')        # 打印最终结果

运行结果:

a = [2, 3, 5, 5, 8]

四、顺序查找

查找是程序和现实生活中经常用到的方法,也是一种查询数据的技术,其目标是以较少的步骤或在较短的时间内找到所需的数据。

这里主要掌握顺序查找和对分查找算法。

1、顺序查找的概念

假设要从n个元素中查找元素x是否存在,最原始的方法就是从头到尾依次查找,这种查找方法就是顺序查找。

顺序查找的基本思想是:从第一个元素开始,按顺序逐个将数据与给定的数据(查找键)进行比较,若某个元素与查找键相等,则查找成功,输出所查数据的位置;反之,输出未找到。

2、顺序查找的处理过程

假设列表a中有n个元素,查找键已经存在变量key中。

从列表a中的第1 哥元素a[0]开始,依次判断各元素的值是否与key相等,若某个元素a[i]的值等于key,则找到了指定的数据,对应的位置索引为i,停止程序;若找遍了所有的n个元素,没有一个元素的值等于key,输出未找到,停止程序。

3、顺序查找的程序实现

在列表中查找元素26。

lst = [32, 17, 56, 25, 26, 89, 65, 12]  # 初始化列表
key = 26    # 初始化要查找的元素
b = -1      # 要查找元素的索引
m = len(lst) # 列表长度
for i in range(0, m):
    if lst[i] == key:
        b = i
        break
if b == -1:    # -1 表示未找到
    print("要查找的元素 [" + str(key) + "] 不在列表lst中。")
else:
    print("要查找的元素 [" + str(key) + "] 的索引是:" + str(b))

4、思考题

(1)想一想,顺序查找与枚举算法的相似之处与不同之处。

(2)为查找课文第一次描写景色的自然段,小张同学打开课本依次阅读每一个自然段进行查找。这种查找方法为( )。

A、无序查找B、顺序查找C、对分查找D、随机查找

(3)在23、41、54、26、84、52、65、21中查找数字52,采用从后往前的顺序查找,需要查找的次数是( )。

A、2次B、3次C、7次D、1次

五、对分查找

如果在一堆无序的数列中查找某个数,可以使用顺序查找;如果在一个排好顺序的有序数列中查找某个数,除了顺序查找,你还有更快、更简洁的查找算法吗?

1、对分查找的概念

对分查找又称“二分查找”,是一种高效的查找方法。

对分查找的前提条件:被查找数据序列是有序的(升序或降序排列)。

对分查找的基本思想:首先将要查找的数据与有序数列内处于中间位置上的数据进行比较,如果两者相等,则查找成功;否则根据数据的有序性,再确定该数据的范围应该在数列的前半部分还是后半部分;在新确定的缩小范围内,继续按上述方法进行查找,直到找到要查询的数据,即查询成功;如果要查询的数据不存在,即查找失败。

2、对分查找的处理过程

若key为查找键,列表a存放n个已按升序排序好的元素。在使用对分查找时,把查找范围[i, j]的中间位置上的数据a[m]与key进行比较,结果必然有以下3中情况:

(1)若key<a[m],查找键key小于中间位置数据a[m]。由于列表a按升序排列,可以确定key的值应该在列表a的前半段,即在新范围(i, m-1)中继续查找。

(2)若key=a[m],查找成功。

(3)若key>a[m],查找键key大于中间位置数据a[m]。可以断定key应该在列表a的后半段,所以应该在新范围(m+1, j)中继续查找。

中间位置数据a[m]的下标m的计算方法如下:

m = (i+j)//2 或 m = int((i+j)/2)

3、对分查找的程序实现

(1)由于比较次数难以确定,所以用while语句实现循环。

(2)在while循环体中用if语句判断查找是否成功。

(3)若查找成功则输出查找结果,并用break语句结束循环。

(4)若查找不成功,则判断查找键在数组的前半段还是后半段,从而缩小范围,继续查找。

假设列表 lst = [12, 17, 23, 25, 26, 35, 47, 68, 76, 88, 96],要查找元素 key = 25, 使用对分查找程序如下:

# 初始化变量
lst = [12, 17, 23, 25, 26, 35, 47, 68, 76, 88, 96]
key = 25
n = len(lst)
# i为左边的索引号,j为右边的索引号
i, j = 0, n - 1
b = -1

# 执行查找操作
while i <= j:    # 只要i小于等于j,就继续查找
    m = (i + j) // 2    # 计算中间索引
    if key == lst[m]:  # 恰好找到目标元素
        b = m    # 将目标元素的索引赋值给b
        break    # 找到目标元素,停止查找
    elif key > lst[m]:  # 如果目标元素在列表后半段
        i = m +1    # 将左边的索引移到中间偏后一位
    else:    # 如果目标元素在前半段
        j = m -1    # 将右边的索引移到中间偏前一位
# 查找完成之后,根据索引b的值判断是否查找成功
if b == -1:    # -1 表示元素未找到
    print("要查找的元素 [" + str(key) + "] 不在列表lst中。")
else:
    print("要查找的元素 [" + str(key) + "] 的索引是:" + str(b))

4、对分查找的查找次数估算

对元素规模为n的列表进行对分查找时,无论是否找到,至多进行log2(n)次查找就能得到结果;而使用顺序查找算法,在最坏的情况下需要进行n次查找,在最好的情况下需要查找1次,平均查找次数为(n+1)/2。

5、思考题

(1)下列有关查找的说法,正确的是( )。

A、顺序查找时,被查找的数据必须有序

B、对分查找时,被查找的数据不一定有序

C、顺序查找总能找到要查找的关键字

D、一般情况下,对分查找的效率较高

(2)某列表有7个元素,依次为:19、28、30、35、39、42、48。若采用对分查找算法在该列表中查找元素48,需要查找的次数是( )。

A、1 B、2 C、3 D、4

六、模拟考题

(一)单选题:

1、编程大赛的成绩排名,可以采用的算法是( )。

A、解析算法B、枚举算法C、排序算法D、查找算法

2、对一组初始记录无序的数据:7、9、3、2、5,使用用选择排序算法,按照从小到大顺序排列,则第一轮排序的结果为( )。

A、7、 9、 2、 3、 5

B、2、 9、 3、 7、 5

C、2、 7、 9、 3、 5

D、2、 3、 5、 7、 9

3、L=[9, 2, 8, 6, 3, 4],采用选择排序进行升序排序,第二轮排序后的结果是( )。

A、[2, 3, 8, 6, 9, 4]

B、[2, 8, 3, 6, 4, 9]

C、[2, 6, 3, 4, 8, 9]

D、[2, 3, 4, 6, 8, 9]

4、设一组初始记录关键字序列为[5, 2, 6, 3, 7],利用插入排序算法进行升序排序,则第二次插入排序的结果为( )。

A、[5, 2, 3, 6, 7]

B、[2, 5, 3, 6, 7]

C、[2, 5, 6, 3, 7]

D、[2, 3, 5, 6, 7]

5、对于n个元素,利用顺序查找算法,最坏的情况需要查找( )次才结束。

A、n B、n / 2 C、n**2 D、log2(n+1)

6、对于n个元素,利用对分查找算法,最坏的情况是查找( )次才结束。

A、n B、n / 2 C、n**1 D、log2(n)

(二)编程题

1、在一列表中产生n(n>=10)个50以内的数据,删除其重复的数据并按照升序输出,同时输出删除数据的个数。

例如输入:n = 10

随机产生列表:a = [1, 2, 3, 7, 4, 7, 3, 8, 5, 7]

输出:a = [1, 2, 3, 4, 5, 7, 8]

输出:共删除数据为3个

请编写程序实现上述功能,或补全代码。

import random

maxn = int(input("请输入要产生的数据个数:"))
_____1_____
for i in range(maxn):
    a.append(random.randrange(1, 50, 1))
print("原始数据:", a)

key, n = 0, maxn
while key < n:
    i = n - 1
    while _____2_____ :
        i -= 1
    if i == key:
        key += 1
    else:
        a.remove( ____3____ )
        n -= 1

for i in range(n):
    for j in range(len(a)-1, i, -1):
        if a[j] < a[j-1]:
            a[j], a[j-1] = _____4_____

print("去重后排序数据:", a)
print("共删除数据:", ____5____ , "个")

2、对于列表对象a = [7, 4, 7, 3, 9],用插入排序算法进行升序排序,不分代码如下,请补全代码。

a = [7, 4, 7, 3, 9]  # 初始化列表
______1______
for i in range(1, count):
    key = ____2____
    j = i - 1
    while j >= 0 and a[j] > key:
        a[j+1] = a[j]
        _____3_____
        a[j+1] = key
print(a)

3、科技小组分两个小队搜集西红柿生长的数据信息。两个小队都将数据进行了从小大大排序:a = [1, 3, 4, 6, 7, 13, 17, 21],b = [2, 5, 6, 8, 10, 12, 14, 16, 18]。请将这两个小队的数据进行合并,生成一个从小到大排列的有序列表。

输入:

1,3,4,6,7,13,17,21
2,5,6,8,10,12,14,16,18

输出:

[1, 2, 3, 4, 5, 6, 6, 7, 8, 10, 12, 13, 14, 16, 17, 18, 21]

请编写程序实现上述功能,或补全代码。

x = input()
s = x.split(',')
a = []
for i in range(_____1_____):
    a.append(int(s[i]))

y = input()
s = y._____2_____
b = []
for i in range(len(s)):
    b.append(int(s[i]))

ret = []
i = j = 0
while len(a) >= i + 1 and _____3_____:
    if a[i] <= b[j]:
        _____4_____
        i += 1
    else:
        ret.append(b[j])
        j += 1

if len(a) > i:
    ret += a[i:]
if len(b) > j:
    _____5_____

print(ret)

–>参考答案往下翻<–





























–>参考答案<–

一、单选题:

1~6:C、B、A、D、A、D

二、编程题:

1、参考答案:

(1)a = []

(2)a[i] != a[key]

(3)a[i]

(4)a[j-1], a[j]

(5)maxn - n

2、参考答案:

(1)count = len(a)

(2)a[i]

(3)j -= 1

3、参考答案:

(1)len(s)

(2)split(‘,’)

(3)len(b) >= j + 1

(4)ret.append(a[i])

(5)ret += b[j:]


http://www.kler.cn/a/374832.html

相关文章:

  • 工业摄像机基于电荷耦合器件的相机
  • 汽车IVI中控开发入门及进阶(四十):FDK AAC音频编解码软件库
  • NavMeshAgent直接transform.position移动报错
  • 2.Couchbase 的增量查询优化
  • set的使用
  • Android 代码模式的理解
  • 使用 Cloudreve 搭建你的专属个人网盘
  • 分布式 ID 生成策略(一)
  • 如何提高社媒品牌知名度,3个增加曝光的实操方法
  • 微信小程序服务通知
  • 【HarmonyOS NEXT】在 HarmonyOS NEXT 中实现优雅的加载动画
  • python 五子棋小游戏
  • GIN 反向代理功能
  • C/C++ 每日一练:二叉树的先序遍历
  • Webserver(2.6)信号
  • 信号完整性SI总结【小登培训】
  • OpenCV基础知识
  • DB-GPT系列(二):DB-GPT部署(镜像一键部署、源码部署)
  • C++ 代码工程化
  • 微信小程序,打开新的项目,调试遇见[ app.json 文件内容错误] app.json: 在项目根目录未找到 app.json
  • 【行业应用-工业防爆】本安型工业防爆网关,实现安全高效的数据传输与监控
  • 如何解决docker镜像下载失败问题
  • nfs作业
  • Docker | 容器数据卷在docker中的角色:持久化存储
  • WebSocket简单使用
  • Python实现图像(边缘)锐化:梯度锐化、Roberts 算子、Laplace算子、Sobel算子的详细方法