排序算法(Python实现)

*爱你&永不变心* 提交于 2020-01-15 07:20:03

1.冒泡排序

def bubble_sort(lst):
    for i in range(1,len(lst)):  # 第n次循环找到排序后第len(lst)-n+1个位置的值【相对最大值】
        for j in range(0, len(lst)-i):
            if lst[j] > lst[j+1]:
                lst[j+1], lst[j] = lst[j], lst[j+1]
    return lst


print(bubble_sort([0, 5, 2, 1]))

2.选择排序

# 方式:找到len(lst)个相对最小值(两层for循环实现)。
def select_sort(lst):
    for i in range(len(lst) - 1):  # 第n次循环找到排序后第n个位置的值【相对最小值】
        for j in range(i + 1, len(lst)):
            if lst[j] < lst[i]:
                lst[i], lst[j] = lst[j], lst[i]
    return lst


print(select_sort([0, 5, 2, 1]))
1-2.冒泡排序与选择排序的区别
  • 冒泡排序每次外循环结束后,得到一个排序后的最大值。【向左推进】
  • 选择排序每次外循环结束后,得到一个排序后的最小值。【向右推进】
排序方式/ 性质 时间复杂度 空间复杂度 最好情况 最坏情况 稳定排序 原地排序
冒泡排序 O(n2) O(1) O(n) O(n2) 稳定
选择排序 O(n2) O(1) O(n2) O(n2) 不稳定

3.插入排序

简要描述:插入排序过程类似于打扑克时的 理牌 过程。
过程简单描述:
  • 1:循环,从数组第2个元素开始遍历
  • 1.1:循环,找到插入位置(把它与它位置左边的元素做比较)
  • 1.2:循环,腾出插入位置(保存当前需要插入的元素后,使原本插入位置至当前插入元素位置的前一个元素都往后移动一位)
  • 1.3:插入元素至插入位置
def insert_sort(lst):
    # 循环第r次后,前r+1个元素都是有序的。
    for i in range(1,len(lst)):
        insert_ele = lst[i]
        insert_index = i
        # 1.找到插入的位置
        for j in range(i-1, -1,-1):
            if lst[i] < lst[j]:
                insert_index = j
            else:
                break
        # 2.腾出位置给要插入的元素
        for move in range(i-1,insert_index-1,-1):
            lst[move+1] = lst[move]
        # 3.插入元素
        lst[insert_index] = insert_ele
    return lst


print(insert_sort([0, 5, 2, 1]))

4.希尔排序

简要描述:是插入排序的变种,多次分组 + 组内插入排序。
过程简单描述:
  • 1:循环,多次分组。
  • 1.2:循环,在当前分组情况下,对各元素排序。
    各分组都从相对第2个元素开始(gap)元素进行插入排序。
  • 1.2.1:循环,找到插入位置(把它与它位置左边的元素做比较,注意增量为 -gap)
  • 1.2.2:循环,腾出插入位置
  • 1.2.3:插入元素至插入位置
def shell_sort(lst):
    import math
    gap = math.floor(len(lst)/2)
    while gap>=1:
        # 当前分组情况下,对所有组内元素一起插入排序(每个元素在所属组内插入排序)。
        for i in range(gap,len(lst),1):
            insert_item(lst,gap,i)
        gap = math.floor(gap/2)
    return lst

# 各组内排序,增量为gap。组内元素为i-k*gap
def insert_item(lst,gap,i):
    insert_ele = lst[i]
    insert_index = i
    for j in range(i-gap, -gap, -gap):
        if lst[i] < lst[j]:
            insert_index = j
        else:
            break
    for move in range(i - gap, insert_index - gap, -gap):
        lst[move + gap] = lst[move]
    lst[insert_index] = insert_ele

print(shell_sort([0, 5, 2, 1]))
3-4.插入排序和希尔排序比较
排序方式/ 性质 时间复杂度 空间复杂度 稳定排序 原地排序
插入排序 O(n2) O(1)
希尔排序 O(nlogn) O(1)

5.归并排序

基本思想

通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 …… 直到全部小的数组合并起来。

过程简单描述
  • 1.分:将大的数组一直二分,直到数组的大小为1时结束分割。
  • 2.递归治:将左侧数组排成有序。
  • 3.递归治:将右侧数组排成有序。
  • 4.合:将左侧有序数组与右侧有序数组合并成一个新的有序数组。
代码实现
import math


def merge_sort(lst, left, right):
    # 二分至只有一个元素时结束递归分治
    if left < right:
        center = math.floor((right + left) / 2)  # 1.分
        merge_sort(lst, left, center)  # 2.治,结束后左侧数组有序
        merge_sort(lst, center + 1, right)  # 3.治,结束后右侧数组有序
        merge(lst, left, center, right)  # 4.合,将左右两数组合并


def merge(lst, left, center, right):
    pointer_left = left  # 左侧数组指针
    pointer_right = center + 1  # 右侧数组指针
    temp = lst.copy()  # 遍历时修改数组,借用第三者
    for index in range(left, right + 1):
        if pointer_left > center:  # 左边元素全部合并完,剩下有序的右边元素数组赋值即可。
            temp[index:right + 1] = lst[pointer_right:right + 1]
            break
        elif pointer_right > right:  # 右边元素全部合并完,剩下有序的左边元素数组赋值即可。
            temp[index:right + 1] = lst[pointer_left:center + 1]
            break
        # 下面两个case是取两侧数组中最小的元素放入临时数组中,取完后对应指针后移1
        elif lst[pointer_left] < lst[pointer_right]:
            temp[index] = lst[pointer_left]
            pointer_left += 1
        else:
            temp[index] = lst[pointer_right]
            pointer_right += 1
    lst[:] = temp[:]  # 将排序好的临时数组赋给lst。


lst = [0, 5, 2, 1, 7, 0, 9, 3, 4, 8]
merge_sort(lst, 0, len(lst) - 1)
print(lst)

性质
排序方式/ 性质 时间复杂度 空间复杂度 稳定排序 原地排序
归并排序 O(nlogn) O(n) 稳定

6.快速排序

基本思想(分治法+挖坑填数):
  • 先从数列中取出一个数作为基准数。
  • 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  • 再对左右区间重复第二步,直到各区间只有一个数。
代码实现
# 调整序列(选定基准数,把比基准数小的放在基准数的左边,把比基准数大的放在基准数的右边)
def list_adjust(lst, index_left, index_right):
    pointer_left = index_left
    pointer_right = index_right
    refer_num = lst[index_left]  # 选定基准数(并且“挖了一个坑”)
    # 一次循环包括:从右向左前进直到填坑一次,从左向右前进直到填坑一次。
    while pointer_left < pointer_right:
        # 坑在左侧,从右侧开始向左前进,直到右侧数字小于基准数则填坑,坑转移到右侧。
        while pointer_left < pointer_right and lst[pointer_right] >= refer_num:
            pointer_right -= 1
        if pointer_left < pointer_right:
            lst[pointer_left] = lst[pointer_right]  # 用右侧替换左侧
        #  坑在右侧,从左侧开始向右前进,直到左侧数字大于基准数则填坑,坑转移到左侧。
        while pointer_left < pointer_right and lst[pointer_left] < refer_num:
            pointer_left += 1
        if pointer_left < pointer_right:
            lst[pointer_right] = lst[pointer_left]  # 用左侧替换右侧
    lst[pointer_left] = refer_num  # 循环结束,填剩下的左侧坑(其实pointer_left=pointer_right,重合不分左右了)
    return pointer_left


# 分治法
def quick_sort(lst, index_left, index_right):
    if index_left < index_right:
        mid = list_adjust(lst, index_left, index_right)
        quick_sort(lst, index_left, mid - 1)  # 递归对左侧排序
        quick_sort(lst, mid + 1, index_right)  # 递归对右侧排序


if __name__ == '__main__':
    lst = [4, 5, 1, 2, 9]
    quick_sort(lst, 0, 4)
    print(lst)


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!