【python】十大排序算法

全文一览

  • 一、排序算法
    • 1.1 选择排序
    • 1.2 冒泡排序
    • 1.3 插入排序
    • 1.4 归并排序
    • 1.5 桶排序
    • 1.6 计数排序
    • 1.7 基数排序
    • 1.8 快速排序
    • 1.9 希尔排序
    • 1.10 堆排序
  • 二、完整代码

一、排序算法

本文介绍了十种最常见的排序算法:选择排序、冒泡排序、插入排序、归并排序、桶排序、计数排序、基数排序、(随机)快速排序、希尔排序和堆排序算法。

1.1 选择排序

每轮循环,从剩余数队列中选出最小的放在剩余队列最前面(或从剩余数队列中选出最大的放在剩余队列最后面,下不赘述):

# 选择排序
def SelectionSort(l: list):
    for i in range(len(l) - 1):
        mini = i
        for j in range(i + 1, len(l)):
            if l[j] < l[mini]:
                mini = j
        if mini != i:
            l[i], l[mini] = l[mini], l[i]

1.2 冒泡排序

每轮循环中,将未排序的数列逐一跟后面的一个数进行比较,得到较大的数放在后面:

# 冒泡排序
def BubbleSort(L: list):
    for i in range(len(L) - 1):
        for j in range(len(L) - 1 - i):
            if L[j] > L[j + 1]:
                L[j], L[j + 1] = L[j + 1], L[j]

1.3 插入排序

插入排序算法可以直接在原列表上进行修改,在已排序好的数列里面依次向后移动数字,直到可以存放新加入的数据:

# 插入排序
def InsertionSort(L: list):
    for i in range(1, len(L)):
        if L[i] < L[i - 1]:
            j = i - 1
            tmp = L[i]
            while j >= 0:
                if L[j] > tmp:
                    L[j + 1] = L[j]
                    j -= 1
                else:
                    break
            L[j + 1] = tmp

1.4 归并排序

在归并排序中,我们使用到两个子函数 MergeRecursion 和 Merge。
MergeRecursion 用于递归地将数列拆分为两列,直到每一列都只有一个元素(此时可认为数列有序),然后调用 Merge 将两个有序列表合并为一个有序列表。

# 归并排序
# 直接调用 MergeRecursion 函数,传入列表的首尾序列
def MergeSort(L: list):
    MergeRecursion(L, 0, len(L) - 1)


# 对列表进行二分拆分成有序的原子序列,然后调用 Merge 函数进行合并
def MergeRecursion(L: list, start, end):
    if start == end:
        return
    mid = (start + end) // 2
    MergeRecursion(L, start, mid)
    MergeRecursion(L, mid + 1, end)
    Merge(L, start, mid, end)


# 将两个有序的列表 L[start:mid] 和 L[mid+1:end] 融合成一个有序列表
def Merge(L: list, start, mid, end):
    new = []
    l = start
    r = mid + 1
    while l <= mid and r <= end:
        if L[l] <= L[r]:
            new.append(L[l])
            l += 1
        else:
            new.append(L[r])
            r += 1
    if l == mid + 1:
        new.extend(L[r:end + 1])
    else:
        new.extend(L[l:mid + 1])
    L[start:end + 1] = new[:]

1.5 桶排序

桶排序是将数据先存放到不同的桶中,桶的数量 bucket_count 可以自行设定。桶内排序需要调用其他排序算法(如选择排序 SelectionSort)来实现。

# 桶排序排序
def BucketSort(L:list):
    bucket_count = 3
    Buckets = [[] for i in range(bucket_count)]
    mini = min(L)
    maxi = max(L)
    length = (maxi - mini + bucket_count) // bucket_count

    for num in L:
        index = (num - mini) // length
        Buckets[int(index)].append(num)

    for bucket in Buckets:
        SelectionSort(bucket)

    sorted_buckets = [i for bucket in Buckets for i in bucket]
    L[:] = sorted_buckets[:]

算法用到 生成式 对代码进行了简化。

1.6 计数排序

计数排序使用一个新的列表记录在最小值 mini 到最大值 maxi 区间内各个数字出现的次数,再通过计数还原成有序的数列。
显然,这类方法适用于整型、密集分布的数据的排序。

# 计数排序
def CountingSort(L: list):
    mini = min(L)
    maxi = max(L)
    new = [0 for i in range(mini, maxi + 1)]
    for num in L:
        new[num - mini] += 1
    # index = 0
    # for i in range(len(new)):
    #     while new[i] > 0:
    #         L[index] = mini + i
    #         index += 1
    #         new[i] -= 1
    L[:] = [mini + i for i in range(len(new)) for j in range(new[i])]

这里再次用到 生成式 对注释部分进行了简化。

1.7 基数排序

基数排序本质上也是一种桶排序,根据位数划分为 0~9 十个桶,再根据个十百千万等位数分别进行排序。
此方法适用于整型数据的排序。
在有负数时,可以先统一减去最小的负数进行排序,事后再统一加回来。

# 基数排序
def RadixSort(L: list):
    base = 1
    maxi = max(L)
    while base < maxi:
        Buckets = [[] for i in range(10)]
        for num in L:
            index = num // base % 10
            Buckets[index].append(num)
        # i = 0
        # for bucket in Buckets:
        #     for num in bucket:
        #         L[i] = num
        #         i += 1
        L[:] = [num for bucket in Buckets for num in bucket]
        base *= 10

这里再一次用到 生成式 。

1.8 快速排序

快速排序算法使用数列的第一个数作为基准 pivot,将大于它的数和小于它的数分别放在它的两边;然后对两边的数列递归使用上述操作,直到每个数都做过基准。
与归并排序类似,QuickSort 传入待处理列表;QuickRecursion 实现递归拆分;QuickSortPivot 则实现具体每一步中如何拆分数据,并返回基准数应在的位置(用于递归拆分)。

# 快速排序算法
def QuickSort(L: list):
    QuickRecursion(L, 0, len(L) - 1)


def QuickRecursion(L: list, start, end):
    if start >= end:
        return
    pivot = QuickSortPivot(L, start, end)
    QuickRecursion(L, start, pivot - 1)
    QuickRecursion(L, pivot + 1, end)


def QuickSortPivot(L: list, start, end):
    pivot = start
    j = start + 1
    for i in range(start + 1, end + 1):
        if L[i] < L[pivot]:
            L[i], L[j] = L[j], L[i]
            j += 1
    L[pivot], L[j - 1] = L[j - 1], L[pivot]
    pivot = j - 1
    return pivot

随机快速排序算法跟快速排序算法大体类似,区别在于 RandomQuickSortPivot 函数相比 QuickSortPivot 函数,在前两行增加了随机数,使得每次选定的基准为随机的。

# 随机快速排序
def RandomQuickSort(L: list):
    RandomQuickRecursion(L, 0, len(L) - 1)


def RandomQuickRecursion(L: list, start, end):
    if start >= end:
        return
    pivot = RandomQuickSortPivot(L, start, end)
    RandomQuickRecursion(L, start, pivot - 1)
    RandomQuickRecursion(L, pivot + 1, end)


def RandomQuickSortPivot(L: list, start, end):
    import random
    randIndex = random.randint(start, end)
    L[start], L[randIndex] = L[randIndex], L[start]
    pivot = start
    j = start + 1
    for i in range(start + 1, end + 1):
        if L[i] < L[pivot]:
            L[i], L[j] = L[j], L[i]
            j += 1
    L[pivot], L[j - 1] = L[j - 1], L[pivot]
    pivot = j - 1
    return pivot

1.9 希尔排序

希尔排序是一种改进后的插入排序。
希尔排序将数据分成 n/2 组,组内数据间隔为 n/2,然后将这些组分别进行插入排序;
之后将数据分成 n/4 组,组内数据间隔为 n/4,同上将这些组分别进行插入排序;
重复上述步骤,直到组内数据间隔不足 1,此时只剩一个组。

# 希尔排序
def ShellSort(L:list):
    n = len(L)
    gap = n // 2
    while gap > 0:
        for i in range(gap,n):
            tmp = L[i]
            j = i
            while j >= gap:
                if tmp < L[j-gap]:
                    L[j] = L[j - gap]
                else:
                    break
                j -= gap
            L[j] = tmp
        gap //= 2

1.10 堆排序

堆排序利用了二叉树的性质。通过交换节点值,可以选举出堆顶的最大元素,将其放入列表后面;再重复选举、后置,即可实现排序。
maxHeapify 函数用于选举出最大值, HeapSort 用于将最大值后置,并循环对剩余的数据进行选举、后置操作。
算法中的 heap 其实是用列表实现的。需要注意堆第一个元素开始的下标为 1,故需要在列表前填充一个元素。

# 堆排序
def HeapSort(L: list):
    heap = [None] + L  # heap 从 1 开始遍历,list 从 0 开始遍历,通过填补实现对接
    root = 1
    for i in range(len(heap) // 2, root - 1, -1):
        maxHeapify(heap, i, len(heap) - 1)
    for i in range(len(heap) - 1, root, -1):
        heap[i], heap[root] = heap[root], heap[i]
        maxHeapify(heap, root, i - 1)
    L[:] = heap[root:]


def maxHeapify(heap: list, start, end):
    son = start * 2
    while son <= end:
        if son + 1 < end and heap[son + 1] > heap[son]:
            son += 1
        if heap[son] > heap[start]:
            heap[start], heap[son] = heap[son], heap[start]
            start, son = son, son * 2
        else:
            break

二、完整代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :sort_algorithms.py
# @Time      :2023/7/25 14:35
# @Author    :Carl.Zhang
# Function   :Eleven most used sort algorithms.

# 选择排序
def SelectionSort(L: list):
    for i in range(len(L) - 1):
        mini = i
        for j in range(i + 1, len(L)):
            if L[j] < L[mini]:
                mini = j
        if mini != i:
            L[i], L[mini] = L[mini], L[i]


# 冒泡排序
def BubbleSort(L: list):
    for i in range(len(L) - 1):
        for j in range(len(L) - 1 - i):
            if L[j] > L[j + 1]:
                L[j], L[j + 1] = L[j + 1], L[j]


# 插入排序
def InsertionSort(L: list):
    for i in range(1, len(L)):
        if L[i] < L[i - 1]:
            j = i - 1
            tmp = L[i]
            while j >= 0:
                if L[j] > tmp:
                    L[j + 1] = L[j]
                    j -= 1
                else:
                    break
            L[j + 1] = tmp


# 插入排序2
def InsertionSort2(L: list):
    for i in range(1, len(L)):
        if L[i] < L[i - 1]:
            for j in range(i):
                if L[i] < L[j]:
                    tmp = L[i]
                    for k in range(i, j, -1):
                        L[k] = L[k - 1]
                    L[j] = tmp
                    break


# 归并排序
# 直接调用 MergeRecursion 函数,传入列表的首尾序列
def MergeSort(L: list):
    MergeRecursion(L, 0, len(L) - 1)


# 对列表进行二分拆分成有序的原子序列,然后调用 Merge 函数进行合并
def MergeRecursion(L: list, start, end):
    if start == end:
        return
    mid = (start + end) // 2
    MergeRecursion(L, start, mid)
    MergeRecursion(L, mid + 1, end)
    Merge(L, start, mid, end)


# 将两个有序的列表 L[start:mid] 和 L[mid+1:end] 融合成一个有序列表
def Merge(L: list, start, mid, end):
    new = []
    l = start
    r = mid + 1
    while l <= mid and r <= end:
        if L[l] <= L[r]:
            new.append(L[l])
            l += 1
        else:
            new.append(L[r])
            r += 1
    if l == mid + 1:
        new.extend(L[r:end + 1])
    else:
        new.extend(L[l:mid + 1])
    L[start:end + 1] = new[:]


# 桶排序排序
def BucketSort(L: list):
    bucket_count = 3
    Buckets = [[] for i in range(bucket_count)]
    mini = min(L)
    maxi = max(L)
    length = (maxi - mini + bucket_count) // bucket_count

    for num in L:
        index = (num - mini) // length
        Buckets[int(index)].append(num)

    for bucket in Buckets:
        SelectionSort(bucket)

    sorted_buckets = [i for bucket in Buckets for i in bucket]
    L[:] = sorted_buckets[:]


# 计数排序
def CountingSort(L: list):
    mini = min(L)
    maxi = max(L)
    new = [0 for i in range(mini, maxi + 1)]
    for num in L:
        new[num - mini] += 1
    # index = 0
    # for i in range(len(new)):
    #     while new[i] > 0:
    #         L[index] = mini + i
    #         index += 1
    #         new[i] -= 1
    L[:] = [mini + i for i in range(len(new)) for j in range(new[i])]


# 基数排序
def RadixSort(L: list):
    base = 1
    maxi = max(L)
    while base < maxi:
        Buckets = [[] for i in range(10)]
        for num in L:
            index = num // base % 10
            Buckets[index].append(num)
        # i = 0
        # for bucket in Buckets:
        #     for num in bucket:
        #         L[i] = num
        #         i += 1
        L[:] = [num for bucket in Buckets for num in bucket]
        base *= 10


# 快速排序算法
def QuickSort(L: list):
    QuickRecursion(L, 0, len(L) - 1)


def QuickRecursion(L: list, start, end):
    if start >= end:
        return
    pivot = QuickSortPivot(L, start, end)
    QuickRecursion(L, start, pivot - 1)
    QuickRecursion(L, pivot + 1, end)


def QuickSortPivot(L: list, start, end):
    pivot = start
    j = start + 1
    for i in range(start + 1, end + 1):
        if L[i] < L[pivot]:
            L[i], L[j] = L[j], L[i]
            j += 1
    L[pivot], L[j - 1] = L[j - 1], L[pivot]
    pivot = j - 1
    return pivot


# 随机快速排序
def RandomQuickSort(L: list):
    RandomQuickRecursion(L, 0, len(L) - 1)


def RandomQuickRecursion(L: list, start, end):
    if start >= end:
        return
    pivot = RandomQuickSortPivot(L, start, end)
    RandomQuickRecursion(L, start, pivot - 1)
    RandomQuickRecursion(L, pivot + 1, end)


def RandomQuickSortPivot(L: list, start, end):
    import random
    randIndex = random.randint(start, end)
    L[start], L[randIndex] = L[randIndex], L[start]
    pivot = start
    j = start + 1
    for i in range(start + 1, end + 1):
        if L[i] < L[pivot]:
            L[i], L[j] = L[j], L[i]
            j += 1
    L[pivot], L[j - 1] = L[j - 1], L[pivot]
    pivot = j - 1
    return pivot


# 希尔排序
def ShellSort(L: list):
    n = len(L)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            tmp = L[i]
            j = i
            while j >= gap:
                if tmp < L[j - gap]:
                    L[j] = L[j - gap]
                else:
                    break
                j -= gap
            L[j] = tmp
        gap //= 2


# 堆排序
def HeapSort(L: list):
    heap = [None] + L  # heap 从 1 开始遍历,list 从 0 开始遍历,通过填补实现对接
    root = 1
    for i in range(len(heap) // 2, root - 1, -1):
        maxHeapify(heap, i, len(heap) - 1)
    for i in range(len(heap) - 1, root, -1):
        heap[i], heap[root] = heap[root], heap[i]
        maxHeapify(heap, root, i - 1)
    L[:] = heap[root:]


def maxHeapify(heap: list, start, end):
    son = start * 2
    while son <= end:
        if son + 1 < end and heap[son + 1] > heap[son]:
            son += 1
        if heap[son] > heap[start]:
            heap[start], heap[son] = heap[son], heap[start]
            start, son = son, son * 2
        else:
            break


if __name__ == "__main__":
    l = [34, 3, 16, 8, 2, 23, 12, 9, 21, 5]
    # SelectionSort(l)
    # BubbleSort(l)
    # InsertionSort2(l)
    # print(InsertionSort(l))
    # MergeSort(l)
    # BucketSort(l)
    # CountingSort(l)
    # RadixSort(l)
    # QuickSort(l)
    # RandomQuickSort(l)
    # ShellSort(l)
    HeapSort(l)
    print(l)

参考:@英雄哪里出来 的 B站视频
更多 python 的使用方法和应用,敬请关注后续更新~

你可能感兴趣的:(算法大全,排序算法,python,算法,数据结构)