Python代码实现 冒泡 选择 插入 希尔 归并 快速 排序 (思想与注释)

本文深入解析了冒泡排序、插入排序、选择排序、Shell排序、归并排序、快速排序等经典排序算法的实现原理及时间复杂度分析。通过对比不同算法的特点,帮助读者理解其适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冒泡排序

思想 

两层循环 外层控制整体循环次数 内层循环每一次找出最大值或最小值 依次类推
def bubble_sort(li):
    for i in range(len(li)-1): #整个列表循环次数
        for j in range(len(li)-1-i): # 长度-1 - i此时是循环次数的下标 每次都减一
            if li[j] > li[j+1]: # 如果当前位置参数比后一个大就交换
                li[j],li[j+1] = li[j+1],li[j] # 交换
    return li

时间复杂度

  • 最优时间复杂度:O(n)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

插入排序

思想

插入排序 插曲排序的思想也是两层循环有两个游标 1和0比 如果小交换 依次类推 外层循环也是控制次数
def insert_sort(alist):
    # 从第二个位置,即下标为1的元素开始向前插入
    for i in range(1, len(alist)):
        # 从第i个元素开始向前比较,如果小于前一个元素,交换位置
        for j in range(i, 0, -1):
            if alist[j] < alist[j-1]:
                alist[j], alist[j-1] = alist[j-1], alist[j]

时间复杂度

  • 最优时间复杂度:O(n)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

选择排序

思想

 其实也差不多也是两层循环 内层循环找到最小值 然后与下标为0交换
def selection_sort(alist):
    n = len(alist)
    # 需要进行n-1次选择操作
    for i in range(n-1):
        # 记录最小位置
        min_index = i
        # 从i+1位置到末尾选择出最小数据
        for j in range(i+1, n):
            if alist[j] < alist[min_index]:
                min_index = j
        # 如果选择出的数据不在正确位置,进行交换
        if min_index != i:
            alist[i], alist[min_index] = alist[min_index], alist[i]

时间复杂度

  • 最优时间复杂度:O(n2)
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定

shell 排序

思想

其实就是插入排序的升级版 只是多了一个 gep 间隔值 据说用数学算到极致 时间复杂度O(n^1.3)次方

 

def shell_sort(li):
    # 先取出 gep值
    gep = len(li) // 2 # 取整除 python3 里需要// 2不需要

    # 控制gep 值
    while gep > 0:
    # 外层循环控制循环整体次数
        for i in range(gep,len(li)):
            # 此时gep循环就是+1+1+1
            while i > 0:
                if li[i] < li[i-gep]:
                    # 此时开始比较
                    li[i],li[i-gep] = li[i-gep],li[i]
                    i -= gep
                else:
                    break
        gep //= 2
    return li

时间复杂度

  • 最优时间复杂度:根据步长序列的不同而不同
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定

归并排序

思想

      就是先递归分解数组,再合并数组

 

def merge_sort(alist):
    if len(alist) <= 1:
        return alist
    # 二分分解
    num = len(alist)/2
    left = merge_sort(alist[:num])
    right = merge_sort(alist[num:])
    # 合并
    return merge(left,right)

def merge(left, right):
    '''合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组'''
    #left与right的下标指针
    l, r = 0, 0
    result = []
    while l<len(left) and r<len(right):
        if left[l] < right[r]:
            result.append(left[l])
            l += 1
        else:
            result.append(right[r])
            r += 1
    result += left[l:]
    result += right[r:]
    return result

时间复杂度

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(nlogn)
  • 稳定性:稳定

快速排序

思想 (标准的用性能换时间)

快速排序 两个游标 一个base == midvalue  开始游标和结束游标  右边游标向左移动 碰到 比mide小的 与
开始下标交换  开始下标 向右移动 遇到比 mide 大的 与 结束游标 交换 当 开始与结束 下标相遇 就是mide的位置
 现在mide 左侧 一定比mide小 右侧的比mide大  这时递归调用自己 两次 一次 用快排计算 左边的值
一次计算右边的值 但是切记不可使用切片(归并是切片)  因为要操作的是同一个列表

 

def quick_sort(alist,first,last):
    # 控制递归值
    if first >= last:
        return
    # 需要比较的值
    mid_value = alist[first]
    # 从左到又比较mid_value下标
    start_index = first
    # 从右到左
    end_index = last
    # 外层循环
    while start_index < end_index:
        # end_ndex向右移动 条件是 开始必须比结束小 and 每次移动的值比base大
        while start_index < end_index and alist[end_index] >= mid_value:
            # 每次向左移动 减一个下标
            end_index -= 1
        # 如果碰到条件不允许 赋值与 start
        alist[start_index] = alist[end_index]
        # start_inde 向左移动 条件同理
        while start_index < end_index and alist[start_index] < mid_value:
            # start 每次加一个下标
            start_index += 1
        # 交换值
        alist[end_index] = alist[start_index]
        # 直到 mid 左边是 都是比他小的 右边都是比他大的
    # 既然退出循环那就证明mid的位置值已经找到 看你开心 现在 start和end的值已经重合
    # 因为上面有多余常数已经交换
    alist[start_index] = mid_value

    # 现在左右两边已经分开 调用递归 分别完成快速排序
    # 有个坑 操作的是同一列表!!!!
    #
    # 递归左边列表
    quick_sort(alist,first,start_index-1) # alist first, start_inde-1

    # 递归右边列表
    quick_sort(alist,start_index+1,last) # alist  start_index+1 ,len(li)-1

时间复杂度

 

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值