当前位置:首页>python>排序算法专题|7种核心排序算法集合(Python版)

排序算法专题|7种核心排序算法集合(Python版)

  • 2026-09-27 13:58:54
排序算法专题|7种核心排序算法集合(Python版)

1. 冒泡排序(Bubble Sort)

算法思路

核心:相邻元素两两比较,将较大元素逐步“冒泡”到数组末尾,每一轮遍历确定一个最大值。时间复杂度O(n²),空间复杂度O(1),稳定排序,适合小规模数据。

Python手撕代码

def bublesort(a):    n = len(a)    # 外层循环:控制排序轮次,共n-1轮(最后一个元素无需比较)    for i in range(n-1):        # 内层循环:每轮遍历未排序部分,相邻元素比较交换        # 每轮结束后,最大元素已沉到末尾,无需再比较        for j in range(n-i-1):            # 若前一个元素大于后一个,交换位置(冒泡核心)            if a[j] > a[j+1]:                a[j], a[j+1] = a[j+1], a[j]    return a

2. 插入排序(Insert Sort)

算法思路

核心:将数组分为有序区和无序区,依次将无序区的元素插入到有序区的合适位置,类比整理扑克牌。时间复杂度O(n²),空间复杂度O(1),稳定排序,小规模数据效率优于冒泡。

Python手撕代码

def insertsort(a):    n = len(a)    # 外层循环:从第2个元素开始(第1个元素默认有序),遍历无序区    for i in range(1, n):        key = a[i]  # 取出当前要插入的元素(无序区第一个元素)        j = i - 1   # 有序区的最后一个元素索引        # 内层循环:在有序区中找到插入位置,将大于key的元素后移        while j >= 0 and a[j] > key:            a[j+1] = a[j]  # 元素后移,腾出插入位置            j -= 1        a[j+1] = key  # 将key插入到正确位置    return a

3. 选择排序(Select Sort)

算法思路

核心:每次从无序区中找到最小(或最大)元素,与无序区第一个元素交换,逐步扩大有序区。时间复杂度O(n²),空间复杂度O(1),不稳定排序,适合数据量小、对稳定性无要求的场景。

Python手撕代码

def selectsort(a):    n = len(a)    # 外层循环:控制有序区范围,共n-1轮(最后一个元素无需选择)    for i in range(n-1):        index = i  # 初始化最小元素索引为无序区第一个元素        # 内层循环:遍历无序区,找到最小元素的索引        for j in range(i+1, n):            if a[j] < a[index]:                index = j  # 更新最小元素索引        # 将最小元素与无序区第一个元素交换        a[i], a[index] = a[index], a[i]    return a

4. 计数排序(Count Sort)

算法思路

核心:非比较排序,先统计数组中每个元素出现的次数,再根据次数重新构建有序数组。时间复杂度O(n+k)(k为数组最大值),空间复杂度O(k),稳定排序,适合元素范围不大的整数数组。

Python手撕代码(修正原代码笔误)

def countsort(a):    n = len(a)    if n == 0:  # 处理空数组边界情况        return a    max_v = max(a)  # 找到数组中的最大值,确定计数数组长度    res = [0] * (max_v + 1)  # 计数数组,存储每个元素出现次数    for num in a:  # 修正原代码nums为a,避免变量名错误        res[num] += 1    tmp = []  # 存储最终有序数组    # 遍历计数数组,按元素大小依次加入结果    for i, r in enumerate(res):        while r > 0:            tmp.append(i)            r -= 1    return tmp

5. 归并排序(Merge Sort)

算法思路

核心:分治思想,将数组递归拆分为两个子数组,分别排序后再合并,合并时保持有序。时间复杂度O(nlogn),空间复杂度O(n),稳定排序,适合大规模数据,兼顾效率和稳定性。

Python手撕代码

def mergesort(a):    # 辅助函数:递归拆分+合并    def merge_sort_(a, res, start, end):        if start >= end:  # 递归终止条件:子数组长度为1(已有序)            return        # 分:将数组拆分为左右两个子数组,分别递归排序        mid = (start + end) // 2        merge_sort_(a, res, start, mid)        merge_sort_(a, res, mid + 1, end)        # 合:将两个有序子数组合并为一个有序数组        i, j, k = start, mid+1, start  # i左子数组指针,j右子数组指针,k结果指针        while i <= mid and j <= end:            # 比较左右子数组元素,将较小值存入结果数组            if a[i] <= a[j]:                res[k] = a[i]                i += 1            else:                res[k] = a[j]                j += 1            k += 1        # 将左子数组剩余元素存入结果        while i <= mid:            res[k] = a[i]            i += 1            k += 1        # 将右子数组剩余元素存入结果        while j <= end:            res[k] = a[j]            j += 1            k += 1        # 将结果数组的值复制回原数组(完成当前区间排序)        for k in range(start, end + 1):              a[k] = res[k]    n = len(a)    if n == 0:        return a    res = [0] * n  # 辅助结果数组,存储合并后的有序数据    merge_sort_(a, res, 0, n-1)    return a

6. 快速排序(Quick Sort)

算法思路

核心:分治思想,选择一个基准元素(pivot),将数组分为两部分,左部分小于基准,右部分大于等于基准,再递归排序左右两部分。时间复杂度O(nlogn)(最坏O(n²)),空间复杂度O(logn)(递归栈),不稳定排序,实际应用中效率最高。

Python手撕代码

def quicksort(a):    # 辅助函数:分区操作,返回基准元素的最终位置    def partition(nums, left, right):        pivot = nums[left]  # 选择左边界元素作为基准        # 双指针交换,将小于基准的元素移到左边,大于等于的移到右边        while left < right:            # 从右往左找,找到第一个小于基准的元素            while left < right and nums[right] >= pivot:                right -= 1            nums[left] = nums[right]  # 移到左指针位置            # 从左往右找,找到第一个大于基准的元素            while left < right and nums[left] <= pivot:                left += 1            nums[right] = nums[left]  # 移到右指针位置        nums[left] = pivot  # 将基准元素放到最终位置        return left  # 返回基准元素索引    # 辅助函数:递归排序    def sort_(nums, left, right):        if left >= right:  # 递归终止条件:子数组长度<=1            return        mid = partition(nums, left, right)  # 分区,得到基准位置        sort_(nums, left, mid-1)  # 递归排序左半部分        sort_(nums, mid+1, right)  # 递归排序右半部分    if len(a) == 0:        return a    sort_(a, 0, len(a)-1)    return a

7. 堆排序(Heap Sort)

算法思路

核心:利用大顶堆(或小顶堆)的特性,每次取出堆顶元素(最大值),与数组末尾元素交换,再调整剩余元素为大顶堆,重复直至排序完成。时间复杂度O(nlogn),空间复杂度O(1),不稳定排序,适合大规模数据排序。

Python手撕代码

def heap_sort(arr):    arr_copy = arr.copy()  # 复制数组,避免修改原数组    n = len(arr_copy)    if n <= 1:        return arr_copy    # 第一步:构建大顶堆(从最后一个非叶子节点开始调整)    for i in range(n // 2 - 1, -1, -1):        adjust_heap(arr_copy, i, n)    # 第二步:逐个交换堆顶元素和末尾元素,然后调整剩余堆    for j in range(n - 1, 0, -1):        # 交换堆顶(最大值)和当前未排序部分的最后一个元素        arr_copy[0], arr_copy[j] = arr_copy[j], arr_copy[0]        # 对剩余未排序部分(0到j-1)重新调整为大顶堆        adjust_heap(arr_copy, 0, j)    return arr_copy# 辅助函数:调整堆结构,使当前父节点满足大顶堆特性(父节点>子节点)def adjust_heap(arr, parent_idx, heap_size):    # 保存父节点值(用于后续赋值,避免多次交换)    temp = arr[parent_idx]    # 左子节点索引(完全二叉树特性:左子节点=2*父节点+1,右子节点=2*父节点+2)    child_idx = 2 * parent_idx + 1    # 循环遍历子节点,找到最大的子节点,完成堆调整    while child_idx < heap_size:        # 如果右子节点存在,且右子节点值 > 左子节点值,切换到右子节点        if child_idx + 1 < heap_size and arr[child_idx] < arr[child_idx + 1]:            child_idx += 1        # 如果子节点值 > 父节点值,将子节点值赋值给父节点(无需交换,先覆盖)        if arr[child_idx] > temp:            arr[parent_idx] = arr[child_idx]            # 父节点索引更新为当前子节点索引,继续向下调整            parent_idx = child_idx            child_idx = 2 * parent_idx + 1        else:            # 父节点值 ≥ 子节点值,无需调整,退出循环            break    # 将最初保存的父节点值赋值到最终位置    arr[parent_idx] = temp

LeetCode 16.16 部分排序

给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。

示例:

输入: [1,2,4,7,10,11,7,12,6,7,16,18,19] 输出: [3,9]

提示:

0 <= len(array) <= 1000000

解题思路

核心:贪心思想,分两步找边界:

1. 从左到右遍历,记录当前最大值,若当前元素小于最大值,说明该元素在无序区间内,更新右边界end;

2. 从右到左遍历(或通过左遍历记录最小值),找到无序区间的最小元素,再从左到右找到第一个大于该最小值的元素,即为左边界start;

3. 若start仍为-1,说明数组有序,返回[-1,-1],否则返回[start, end]。时间复杂度O(n),空间复杂度O(1),高效适配大数据量。

Python解题代码

def part_sort(array):    if len(array) <= 1:  # 数组长度<=1,本身有序        return [-1, -1]    max_v = float('-inf')  # 记录左到右遍历的最大值    min_v = float('inf')   # 记录无序区间的最小值    start = -1             # 无序区间左边界    end = -1               # 无序区间右边界    # 第一步:从左到右遍历,找无序区间的右边界end,同时记录无序区间的最小值min_v    for i, value in enumerate(array):        if max_v < value:            max_v = value  # 更新当前最大值(处于有序区间)        if max_v > value:            end = i        # 出现比当前最大值小的元素,更新右边界            if min_v > value:                min_v = value  # 更新无序区间的最小值    # 第二步:从左到右遍历,找无序区间的左边界start(第一个大于min_v的元素)    for i, value in enumerate(array):        if min_v < value:            start = i            break    # 若start仍为-1,说明数组有序(min_v未更新,即无无序元素)    return [start, end] if start != -1 else [-1, -1]
例题来自力扣网https://leetcode-cn.com/

请在微信客户端打开

最新文章

随机文章