排序算法(冒泡、选择、插入、快速、归并、计数、基数、桶)

一、冒泡排序

 核心思想

  • 依次比较相邻的两个元素,将较大的元素“冒泡”到序列末端。

  • 每一趟遍历,都会把当前未排序部分的最大元素放到该区域的尾。

  • 稳定(相等元素不会改变相对次序)

伪代码 

function bubbleSort(A[0..n-1]):
    for i from 0 to n-2:
        swapped = false                     // 标记本趟是否发生过交换
        for j from 0 to n-2-i:
            if A[j] > A[j+1]:
                swap A[j], A[j+1]
                swapped = true              // 只要有一次交换,就标记为 true
        if not swapped:                     // 如果本趟没有任何交换,说明已完全有序
            break                           // 提前结束排序
    return A

python实现 

def bubble(arr):
    l = len(arr)
    for i in range(l-1):
        sawp = False
        for j in range(l-1-i):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
                sawp = True
        if sawp == False:
            break
    return arr

lst = [5, 2, 9, 1, 5]
print("排序后:", bubble(lst))

过程演示:

以序列 [5,2,9,1,5](长度 n=5)为例,演示若按升序排列,如何将最大值逐步“冒泡”。

  1. 初始状态

    A = [5, 2, 9, 1, 5]

  2. 第一趟(i=0,未排序区间 0..4)

    • 比较 A[0]=5 与 A[1]=2,5>2 ⇒ 交换 ⇒ [2, 5, 9, 1, 5]

    • 比较 A[1]=5 与 A[2]=9,5≤9 ⇒ 无交换 ⇒ [2, 5, 9, 1, 5]

    • 比较 A[2]=9 与 A[3]=1,9>1 ⇒ 交换 ⇒ [2, 5, 1, 9, 5]

    • 比较 A[3]=9 与 A[4]=5,9>5 ⇒ 交换 ⇒ [2, 5, 1, 5, 9]

    • 本趟结果:最大元素 9 已移至末尾索引 4

  3. 第二趟(i=1,未排序区间 0..3)

    • 比较 A[0]=2 与 A[1]=5,2≤5 ⇒ 无交换 ⇒ [2, 5, 1, 5, 9]

    • 比较 A[1]=5 与 A[2]=1,5>1 ⇒ 交换 ⇒ [2, 1, 5, 5, 9]

    • 比较 A[2]=5 与 A[3]=5,5≤5 ⇒ 无交换 ⇒ [2, 1, 5, 5, 9]

    • 本趟结果:次大元素 5(第二个 5)已移至索引 3

  4. 第三趟(i=2,未排序区间 0..2)

    • 比较 A[0]=2 与 A[1]=1,2>1 ⇒ 交换 ⇒ [1, 2, 5, 5, 9]

    • 比较 A[1]=2 与 A[2]=5,2≤5 ⇒ 无交换 ⇒ [1, 2, 5, 5, 9]

    • 本趟结果:第三大元素 5 已移至索引 2

  5. 第四趟(i=3,未排序区间 0..1)

    • 比较 A[0]=1 与 A[1]=2,1≤2 ⇒ 无交换 ⇒ [1, 2, 5, 5, 9]

    • 本趟结果:索引 1 处元素 2 已正确;索引 0 处元素 1 本身即为最小

 二、选择排序

核心思想

每一趟从“未排序”区间中选出最小(或最大)元素,将其放到“已排序”区间的末端(或开头),直到所有元素均归位。

  • 数据规模较小、对稳定性不严格要求时可以直接使用。

  • 当内存开销非常有限、只需常数级额外空间(O(1))时,选择排序可作为一种可行方案。

  • 由于交换次数较少(最多 n−1次),在某些对交换代价敏感的场景里(比如写入操作成本高时)有一定优势。

伪代码

function selectionSort(A[0..n-1]):
    for i from 0 to n-2:            // 共需进行 n-1 趟
        minIndex = i                // 假设当前下标 i 处是“最小值“
        // 在 [i+1..n-1] 范围内找真正的最小值
        for j from i+1 to n-1:
            if A[j] < A[minIndex]:
                minIndex = j        // 更新当前最小元素下标
        // 若 minIndex 与 i 不同,则交换,放到已排序区尾部
        if minIndex ≠ i:
            swap A[i], A[minIndex]
    return A

python实现

def Selection(arr):
    l = len(arr)
    for i in range(l-1):
        min_index = i
        for j in range(i,l):
            if arr[j] < arr[min_index]:
                arr[min_index],arr[j] = arr[j],arr[min_index]
    return arr

补充 :补充双端选择排序,即每一次同时选择未排序的队列中的最小值和最大值,分别放到队列的两端。

def QuickSelection(arr):
    left = 0
    right = len(arr)-1
    while left <= right:
        min_index = left
        max_index = right
        for i in range(left, right+1):
            if arr[i] < arr[min_index]:
                min_index = i
            if arr[i] > arr[max_index]:
                max_index = i
        arr[min_index], arr[left] = arr[left], arr[min_index]
        arr[max_index], arr[right] = arr[right], arr[max_index]

        left += 1
        right -= 1
    return arr

三、插入排序

核心思想
将待排序的数组分为“已排序区间”和“未排序区间”,每次从未排序区间取出第一个元素,将其插入到已排序区间的正确位置,直到所有元素均插入完毕。

  • 数据规模较小,或者待排序数组本身“近乎有序”时,插入排序效率较高。

  • 适用于在线排序(数据不断到达,一边接收一边排序)。

  • 由于算法简单易实现,也常用于“对部分有序序列进行最后微调”(如归并排序子段合并后,进行插入操作)。

伪代码 

function insertionSort(A[0..n-1]):
    for i from 1 to n-1:
        key = A[i]
        j = i - 1
        // 在已排序区间 [0..i-1] 中,从后向前寻找合适插入位置
        while j ≥ 0 and A[j] > key:
            A[j + 1] = A[j]    // 将 A[j] 向后移一位
            j = j - 1
        // 循环结束后,j == -1 或 A[j] ≤ key
        A[j + 1] = key        // 将 key 放到正确位置
    return A

python实现

def insertion_sort1(arr):
    for i in range(1,len(arr)):
        key = i
        j = i-1
        while j >= 0 and arr[j] > arr[key]:
            arr[j+1] = arr[j]
            j -= 1
        arr[j+1] = arr[key]
    return arr

四、快速排序

  • 定义
    快速排序(Quick Sort)是一种基于分治(Divide and Conquer)思想的高效排序算法。其核心思路是:

    1. 选取基准(pivot)

    2. 分区(Partition):将待排序数组划分为两部分,左侧所有元素均不大于基准,右侧所有元素均不小于基准(某些实现方式略有不同)。

    3. 递归排序:对“左侧子数组”和“右侧子数组”分别递归执行快速排序,最终将整个数组排序完毕。

  • 特点

    • 平均时间复杂度较低,为 O(nlog⁡n);

    • 原地排序(in-place)——常见的分区方案仅需 O(log⁡n)额外空间用于递归栈;

    • 非稳定排序(unstable),相等元素的相对次序可能在交换过程中被改变;

    • 实践中表现优异,是许多语言库(如 C++ std::sort、Java 的基本类型排序)采用的核心算法。

  • 适用场景

    • 大多数随机、无序的场景下性能优秀;

    • 内存允许时,原地实现减少空间开销;

    • 尽管最坏时退化为O(n^2),但通过合理选取基准可极大降低退化出现概率,故在工业界被广泛使用。

伪代码

这里以Hoare 分区方案为例子 

function partitionHoare(A, low, high):
    pivot = A[(low + high) // 2]
    i = low − 1
    j = high + 1
    while true:
        do:
            i = i + 1
        while A[i] < pivot

        do:
            j = j − 1
        while A[j] > pivot

        if i ≥ j:
            return j
        swap A[i], A[j]

初始:

A = [8, 3, 1, 7, 0, 10, 2],

low=0, high=6 pivot = A[6] = 2 i = low−1 = −1

  1. 遍历 j=0..5:

    • j=0, A[0]=8 > 2 ⇒ 不交换,i remains −1

    • j=1, A[1]=3 > 2 ⇒ 不交换

    • j=2, A[2]=1 ≤ 2 ⇒ i=0, swap A[0]↔A[2] ⇒ A=[1,3,8,7,0,10,2]

    • j=3, A[3]=7 > 2 ⇒ 不交换

    • j=4, A[4]=0 ≤ 2 ⇒ i=1, swap A[1]↔A[4] ⇒ A=[1,0,8,7,3,10,2]

    • j=5, A[5]=10 > 2 ⇒ 不交换

    最终 i=1。

  2. 归位基准

    • swap A[i+1]=A[2] ↔ A[6] ⇒ swap A[2]=8 与 A[6]=2 ⇒

      A = [1, 0, 2, 7, 3, 10, 8]

    • 返回 p = i+1 = 2 作为基准下标。

A[0..1] = [1,0] ≤ 2 A[2] = [2] == pivot A[3..6] = [7,3,10,8] ≥ 2

接下来分治排序 [1,0][7,3,10,8]

python实现

def Quick_sort(arr,low,high):
    if low < high:
        p = Hoare(arr,low,high)
        Quick_sort(arr,low,p)
        Quick_sort(arr,p+1,high)
    return arr
def Hoare(arr,low,high):
    pivot = arr[(low+high)//2]
    i = low-1
    j = high+1
    while True:
        i += 1  # 特别注意,当交换之后继续寻找下一个可交换点的关键
        while arr[i] < pivot:
            i += 1
        j -= 1
        while arr[j] > pivot:
            j -= 1
        if i >= j:  # 循环while true结束的条件
            return j
        arr[i], arr[j] = arr[j], arr[i]

补充给出使用Lomuto 分区方案的代码

def partition_lomuto(arr, low, high):
    pivot = arr[high]
    i = low - 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

五、归并排序 

  • 定义
    归并排序(Merge Sort)是一种经典的分治(Divide and Conquer)排序算法。其核心思想是:

    1. 归并排序的核心在于“分治”与“合并”两部分:

    2. 分解(Divide)

      • 给定数组 A[0..n-1],如果 n <= 1,直接返回(数组已经有序)。

      • 否则,计算中点 mid = ⌊(low + high)/2⌋,将数组分为两半:A[low..mid]A[mid+1..high]

    3. 递归排序

      • 递归地对左半部分 A[low..mid] 调用归并排序。

      • 递归地对右半部分 A[mid+1..high] 调用归并排序。

    重复上述分解和合并过程,直到整个区间合并完毕,即得最终有序数组。

  • 合并(Merge)

    • 当左、右两个子数组分别已经排序后,将它们“归并”到一个临时数组 temp[] 中,使得 temp 也是有序的。具体做法是:

      1. 用两个指针 i = low(指向左子数组起始)和 j = mid+1(指向右子数组起始)。

      2. 比较 A[i]A[j],较小的元素先放入 temp[k],并相应地移动 ij

      3. 重复上述比较,直到其中一个子数组耗尽。

      4. 将另一个子数组剩余的所有元素依次复制到 temp

      5. 最后将 temp[low..high] 复制回 A[low..high],完成该区间的合并。

  • 特点

    • 时间复杂度 均衡且稳定,为 O(nlog⁡n);

    • 空间复杂度 需要额外 O(n)辅助空间(典型实现);

    • 稳定排序(Stable),在合并过程中相等元素不会改变原有相对顺序;

    • 可适用于外部排序(大规模数据需借助磁盘时常用多路归并);

    • 递归实现简单直观,也可改写为自底向上的迭代实现。

  • 适用场景

    • 对大规模数据(在内存足够情况下)要求稳定排序时;

    • 需要保证最坏时间复杂度为 O(nlog⁡n)的场景;

    • 在外部排序(外存排序)时,归并过程可扩展为多路归并;

    • 对链表结构排序时,归并排序可做到 O(1)辅助空间并保持稳定。

伪代码

function mergeSort(A, low, high):
    if low >= high:
        return
    mid = ⌊(low + high) / 2⌋
    mergeSort(A, low, mid)         // 对左半部分递归排序
    mergeSort(A, mid + 1, high)    // 对右半部分递归排序
    merge(A, low, mid, high)       // 合并两个有序子数组

function merge(A, low, mid, high):
    // 准备临时数组 temp,用于存放合并结果
    create array temp of size (high - low + 1)
    i = low
    j = mid + 1
    k = 0

    // 1. 合并过程:两个子数组都不为空时依次比较放入 temp
    while i ≤ mid and j ≤ high:
        if A[i] ≤ A[j]:
            temp[k] = A[i]
            i = i + 1
        else:
            temp[k] = A[j]
            j = j + 1
        k = k + 1

    // 2. 如果左子数组还有剩余,全部复制到 temp
    while i ≤ mid:
        temp[k] = A[i]
        i = i + 1
        k = k + 1

    // 3. 如果右子数组还有剩余,全部复制到 temp
    while j ≤ high:
        temp[k] = A[j]
        j = j + 1
        k = k + 1

    // 4. 将 temp 中的元素复制回 A[low..high]
    for t from 0 to (high - low):
        A[low + t] = temp[t]

python实现

def merge_sort(A):
    """
    归并排序(自顶向下递归实现)。
    输入:
        A: 待排序列表(会被修改)
    返回:
        无返回值,排序在 A 原地完成
    """
    def _merge_sort(arr, low, high):
        if low >= high:
            return
        mid = (low + high) // 2
        # 1. 递归排序左半部分
        _merge_sort(arr, low, mid)
        # 2. 递归排序右半部分
        _merge_sort(arr, mid + 1, high)
        # 3. 合并两部分
        _merge(arr, low, mid, high)

    def _merge(arr, low, mid, high):
        # 辅助数组 temp,用于暂存合并结果
        temp = []
        i, j = low, mid + 1

        # 1. 当左右子数组都未遍历完,依次比较
        while i <= mid and j <= high:
            if arr[i] <= arr[j]:
                temp.append(arr[i])
                i += 1
            else:
                temp.append(arr[j])
                j += 1

        # 2. 如果左子数组有剩余,全部追加
        while i <= mid:
            temp.append(arr[i])
            i += 1

        # 3. 如果右子数组有剩余,全部追加
        while j <= high:
            temp.append(arr[j])
            j += 1

        # 4. 将 temp 中的元素复制回 arr[low..high]
        for k in range(len(temp)):
            arr[low + k] = temp[k]

    # 调用递归函数对整个数组排序
    _merge_sort(A, 0, len(A) - 1)

 六、计数排序、

计数排序核心思想是对于待排序数组中元素的取值范围已知(或较小)时,先统计各元素出现的次数,再根据累计计数结果直接将元素放置到最终位置,从而达到排序目的。例如比当前数小的数有15个,则当前数放在第16位。

特点

  • 非比较:不通过元素间两两比较来决定顺序,而是借助“计数”与“前缀和”直接定位位置。

  • 线性时间:时间复杂度为 O(n+k),其中 n为元素个数,k为元素值域大小。

  • 稳定排序:只要在合并输出时按照从后向前或维护计数时采用合适策略,就能保证相等元素的相对次序不变。

  • 额外空间:需要一个大小约为 k+1的计数数组,以及一个大小约为 n的输出数组,空间复杂度为 O(n+k)。

伪代码

function countingSort(A, n, k):
    // A: 待排序数组,索引范围 0..n-1,元素取值范围 0..k
    // n: 数组长度;k: 元素最大值

    // 1. 初始化计数数组 C[0..k] 为 0
    create array C of length k+1, initialize all entries to 0

    // 2. 统计频次
    for i from 0 to n-1:
        C[A[i]] = C[A[i]] + 1

    // 3. 累加计数,计算前缀和
    for i from 1 to k:
        C[i] = C[i] + C[i-1]

    // 4. 创建输出数组 B[0..n-1]
    create array B of length n

    // 5. 从后向前遍历 A,输出到 B
    for i from n-1 down to 0:
        v = A[i]
        pos = C[v] - 1      // 最后一个值为 v 的元素应放在 pos
        B[pos] = v
        C[v] = C[v] - 1     // 预留下一个相同值放置位置

    // 6. 若需将结果复制回 A,可执行:
    for i from 0 to n-1:
        A[i] = B[i]

    // 返回有序结果 B(或 A)
    return B

python实现

def counting_sort(A, k):
    """
    计数排序(适用于非负整数)。
    输入:
        A: 待排序列表,元素均为整数,范围假设在 0..k。
        k: 最大可能值(假定最小值为 0)。
    输出:
        就地修改 A,使之按升序排序;并返回排序结果列表。
    """
    n = len(A)
    # 1. 初始化计数数组 C[0..k] 为 0
    C = [0] * (k + 1)

    # 2. 统计频次
    for v in A:
        # 假设 v 在 0..k 范围内
        C[v] += 1

    # 3. 累加计数,计算前缀和
    for i in range(1, k + 1):
        C[i] += C[i - 1]

    # 4. 创建输出数组 B[0..n-1]
    B = [0] * n

    # 5. 从后向前遍历 A,保证稳定性
    for i in range(n - 1, -1, -1):
        v = A[i]
        pos = C[v] - 1       # 最后一个该值应放位置
        B[pos] = v
        C[v] -= 1

    # 6. 将结果复制回 A
    for i in range(n):
        A[i] = B[i]

    return A


基数排序:从最低位(Least Significant Digit, LSD)到最高位(Most Significant Digit, MSD)依次进行稳定排序,最终得到整体有序序列。先对个数位进行排序,在排序基础上继续对十位数进行排序依次类推。

核心思想

  1. 按位分组:先根据元素的最低位(个位)进行一次稳定的“计数排序”或“桶排序”,使得其在该位上有序。

  2. 逐位推进:再按次低位(十位)继续进行一次稳定排序,以此类推直到最高位。

  3. 稳定保证:由于每轮对各位进行的子排序均为稳定排序(如计数排序),上一轮已经排好序的低位次序得以保留,从而最终得到全局升序。

伪代码

function radixSort(A, n):
    # A: 待排序的非负整数数组,长度为 n
    # 1. 先找出最大值,以确定最大位数 d
    max_val = max(A[0..n-1])
    d = numberOfDigits(max_val)      # 十进制位数,例如 max_val=356 -> d=3

    # 2. 初始化基数 r = 10,用于针对各位做计数排序
    r = 10

    # 3. 从第 1 位(个位)到第 d 位逐位排序
    for k from 1 to d:
        # 3.1 创建计数数组 C[0..r-1],初始化为 0
        create array C[0..r-1], initialize all to 0

        # 3.2 创建输出数组 B[0..n-1]
        create array B[0..n-1]

        # 3.3 统计第 k 位的频次
        for i from 0 to n-1:
            digit = getDigit(A[i], k)     # 获取 A[i] 的第 k 位数字 (1 表示个位, 2 表示十位, …)
            C[digit] = C[digit] + 1

        # 3.4 累加计数,计算前缀和
        for i from 1 to r-1:
            C[i] = C[i] + C[i - 1]

        # 3.5 从后向前遍历 A,依据第 k 位将元素放到 B 中(保证稳定性)
        for i from n-1 down to 0:
            digit = getDigit(A[i], k)
            pos = C[digit] - 1           # 该 digit 在输出中应放的位置
            B[pos] = A[i]
            C[digit] = C[digit] - 1

        # 3.6 将 B 复制回 A,为下一位排序做准备
        for i from 0 to n-1:
            A[i] = B[i]

    # 4. 完成所有位的排序,A 即为最终升序结果
    return A

 python实现

def radix_sort(A):
    """
    基数排序(十进制 LSD 方式,针对非负整数列表)。
    输入:
        A: 待排序列表,元素均为非负整数
    返回:
        就地对 A 进行升序排序,并返回排序后的列表引用
    """
    if not A:
        return A

    # 1. 找到最大值,以确定最大位数 d
    max_val = max(A)
    # 计算位数 d:例如 max_val=356 -> d=3
    d = 0
    while (10 ** d) <= max_val:
        d += 1

    # 2. 从第 1 位到第 d 位,依次进行计数排序
    #   令 exp = 10^(k-1),每次定位到 k 位:digit = (num // exp) % 10
    exp = 1  # 代表 10^(k-1),初始为 1(个位)
    n = len(A)
    # 临时输出数组
    B = [0] * n

    for _ in range(d):
        # 2.1 构造计数数组 C[0..9],初始化为 0
        C = [0] * 10

        # 2.2 统计当前位(exp 指定的位)的频次
        for num in A:
            digit = (num // exp) % 10
            C[digit] += 1

        # 2.3 累加计数,计算前缀和
        for i in range(1, 10):
            C[i] += C[i - 1]

        # 2.4 从后向前遍历 A,依据当前位将元素放到 B
        for i in range(n - 1, -1, -1):
            num = A[i]
            digit = (num // exp) % 10
            pos = C[digit] - 1
            B[pos] = num
            C[digit] -= 1

        # 2.5 将 B 复制回 A,为下一位排序做准备
        for i in range(n):
            A[i] = B[i]

        # 2.6 准备下一个更高位:从个位(exp=1)到十位(exp=10)、百位(exp=100)……
        exp *= 10

    return A

桶排序:是一种基于“分布”思想的非比较排序算法。其核心思路是:

  1. 根据数据分布,将待排序元素均匀分布到若干个“桶”(Bucket)中。

  2. 对每个桶内部分别进行排序(通常采用插入排序或其他高效算法)。

  3. 最后按桶的顺序将各桶中元素依次合并,得到整体有序序列。

伪代码

function bucketSort(A[0..n-1], L, U, m):
    # A: 待排序数组,长度 n
    # L, U: 值域区间下界和上界(假设 A 中所有元素都满足 L ≤ x < U)
    # m: 桶的数量

    # 1. 初始化 m 个空桶,每个桶用动态数组(或链表)表示
    create array buckets[0..m-1]
    for i from 0 to m-1:
        buckets[i] = empty list

    # 2. 将元素分发到各自桶
    Δ = (U - L) / m   # 每个桶负责的区间跨度
    for i from 0 to n-1:
        x = A[i]
        idx = floor((x - L) / Δ)
        if idx == m:   # 如果 x 恰好等于 U(边界情况)
            idx = m - 1
        buckets[idx].append(x)

    # 3. 对每个桶内部进行排序(使用稳定的插入排序或其他)
    for i from 0 to m-1:
        insertionSort(buckets[i])   # 假设 insertionSort 是稳定的

    # 4. 合并所有桶内容到输出数组 B
    create array B[0..n-1]
    pos = 0
    for i from 0 to m-1:
        for each element x in buckets[i]:
            B[pos] = x
            pos = pos + 1

    # 5. (可选)将 B 复制回 A
    for i from 0 to n-1:
        A[i] = B[i]

    return A   # 或直接返回 B

python实现

def bucket_sort(A):
    """
    桶排序(适用于浮点数,假设所有元素都在 [0, 1) 区间内)。
    输入:
        A: 待排序列表,元素均为 float,0 <= x < 1
    返回:
        就地对 A 进行升序排序,并返回排序后的列表引用
    """
    n = len(A)
    if n <= 1:
        return A

    # 1. 创建 n 个空桶(列表嵌套列表)
    buckets = [[] for _ in range(n)]

    # 2. 将元素分发到各自桶:桶索引为 floor(x * n)
    for x in A:
        idx = int(x * n)        # idx in [0..n-1],当 x==1 时要特殊处理,但此处假设 x < 1
        buckets[idx].append(x)

    # 3. 对每个桶内部使用插入排序进行排序
    for i in range(n):
        insertion_sort(buckets[i])   # 使用下文定义的插入排序函数

    # 4. 合并所有桶到 A
    pos = 0
    for i in range(n):
        for x in buckets[i]:
            A[pos] = x
            pos += 1

    return A

def insertion_sort(lst):
    """
    插入排序,对列表 lst 原地升序排序(保证稳定性)。
    """
    for i in range(1, len(lst)):
        key = lst[i]
        j = i - 1
        # 向左移动大于 key 的元素
        while j >= 0 and lst[j] > key:
            lst[j + 1] = lst[j]
            j -= 1
        lst[j + 1] = key
    return lst


 

 

算法 最坏时间复杂度 平均时间复杂度 最好时间复杂度 空间复杂度 稳定性 额外说明
冒泡排序 O(n²) O(n²) O(n) O(1) 稳定 简单易懂、性能差,只适合小数据或近乎有序场景
选择排序 O(n²) O(n²) O(n²) O(1) 不稳定 交换次数少(最少为 n−1 次),但比较次数固定;不稳定
插入排序 O(n²) O(n²) O(n) O(1) 稳定 对近乎有序效果好,可用于小规模排序或部分有序数据的最终“微调”
希尔排序 O(n·(log n)²)〜O(n^(1.5)) (视 gap 序列而定) O(1) 不稳定 介于 O(n²) 与 O(n log n) 之间,性能取决于增量序列;常用于中等规模数组
归并排序 O(n log n) O(n log n) O(n log n) O(n) 稳定 分治思想,性能稳定;需要线性额外空间;可做外部归并排序
快速排序 O(n²) O(n log n) O(n log n) O(log n) (递归栈) 不稳定 在随机化或“三数取中”等优化下,实际性能很高;若无优化,最坏可能退化;不稳定
堆排序 O(n log n) O(n log n) O(n log n) O(1) 不稳定 原地排序,无需额外线性空间,但不稳定;常用于需要 O(n log n) 且空间受限场景
计数排序 O(n + k) O(n + k) O(n + k) O(n + k) 稳定 适用于整数且 k 较小;线性时间;非比较排序
桶排序 平均 O(n + m) O(n + m) 视桶内排序算法而定 适合均匀分布数据;最坏 O(n²);空间按桶数 m 而定
基数排序 O(d·(n + k)) O(n + k) 稳定 适合定长整数或字符串排序;当 d、k 为常数时近似线性;依赖稳定子过程
Timsort O(n log n) O(n)(部分有序) O(n)(部分有序) O(n) 稳定 结合插入与归并,针对“部分有序”优化;Python、Java 等语言默认内置
  • 小规模或近乎有序数据

    • 可优先考虑 插入排序 或 冒泡排序 (带有“有序检测”优化)。

    • 若追求低常数开销,可选 插入排序(本地缓存命中率好)。

  • 中等规模数据

    • 快速排序(随机化版)也是不错选择。

  • 大规模数据且内存足够

    • 快速排序(在绝大多数编程语言标准库中都有高效实现);

    • 归并排序(若对稳定性有要求或计划做外部归并)。

  • 对稳定性有严格要求时

    • 归并排序、计数排序、基数排序、插入排序(理想场景)。

  • 数据范围已知且元素为整数时

    • 计数排序、基数排序、或者桶排序(特别是浮点数分布已知场景)。

你可能感兴趣的:(排序算法,算法)