常见排序算法性能对比

排序算法是计算机科学中将一个数据集合按照特定顺序(如升序或降序)重新排列的算法。根据是否通过比较元素来决定次序,主要分为比较排序非比较排序两大类 。

常见排序算法对比

下表对几种主流排序算法的核心特性进行了对比 :

算法名称 平均时间复杂度 最坏时间复杂度 空间复杂度 是否稳定 核心思想
冒泡排序 O(n²) O(n²) O(1) 稳定 重复遍历,依次比较相邻元素,将最大/小元素"冒泡"到末尾。
选择排序 O(n²) O(n²) O(1) 不稳定 每次从未排序部分选择最小(或最大)元素,放到已排序序列的末尾。
插入排序 O(n²) O(n²) O(1) 稳定 构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
希尔排序 O(n¹·³) O(n²) O(1) 不稳定 插入排序的改进,通过将数组按增量分组,对每组进行插入排序,逐步缩小增量至1。
归并排序 O(n log n) O(n log n) O(n) 稳定 分治法。将数组递归地分成两半分别排序,然后将两个有序子数组合并成一个有序数组 。
快速排序 O(n log n) O(n²) O(log n) 不稳定 分治法。选取一个基准,将数组分为小于基准和大于基准的两部分,递归地对这两部分排序。
堆排序 O(n log n) O(n log n) O(1) 不稳定 利用堆(一种完全二叉树)数据结构,将数组构建成大顶堆,然后重复将堆顶元素(最大)与末尾交换并调整堆。
计数排序 O(n + k) O(n + k) O(n + k) 稳定 非比较排序。适用于数据范围k不大的整数。统计每个值的出现次数,然后按顺序输出。
基数排序 O(d * (n + k)) O(d * (n + k)) O(n + k) 稳定 非比较排序。按位(个位、十位...)进行稳定排序(如计数排序),从低位到高位。

算法原理与代码实现

  1. 冒泡排序

每一轮遍历,比较相邻元素,如果顺序错误就交换,这样每一轮都会将当前未排序部分的最大值"冒泡"到正确位置 。

python 复制代码
def bubble_sort(arr):
    n = len(arr)
    for i in range(n - 1):          # 进行 n-1 轮比较
        swapped = False
        for j in range(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

# 示例
arr = [64, 34, 25, 12, 22, 11, 90]
print(bubble_sort(arr))  # 输出: [11, 12, 22, 25, 34, 64, 90]
  1. 选择排序

算法在未排序序列中找到最小元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小元素,放到已排序序列的末尾,以此类推 。

python 复制代码
def selection_sort(arr):
    n = len(arr)
    for i in range(n - 1):          # 进行 n-1 轮选择
        min_idx = i                  # 假设当前位置为最小值索引
        for j in range(i + 1, n):   # 在未排序部分寻找更小的值
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]  # 将找到的最小值与当前位置交换
    return arr

# 示例
arr = [64, 25, 12, 22, 11]
print(selection_sort(arr))  # 输出: [11, 12, 22, 25, 64]
  1. 插入排序

将数组视为已排序和未排序两部分。初始时,已排序部分只包含第一个元素。然后,依次将未排序部分的元素插入到已排序部分的正确位置 。

python 复制代码
def insertion_sort(arr):
    n = len(arr)
    for i in range(1, n):          # 从第二个元素开始,视为待插入元素
        key = arr[i]               # 当前待插入的元素
        j = i - 1
        # 将比 key 大的元素向后移动一位,为 key 腾出位置
        while j >= 0 and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key           # 将 key 插入到正确位置
    return arr

# 示例
arr = [12, 11, 13, 5, 6]
print(insertion_sort(arr))  # 输出: [5, 6, 11, 12, 13]
  1. 归并排序

采用分治法,将数组递归地分成两半,直到每个子数组只有一个元素(自然有序),然后将这些有序子数组合并起来 。

python 复制代码
def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    # 1. 分解:找到中间点,将数组分成两半
    mid = len(arr) // 2
    left_half = arr[:mid]
    right_half = arr[mid:]
    # 2. 解决:递归地对左右两半进行排序
    left_sorted = merge_sort(left_half)
    right_sorted = merge_sort(right_half)
    # 3. 合并:将两个有序数组合并成一个
    return merge(left_sorted, right_sorted)

def merge(left, right):
    result = []
    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
    # 将剩余元素追加到结果数组
    result.extend(left[i:])
    result.extend(right[j:])
    return result

# 示例
arr = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(arr))  # 输出: [3, 9, 10, 27, 38, 43, 82]
  1. 快速排序

选择一个元素作为"基准",将数组重新排列,所有比基准小的放在基准前面,比基准大的放在后面。然后递归地对基准前后的子数组进行快速排序 。

python 复制代码
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    # 选择中间元素作为基准
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    # 递归排序并合并
    return quick_sort(left) + middle + quick_sort(right)

# 示例
arr = [10, 7, 8, 9, 1, 5]
print(quick_sort(arr))  # 输出: [1, 5, 7, 8, 9, 10]

特殊排序算法:Stalin Sort

这是一种非标准的、带有讽刺意味的"高效"算法。其核心思想是:遍历数组,只保留那些不破坏非递减顺序的元素,而直接"移除"(忽略)任何比前一个保留元素小的元素,从而实现"排序" 。

python 复制代码
def stalin_sort(arr):
    if not arr:
        return []
    result = [arr[0]]  # 总是保留第一个元素
    max_so_far = arr[0]
    for i in range(1, len(arr)):
        if arr[i] >= max_so_far:  # 只有当前元素不小于当前最大值时才保留
            result.append(arr[i])
            max_so_far = arr[i]
        # 否则,该元素被"移除"(忽略)
    return result

# 示例
arr = [1, 2, 5, 3, 5, 7, 4, 9]
print(stalin_sort(arr))  # 输出: [1, 2, 5, 5, 7, 9]
# 注意:原数组中的 3 和 4 被移除了,结果序列是非递减的,但已不是原数组的完整集合。

算法选择与适用场景

  • 小规模或基本有序数据插入排序简单高效,是许多高级算法(如TimSort)在小规模数据上的 fallback 选择 。
  • 通用且高效的比较排序快速排序 在平均情况下性能极佳,是许多语言标准库的默认排序实现。归并排序稳定且时间复杂度稳定为 O(n log n),常用于需要稳定排序或链表排序的场景 。
  • 原地排序且对空间有严格要求堆排序能保证最坏情况下的 O(n log n) 时间复杂度,且只需要常数额外空间,适用于内存受限环境 。
  • 非比较排序 :当数据是有限范围内的整数时,计数排序基数排序可以在 O(n) 时间内完成排序,效率远超比较排序 。
  • 教学与理解冒泡排序选择排序因其思路直观,常被用于算法入门教学,但在实际应用中因其 O(n²) 的时间复杂度而较少使用 。

参考来源

相关推荐
Hello!!!!!!2 小时前
C++基础(十二)——标准库算法
c++·算法
minji...2 小时前
Linux 网络套接字编程(四)支持多客户端同时在线、消息能转发给所有人的 UDP 聊天室服务器
linux·运维·开发语言·网络·c++·算法·udp
灵感__idea9 小时前
Hello 算法:“走一步看一步”的智慧
前端·javascript·算法
lwf00616410 小时前
导数学习日记
学习·算法·机器学习
头发够用的程序员11 小时前
从滑动窗口到矩阵运算:img2col算法基本原理
人工智能·算法·yolo·性能优化·矩阵·边缘计算·jetson
武帝为此12 小时前
【数据清洗缺失值处理】
python·算法·数学建模
Halo_tjn12 小时前
Java 基于字符串相关知识点
java·开发语言·算法
念越12 小时前
算法每日一题 Day08|双指针法解决三数之和
算法·力扣
黎阳之光13 小时前
黎阳之光透明管理:视频孪生重构智慧仓储新范式
人工智能·算法·安全·重构·数字孪生