七种排序算法比较与选择[Python ]

七种排序算法比较与选择[Python ]

      • [1. 冒泡排序(Bubble Sort)](#1. 冒泡排序(Bubble Sort))
      • [2. 选择排序(Selection Sort)](#2. 选择排序(Selection Sort))
      • [3. 插入排序(Insertion Sort)](#3. 插入排序(Insertion Sort))
      • [4. 希尔排序(Shell Sort)](#4. 希尔排序(Shell Sort))
      • [5. 快速排序(Quick Sort)](#5. 快速排序(Quick Sort))
      • [6. 归并排序(Merge Sort)](#6. 归并排序(Merge Sort))
      • [7. 堆排序(Heap Sort)](#7. 堆排序(Heap Sort))
      • 总结

1. 冒泡排序(Bubble Sort)

原理 :重复遍历列表,每次比较相邻元素,若顺序错误则交换,直到没有元素需要交换(大元素像气泡一样"浮"到末尾)。
时间复杂度 :O(n²)(最坏/平均),O(n)(最好,已排序时)
空间复杂度:O(1)(原地排序)

python 复制代码
def bubble_sort(arr):
    # 获取列表长度,n为元素个数
    n = len(arr)
    # 外层循环:需要进行n-1轮比较(每轮确定一个最大元素的位置)
    for i in range(n - 1):
        # 标记本轮是否发生交换,初始为False(假设已排序)
        swapped = False
        # 内层循环:每轮比较到第n-1-i个元素(因为后面i个已排好序)
        for j in range(0, n - 1 - i):
            # 若当前元素大于下一个元素,交换它们
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                # 标记发生了交换
                swapped = True
        # 若本轮未发生交换,说明列表已排序,提前退出
        if not swapped:
            break
    # 返回排序后的列表(原地修改,也可省略返回)
    return arr

# 测试
print(bubble_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

2. 选择排序(Selection Sort)

原理 :每次从待排序部分找到最小(大)元素,放到已排序部分的末尾,直到全部排完。
时间复杂度 :O(n²)(所有情况)
空间复杂度:O(1)(原地排序)

python 复制代码
def selection_sort(arr):
    # 获取列表长度
    n = len(arr)
    # 外层循环:遍历到倒数第二个元素(最后一个自然有序)
    for i in range(n - 1):
        # 记录待排序部分中最小元素的索引,初始假设i位置为最小
        min_index = i
        # 内层循环:从i+1开始找比当前min_index更小的元素
        for j in range(i + 1, n):
            if arr[j] < arr[min_index]:
                # 更新最小元素索引
                min_index = j
        # 将找到的最小元素与i位置元素交换(放入已排序部分末尾)
        arr[i], arr[min_index] = arr[min_index], arr[i]
    return arr

# 测试
print(selection_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

3. 插入排序(Insertion Sort)

原理 :将列表分为"已排序"和"待排序"两部分,每次从待排序部分取一个元素,插入到已排序部分的正确位置(类似整理扑克牌)。
时间复杂度 :O(n²)(最坏/平均),O(n)(最好,已排序时)
空间复杂度:O(1)(原地排序)

python 复制代码
def insertion_sort(arr):
    # 获取列表长度
    n = len(arr)
    # 外层循环:从第二个元素开始(第一个元素默认已排序)
    for i in range(1, n):
        # 记录待插入的元素(当前元素)
        key = arr[i]
        # 内层循环:从已排序部分的末尾(i-1)向前比较
        j = i - 1
        # 若已排序元素大于key,将其向后移动一位
        while j >= 0 and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        # 将key插入到正确位置(j+1是插入索引)
        arr[j + 1] = key
    return arr

# 测试
print(insertion_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

4. 希尔排序(Shell Sort)

原理 :插入排序的改进版,通过"步长"将列表分组,对每组进行插入排序,逐步减小步长至1(最终退化为插入排序)。
时间复杂度 :O(n log n) ~ O(n²)(取决于步长选择)
空间复杂度:O(1)(原地排序)

python 复制代码
def shell_sort(arr):
    # 获取列表长度
    n = len(arr)
    # 初始化步长(通常从n//2开始,逐步减半)
    gap = n // 2
    # 当步长大于0时,持续分组排序
    while gap > 0:
        # 对每个分组进行插入排序(从gap位置开始遍历)
        for i in range(gap, n):
            # 记录当前分组中待插入的元素
            temp = arr[i]
            # 分组内的插入排序:与组内前一个元素比较
            j = i
            # 若组内前一个元素(j-gap)大于temp,向后移动
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            # 将temp插入到分组内的正确位置
            arr[j] = temp
        # 步长减半(逐渐缩小分组规模)
        gap //= 2
    return arr

# 测试
print(shell_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

5. 快速排序(Quick Sort)

原理 :分治法思想,选择一个"基准"元素,将列表分为"小于基准"和"大于基准"两部分,递归排序两部分。
时间复杂度 :O(n log n)(平均),O(n²)(最坏,如已排序时)
空间复杂度:O(log n) ~ O(n)(递归栈开销)

python 复制代码
def quick_sort(arr):
    # 辅助函数:实现分区操作(核心)
    def partition(low, high):
        # 选择最右侧元素作为基准
        pivot = arr[high]
        # i是"小于基准"区域的边界索引(初始为low-1)
        i = low - 1
        # 遍历low到high-1的元素
        for j in range(low, high):
            # 若当前元素小于等于基准,加入"小于基准"区域
            if arr[j] <= pivot:
                i += 1  # 扩展"小于基准"区域
                arr[i], arr[j] = arr[j], arr[i]  # 交换元素到区域内
        # 将基准元素放到"小于基准"区域的右侧(正确位置)
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        # 返回基准元素的索引(用于递归分割)
        return i + 1

    # 递归排序函数
    def _quick_sort(low, high):
        # 递归终止条件:low >= high时子列表长度为0或1
        if low < high:
            # 分区,获取基准元素的索引
            pi = partition(low, high)
            # 递归排序基准左侧子列表
            _quick_sort(low, pi - 1)
            # 递归排序基准右侧子列表
            _quick_sort(pi + 1, high)

    # 初始化递归(从0到n-1)
    _quick_sort(0, len(arr) - 1)
    return arr

# 测试
print(quick_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

6. 归并排序(Merge Sort)

原理 :分治法思想,将列表递归拆分为两个子列表,排序后合并为一个有序列表(核心是"合并"两个有序子列表)。
时间复杂度 :O(n log n)(所有情况)
空间复杂度:O(n)(需要额外空间存储临时列表)

python 复制代码
def merge_sort(arr):
    # 递归终止条件:列表长度小于等于1时无需排序
    if len(arr) <= 1:
        return arr
    # 拆分列表:找到中间索引
    mid = len(arr) // 2
    # 递归排序左半部分
    left = merge_sort(arr[:mid])
    # 递归排序右半部分
    right = merge_sort(arr[mid:])
    # 合并两个有序子列表
    return merge(left, right)

# 合并两个有序列表的辅助函数
def merge(left, right):
    # 结果列表(存储合并后的有序元素)
    result = []
    # i:left的索引,j:right的索引(初始都为0)
    i = j = 0
    # 比较两个列表的元素,较小的先加入结果
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    # 将left中剩余元素加入结果(若有)
    result.extend(left[i:])
    # 将right中剩余元素加入结果(若有)
    result.extend(right[j:])
    return result

# 测试
print(merge_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

7. 堆排序(Heap Sort)

原理 :利用"堆"(完全二叉树)的特性,先构建大顶堆(父节点 >= 子节点),再反复将堆顶(最大值)与末尾元素交换,调整剩余元素为大顶堆。
时间复杂度 :O(n log n)(所有情况)
空间复杂度:O(1)(原地排序)

python 复制代码
def heap_sort(arr):
    n = len(arr)

    # 构建大顶堆的辅助函数(调整以i为根的子树为大顶堆)
    def heapify(i, heap_size):
        # 初始化最大值索引为当前根节点i
        largest = i
        # 左子节点索引(2*i + 1)
        left = 2 * i + 1
        # 右子节点索引(2*i + 2)
        right = 2 * i + 2
        # 若左子节点存在且大于当前最大值,更新最大值索引
        if left < heap_size and arr[left] > arr[largest]:
            largest = left
        # 若右子节点存在且大于当前最大值,更新最大值索引
        if right < heap_size and arr[right] > arr[largest]:
            largest = right
        # 若最大值不是根节点,交换并递归调整子树
        if largest != i:
            arr[i], arr[largest] = arr[largest], arr[i]
            heapify(largest, heap_size)

    # 1. 构建初始大顶堆(从最后一个非叶子节点开始向前调整)
    for i in range(n // 2 - 1, -1, -1):
        heapify(i, n)

    # 2. 逐步提取堆顶元素(最大值)并调整堆
    for i in range(n - 1, 0, -1):
        # 将堆顶(最大值)与当前未排序部分的末尾元素交换
        arr[0], arr[i] = arr[i], arr[0]
        # 调整剩余元素为大顶堆(堆大小减1)
        heapify(0, i)

    return arr

# 测试
print(heap_sort([64, 34, 25, 12, 22, 11, 90]))  # 输出:[11, 12, 22, 25, 34, 64, 90]

总结

算法 时间复杂度(平均) 空间复杂度 稳定性 特点
冒泡排序 O(n²) O(1) 稳定 简单,适合小规模数据
选择排序 O(n²) O(1) 不稳定 交换次数少
插入排序 O(n²) O(1) 稳定 适合接近有序的数据
希尔排序 O(n log n) O(1) 不稳定 插入排序的高效改进版
快速排序 O(n log n) O(log n) 不稳定 实际应用中最快
归并排序 O(n log n) O(n) 稳定 适合大规模数据,可并行
堆排序 O(n log n) O(1) 不稳定 利用堆结构,无需额外空间

根据场景选择合适的算法:小规模数据用简单排序(如插入),大规模数据用快速/归并/堆排序,稳定性要求高则选归并排序。这条消息已经在编辑器中准备就绪。你想如何调整这篇文档?请随时告诉我。

相关推荐
秃头狂魔3 小时前
DAY1 数组一
算法
CM莫问3 小时前
推荐算法之粗排
深度学习·算法·机器学习·数据挖掘·排序算法·推荐算法·粗排
掘金者阿豪3 小时前
金仓数据库KingbaseES与MyBatis-Plus整合实践:电商系统开发实战
java·后端
rengang663 小时前
10-支持向量机(SVM):讲解基于最大间隔原则的分类算法
人工智能·算法·机器学习·支持向量机
消失的旧时光-19434 小时前
人脸跟随 ( Channel 实现(缓存5条数据 + 2度过滤 + 平滑移动))
android·java·开发语言·kotlin
默默coding的程序猿4 小时前
1.单例模式有哪几种常见的实现方式?
java·开发语言·spring boot·spring·单例模式·设计模式·idea
编程岁月4 小时前
java面试-0136-BIO、NIO、AIO区别?
java·面试·nio
春生野草4 小时前
部署项目到Tomcat
java·tomcat
安逸sgr4 小时前
SpringMVC启动流程
java·jvm·spring·spring cloud·eclipse·tomcat·maven