在路上---学习篇,一Python 数据结构和算法 (4 --希尔排序、归并排序

独白

  希尔排序是经过优化的插入排序算法,之前所学的排序在空间上都是使用列表本身。而归并排序是利用增加新的空间,来换取时间复杂度的减少。这俩者理念完全不一样,注定造成的所消耗的时间不同以及空间上的不同。

  归并排序涉及到递归的使用,需要理解其中精髓才能更好了解归并排序,以及其他应用到递归的算法。理解其本质才能更好的应用。


希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

时间复杂度

  • 最优时间复杂度:根据步长序列的不同而不同
  • 最坏时间复杂度:O(n2)
  • 稳定想:不稳定
"""
希尔排序
最优时间复杂度: 根据步长序列不同而不同
最坏时间复杂度: O(n*n)
稳定性 : 不稳定
"""

import time
import random


def shell_sort(list):
    n = len(list)
    #初始步长
    gap = n // 2
    while gap > 0:
        # 按初始步长进行插入排序
        for j in range(gap, n):
            i = j
            # 插入排序
            while i >= gap and list[i-gap] > list[i]:
                list[i-gap], list[i] = list[i], list[i-gap]
                i -= gap

        # 得到新的步长
        gap = gap // 2


def new_num(lis):
    """随机生成50个数加入列表中"""
    for i in range(50):
        j = random.randint(0, 10000)
        lis.append(j)

if __name__ == '__main__':
    first_time = time.time()
    # 空列表
    lis = [54,26,93,17,77,31]

    # 随机函数添加到列表中
    # new_num(lis)
    print(lis)

    # 列表排序
    shell_sort(lis)
    print(lis)

    # 结束时间
    last_time = time.time()

    print("共用时%s" % (last_time - first_time))

归并排序

归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

时间复杂度

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(nlogn)
  • 稳定性:稳定
"""
归并排序
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
稳定性:稳定


与其他排序区别
利用一个新列表讲算法排序后的元素储存当中
空间换时间
"""

import time
import random


def merge_sort(list):
    """归并排序"""
    n = len(list)
    if n <= 1:
        return list
    # 最大整除
    mid = n // 2
    # left 利用递归  截取的列表形成的有序列表
    left_list = merge_sort(list[:mid])
    # right 利用递归  截取的列表形成的有序列表
    right_list =merge_sort(list[mid:])
    # 创建 左右游标记录列表值的索引
    left_pointer, right_pointer = 0,0
    # 创建新空列表
    result = []
    # 循环 比较数值大小
    # 退出循环条件 当左右游标其中一个等于所在列表的长度时
    while left_pointer < len(left_list) and right_pointer < len(right_list):
        # 判断 左值和右值大小
        if left_list[left_pointer] <= right_list[right_pointer]:
            result.append(left_list[left_pointer])
            # 每判断一次 游标加一
            left_pointer += 1
        else:
            result.append(right_list[right_pointer])
            right_pointer += 1
    # 将最后一个数值加入新列表中
    result += left_list[left_pointer:]
    result += right_list[right_pointer:]
    # 返回值
    return result


def new_num(lis):
    """随机生成50个数加入列表中"""
    for i in range(50):
        j = random.randint(0, 100)
        lis.append(j)

if __name__ == '__main__':
    first_time = time.time()
    # 空列表
    lis = []

    # 随机函数添加到列表中
    new_num(lis)
    print(lis)

    # 列表排序
    # 因为归并排序最后是返回一个新列表,所以打印输出为新列表
    alist = merge_sort(lis)
    print(alist)

    # 结束时间
    last_time = time.time()

    print("共用时%s" % (last_time - first_time))