Python中三种简单的基础排序算法(冒泡,选择,插入)

冒泡法排序

  • 冒泡法
    • 属于交换排序
    • 两两比较大小,交换位置。如同水泡咕嘟咕嘟往上冒
    • 结果分为升序和降序排序
  • 升序
    • n个数从左至右,编号从0开始到n-1,索引0和1的值比较,如果索引0大,则交换两者位置,如果索引1大,则不交换。继续比较索引1和2的值,将大值放在右侧。直至n-2和n-1比较完,第一轮比较完成。第二轮从索引0比较到 n-2,因为最右侧n-1位置上已经是最大值了。依次类推,每一轮都会减少最右侧的不参与比较,直至剩下最后2个数比较
  • 降序
    • 和升序相反
import random
lst = [random.randint(2,15) for i in range(10)]
print(lst)
#[3, 9, 14, 8, 10, 13, 15, 2, 13, 9]
length = len(lst)
for i in range(length):
    flag = False
    for j in range(length-i-1):
        if lst[j] > lst[j+1]:
            lst[j],lst[j+1] = lst[j+1],lst[j]
            flag = True
    if not flag:
        break

print(lst)
#[2, 3, 8, 9, 9, 10, 13, 13, 14, 15]

冒泡法总结

  • 冒泡法需要数据一轮轮比较
  • 可以设定一个标记判断此轮是否有数据交换发生,如果没有发生交换,可以结束排序,如果发生交换,继续下一轮排序
  • 最差的排序情况是,初始顺序与目标顺序完全相反,遍历次数1,……,n-1之和 n(n-1)/2
  • 最好的排序情况是,初始顺序与目标序完全相同,遍历次数 n-1
  • 时间复杂度 O(n^2)

简单选择排序

  • 简单选择排序
    • 属于选择排序
    • 两两比较大小,找出极值(极大值或极小值)被放置在固定的位置,这个固定位置一般指的是某一端
    • 结果分为升序和降序排列
  • 降序
    • n 个数从左至右,索引从 0 开始到 n-1 ,两两依次比较,记录大值索引,此轮所有数比较完毕,将大数和索引1位置交换,如果它就在索引1位置则不交换。依次类推,每次左边都会固定下一个大数
  • 升序
    • 和降序相反

  • 简单选择排序代码实现(一)
lst = [3, 9, 14, 8, 10, 13, 15, 2, 13, 9]
print(lst)
length = len(lst)
for i in range(length):
    maxindex = i
    for j in range(i+1 , length):
        if lst[j] > lst[maxindex]:
            maxindex = j
    if i != maxindex:
        lst[i],lst[maxindex] = lst[maxindex],lst[i]
        
print(lst)
#[3, 9, 14, 8, 10, 13, 15, 2, 13, 9]
#[15, 14, 13, 13, 10, 9, 9, 8, 3, 2]

  • 简单选择排序代码实现(二)
lst = [3, 9, 14, 8, 10, 13, 15, 2, 13, 9]
print(lst)
length = len(lst)
for i in range(length//2):
    maxindex = i
    minindex = -i-1
    minorigin = length + minindex
    for j in range(i+1 , length):
        if lst[j] > lst[maxindex]:
            maxindex = j
        if lst[-j-1] < lst[minindex]:
            minindex = -j-1
    else:
        minindex = length + minindex   
    if i != maxindex:
        lst[i],lst[maxindex] = lst[maxindex],lst[i]
        if i == minindex:
            minindex = maxindex
    if minindex != minorigin:
        lst[minorigin],lst[minindex] = lst[minindex],lst[minorigin]

print(lst)
#[3, 9, 14, 8, 10, 13, 15, 2, 13, 9]
#[15, 14, 13, 13, 10, 9, 9, 8, 3, 2]
  • 优化实现
    • 二元选择排序:同时固定左边最大值和右边最小值
    • 优点:减少迭代元素的次数
  1. length//2 整除,通过几次运算就可以发现规律
  2. 由于使用了负索引,为了计算方便,所以增加了转换为正索引

  • 简单选择排序代码实现(二)
lst = [1,1,1,1,1,1,1,1,1,1,1,1]
print(lst)
length = len(lst)
count_iter = 0
count_swap = 0
for i in range(length//2):
    maxindex = i
    minindex = -i-1
    minorigin = length + minindex
    for j in range(i+1 , length-1):
        count_iter += 1
        if lst[j] > lst[maxindex]:
            maxindex = j
        if lst[-j-1] < lst[minindex]:
            minindex = -j-1
    if lst[maxindex] == lst[minindex]:break
    minindex = length + minindex   
    if i != maxindex:
        lst[i],lst[maxindex] = lst[maxindex],lst[i]
        count_swap += 1
        if i == minindex:
            minindex = maxindex
    if minindex != minorigin:
        lst[minorigin],lst[minindex] = lst[minindex],lst[minorigin]
        count_swap += 1
        
        
print(lst,count_iter,count_swap)
#[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
#[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 10 0
  • 如果一轮比较后,极大值、极小值的值相等,说明比较的序列元素全部相等
  • 改进实现,[1,1,1,1,1,1,1,1,2,1,1,1] 这种情况,找到的最小索引是 -2 ,最大索引8,上面的代码会交换两次,最小值两个1交换是无用功,所以,增加一个判断
 lst = [1,1,1,1,1,1,1,1,2,1,1,1]
print(lst)
length = len(lst)
count_iter = 0
count_swap = 0
for i in range(length//2):
    maxindex = i
    minindex = -i-1
    minorigin = length + minindex
    for j in range(i+1 , length-1):
        count_iter += 1
        if lst[j] > lst[maxindex]:
            maxindex = j
        if lst[-j-1] < lst[minindex]:
            minindex = -j-1
    if lst[maxindex] == lst[minindex]:break
    minindex = length + minindex   
    if i != maxindex:
        lst[i],lst[maxindex] = lst[maxindex],lst[i]
        count_swap += 1
        if i == minindex:
            minindex = maxindex
    if minindex != minorigin and lst[minorigin] != lst[minindex]:
        lst[minorigin],lst[minindex] = lst[minindex],lst[minorigin]
        count_swap += 1
        
        
print(lst,count_iter,count_swap)
#[1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1]
#[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 19 1

简单选择排序总结

  • 简单选择排序需要数据一轮轮比较,并在每一轮中发现极值
  • 没有办法知道当前轮是否已经达到排序的要求,但是可以知道极值是否在目标索引位置上
  • 遍历次数 1,……,n-1之和n(n-1)/2
  • 时间复杂度 O(n^2)
  • 减少了交换次数,提高了效率,性能略好于冒泡法

直接插入排序

  • 直接插入排序原理
    • 在未排序序列中,构建一个子排序序列,直至全部数据排序完成
    • 将待排序的数,插入到已经排序的序列中合适的位置
    • 增加一个哨兵,放入待比较值,让它和后面已经排好序的序列比较,找到合适的插入点

  • 增加一个哨兵位,每趟将待比较数放入
  • 哨兵依次和待比较数的前一个数据比较,大数靠右移动,找到哨兵中值的插入位置
  • 每一轮结束后,得到一个从开始到待比较数位置的一个有序序列
lst = [9, 3, 14, 8, 10, 13, 15, 2, 13, 9]
lst = [0]+lst
print(lst)
length = len(lst)
for i in range(2,length):  
    lst[0] = lst[i]     
    j = i - 1                
    if lst[j] > lst[0]:   
        while lst[j] > lst[0]:
            lst[j+1] = lst[j]   
            j -= 1           
        lst[j+1] = lst[0]     
        
print(lst[1:])

  • 最好情况,正好是升序排序,比较迭代 n-1 次
  • 最差情况,正好是降序排列,比较迭代 1,2,……,n-1 即n(n-1)/2,数据移动非常多
  • 使用两层嵌套循环,时间复杂度O(n^2)
  • 稳定排序算法
    • 如果待排序序列R中两元素相等,即 Ri 等于 Rj ,且 i < j ,那么排序后这个先后顺序不变,这种排序算法就称为稳定排序
  • 使用在小规模数据比较
  • 优化,如果比较操作耗时大的话,可以采用二分查找来提高效率,即二分查找插入排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值