Python 基础排序算法

冒泡排序(bubble sort)

思路

以升序为例:
从第一个数开始向后两两对比,将大的数一直向后移动,直至最大的数移到最后,再找第二大的数
最好情况:O(n)
一般情况:O(n^2)
最坏情况:O(n^2)

代码

import random


def bubble_sort(l):
    for i in range(len(l) - 1):
        exchange = False
        for j in range(len(l) - 1 - i):
            if l[j] > l[j + 1]:
                l[j], l[j + 1] = l[j + 1], l[j]
                exchange = True
        if not exchange:	# 如果一次循环中都没有交换,则说明已经排序完成,可以提前结束
            break


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    bubble_sort(data)
    print(data)

选择排序(selection sort)

思路

以升序为例:
从第一个位置开始向后寻找,找到最小的数,放在这个位置,之后向后移一个位置

时间复杂度

最好情况:O(n^2)
一般情况:O(n^2)
最坏情况:O(n^2)

代码

import random


def selection_sort(l):
    for i in range(len(l) - 1):
        min_num = i
        for j in range(i + 1, len(l)):
            if l[j] < l[min_num]:
                min_num = j
        if min_num != i:
            l[i], l[min_num] = l[min_num], l[i]


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    selection_sort(data)
    print(data)

插入排序(insertion sort)

思路

以升序为例:
将第一个数分为有序队列,后面为无序队列。从二个数开始,依次插入前面有序队列

时间复杂度

最好情况:O(n)
一般情况:O(n^2)
最坏情况:O(n^2)

代码

import random


def insertion_sort(l):
    for i in range(1, len(l)):
        tem = l[i]
        j = i - 1
        while j >= 0 and tem < l[j]:
            l[j + 1] = l[j]
            j -= 1
        l[j + 1] = tem


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    insertion_sort(data)
    print(data)

快速排序(quicksort)

Python 的 sort 时间复杂度为 O(nlogn),但是因为是 C 写的,所以会快

思路

以升序为例:
从第一个数开始,将其他数分成两部分,小于这个数的放在左边,大于这个数的放在右边,分出的左右两边分别继续执行。

时间复杂度

最好情况:O(nlogn)
一般情况:O(nlogn)
最坏情况:O(n^2)

代码

import random


def quick_sort(l, left, right):
    if left < right:
        mid = partition(l, left, right)
        quick_sort(l, left, mid - 1)
        quick_sort(l, mid + 1, right)


def partition(l, left, right):
    tem = l[left]
    while left < right:
        # 一次循环左右各移动一位
        while left < right and l[right] > tem:
            # 当前位不需要换位置,指针向内移动一位,直至遇到需要换位置的位
            right -= 1
        l[left] = l[right]  # 将右边需要换位置的换到左边(取出的数之前的位置)
        while left < right and l[left] < tem:
            left += 1
        l[right] = l[left]
    l[left] = tem
    return left


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    quick_sort(data, 0, len(data) - 1)
    print(data)

堆排序(heapsort)

思路

以升序为例:
借助最大堆(大根堆)的特性,依次取出堆中最大的数(根结点的数),再对堆进行调整

时间复杂度

最好情况:O(nlogn)
一般情况:O(nlogn)
最坏情况:O(nlogn)

代码

import random


def sift(l, low, high):
    i = low     # 指向父节点
    j = 2 * i + 1   # 指向左节点
    tem = l[i]   # 获取父节点的值
    while j <= high:    # 如果子节点在堆中(有子节点)
        if j < high and l[j] < l[j + 1]:  # 有右节点且比左节点大
            j += 1      # 指向右节点
        if tem < l[j]:   # 如果根结点小于子节点中较大的那个
            l[i] = l[j]   # 将较大的值放入父节点
            i = j   # 指向下一层树
            j = 2 * i + 1
        else:
            break
    l[i] = tem   # 将循环开始时的父节点数据写入


def heap_sort(l):
    n = len(l)
    for i in range(n // 2 - 1, -1, -1):
        sift(l, i, n - 1)
        # 堆建好了
    for i in range(n - 1, -1, -1):      # i 指向堆堆最后
        l[0], l[i] = l[i], l[0]     # 将当前最大数移到最后,最后的数移到根结点
        sift(l, 0, i - 1)


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    heap_sort(data)
    print(data)

归并排序(merge sort)

思路

以升序为例:
由于将两个有序列表合并比较简单,所以将列表无限分割成仅有一个元素的有序列表,之后再合并

时间复杂度

最好情况:O(nlogn)
一般情况:O(nlogn)
最坏情况:O(nlogn)

代码

import random


def merge_sort(l, low, high):
    if low < high:
        mid = (low + high) // 2
        merge_sort(l, low, mid)     # 前半部分迭代
        merge_sort(l, mid + 1, high)    # 后半部分迭代
        merge(l, low, mid, high)    # 调整


def merge(l, low, mid, high):
    """
    用于将两个有序列表进行合并
    """
    i = low         # 指向左边有序列表第一个元素
    j = mid + 1     # 指向右边有序列表第一个元素
    tem_l = []      # 临时列表,用于存放合并后列表
    while i <= mid and j <= high:
        # 当左右列表中都有元素时
        if l[i] <= l[j]:
            tem_l.append(l[i])
            i += 1
        else:
            tem_l.append(l[j])
            j += 1
    while i <= mid:
        # 当左边列表中有元素时,直接将剩下的元素全部插入临时列表
        tem_l.append(l[i])
        i += 1
    while j <= high:
        # 当右边列表中有元素时,直接将剩下的元素全部插入临时列表
        tem_l.append(l[j])
        j += 1
    # 用排序完成的元素替代未排序的元素
    l[low:high + 1] = tem_l


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    merge_sort(data, 0, len(data) - 1)
    print(data)

希尔排序(Shell's sort)

思路

以升序为例:
将元素分为n组,每一组进行插入排序,再将每组元素增加直至所有元素都在一组中

时间复杂度

O((1 + τ)n)
一般情况:O(1.3n)

代码

import random


def shell_sort(l):
    gap = len(l) // 2
    while gap > 0:
        for i in range(gap, len(l)):
            tem = l[i]
            j = i - gap     # 指向同组前一个元素
            while j >= 0 and tem < l[j]:    # 存在前一个元素并且比当前元素大
                l[j + gap] = l[j]           # 将前一个元素移到后面一位
                j -= gap                    # 指向前一个元素
            l[j + gap] = tem
        gap //= 2


if __name__ == '__main__':
    data = list(range(1000))
    random.shuffle(data)
    shell_sort(data)
    print(data)

原文地址:https://www.cnblogs.com/dbf-/p/11209193.html