zoukankan      html  css  js  c++  java
  • Python

    插入排序

    算法分析

    两次循环, 大循环对队列中的每一个元素拿出来作为小循环的裁定对象

    小循环对堆当前循环对象在有序队列中寻找插入的位置

    性能参数

    空间复杂度  O(1)

    时间复杂度  O(n^2)

    详细代码解读

    import random
    
    
    def func(l):
        # 外层循环: 对应遍历所有的无序数据
        for i in range(1, len(l)):
            # 备份 取出数据
            temp = l[i]
            # 记录取出来的下标值
            pos = i
            # 内层循环: 对应从后往前扫描所有有序数据
            """
            i - 1  >   从最后一个有序数据开始, 即无序数据前一位
            -1  >   扫描到下标 0 为止, 要包括第一个, 因此设置 -1 往后推一位
            -1  >   从后往前扫描
            """
            for j in range(i - 1, -1, -1):
                # 若有序数据 大于 取出数据
                if l[j] > temp:
                    # 有序数据后移
                    l[j + 1] = l[j]
                    # 更新数据的插入位置
                    pos = j  # 对应所有有序数据比取出数据大的情况
                    # 若有序数据 小于/等于  取出数据
                else:
                    pos = j + 1
                    break
            # 在指定位置插入数据
            l[pos] = temp
    
    
    if __name__ == '__main__':
        l = list(range(1, 13))
        random.shuffle(l)
        func(l)
        print(l)

    简单实例

    import random
    
    
    def foo(l):
        for i in range(1, len(l)):
            temp = l[i]
            pos = i
            for j in range(i - 1, -1, -1):
                if temp < l[j]:
                    l[j + 1] = l[j]
                    pos = j
                else:
                    pos = j + 1
                    break
    
            l[pos] = temp
        return l
    
    
    if __name__ == '__main__':
        l = list(range(13))
        random.shuffle(l)
        print(l)  # [12, 0, 4, 5, 6, 2, 11, 10, 8, 7, 3, 1, 9]
        print(foo(l))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    冒泡排序

    算法分析

    两两比较, 每次比较出一个未排序队列的最大值,让只在队列右侧排列

    两次循环, 大循环每次输出一个当前最大值. 

    小循环进行具体的数值比对

    性能参数

    空间复杂度  O(1)

    时间复杂度  O(n^2)

    详细代码

    """
    入学后, 第一次上体育课, 体育老师要求大家排队, 按照身高从低到高排队
    获取全班 10 名同学的身高
    """
    
    """
    外层循环
        大循环控制总循环次数                    
    内层循环
        小循环控制如歌得出这个最大值
            计算大小, 然后彼此交换
    """
    
    import random
    
    """
    基础版
    """
    
    
    def func(l):
        # 外层循环: 走访数据的次数
        for i in range(len(l) - 1):
            # 内层循环: 每次走访数据时, 相邻对比次数
            for j in range(len(l) - i - 1):
                # 要求从低到高
                # 如次序有误就交换
                if l[j] > l[j + 1]:
                    l[j], l[j + 1] = l[j + 1], l[j]
    
        # 遍历次数
        print("走访次数:", i + 1)
    
    
    """
    升级版
    """
    
    
    def foo(l):
        # 外层循环: 走访数据的次数
        for i in range(len(l) - 1):
            # 设置是否交换标志位
            flag = False
            # 内层循环: 每次走访数据时, 相邻对比次数
            for j in range(len(l) - i - 1):
                # 要求从低到高
                # 如次序有误就交换
                if l[j] > l[j + 1]:
                    l[j], l[j + 1] = l[j + 1], l[j]
                    # 发生了数据交换
                    flag = True
            # 如果未发生交换数据, 则说明后续数据均有序
            if flag == False:
                break  # 跳出数据走访
        # 遍历次数
        print("走访次数:", i + 1)
    
    
    if __name__ == '__main__':
        l = list(range(1, 11))
        random.shuffle(l)
        print("排序前:", l)
        # func(l)
        foo(l)
        print("排序后:", l)

    简单代码

    import random
    
    
    def foo(l):
        for i in range(len(l) - 1):
            for j in range(len(l) - i - 1):
                if l[j] > l[j + 1] and j != len(l):
                    l[j], l[j + 1] = l[j + 1], l[j]
    
        return l
    
    
    if __name__ == '__main__':
        l = list(range(13))
        random.shuffle(l)
        print(l)  # [2, 3, 0, 7, 8, 11, 10, 6, 4, 5, 12, 1, 9]
        print(foo(l))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    升级版代码

    import random
    
    
    def foo(l):
        for i in range(len(l) - 1):
            flag = 1
            for j in range(len(l) - i - 1):
                if l[j] > l[j + 1] and j != len(l):
                    l[j], l[j + 1] = l[j + 1], l[j]
                    flag = 0
            if flag:
                break
        return l
    
    
    if __name__ == '__main__':
        l = list(range(13))
        random.shuffle(l)
        print(l)  # [0, 9, 1, 3, 8, 12, 6, 5, 2, 7, 10, 11, 4]
        print(foo(l))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    快速排序

    算法分析

    首先任意取一个元素作为关键数据 ( 通常取首元素

    然后将所有比他小的数据源放在其前面, 所有比它大的放在他后面

    通过一次排序将要排序的数据分为独立的两部分

    然后按照该方法再递归对两部分数据进行快速排序

    性能参数

    时间复杂度  O(nlogn)

    空间复杂度  O(logn)

    稳定性    不稳定

    详细代码

    # 快速排序
    import random
    
    
    def quick(l):
        # 递归退出条件
        # 仅剩一个元素无需继续分组
        if len(l) < 2:
            return l
            # 设置关键数据
        a = l[0]
        # 找出所有比 a 大的数据
        big = [x for x in l if x > a]
        # 找出所有比 a 小的数据
        small = [x for x in l if x < a]
        # 找出所有与 a 相等的数据
        same = [x for x in l if x == a]
        # 拼接数据排序的结果
        return quick(small) + same + quick(big)
    
    
    if __name__ == '__main__':
        l = list(range(1, 25))
        random.shuffle(l)
        l = quick(l)
        print(l)

    二分查找

    算法分析

    只能对有序队列进行查找, 利用和中间值进行对比, 然后基于判断将队列丢弃一半的方式

    性能参数

    时间复杂度  O(log2 n)
    空间复杂度  O(1)

    详细代码

    """
    1. 切分成两部分,取中间值来判断
    2. 如何定义下一次的范围:
        大于中间值, 在左侧找
        小于中间值, 在右侧找
    3. 查找失败情况: 中间值 小于左端 或者 中间值 大于 右端
    """
    
    """
    扑克牌 只取 黑桃 13 张, 用 1-13 表示, 将牌从小到大排序, 反面向上排成一排, 找到黑桃 6 的位置
    """
    
    """
    l   原始数据
    k     待查找数据
    left    首元素下标值
    right   尾元素下标值
    """
    
    """
    递归方式实现
    """
    
    
    def func(l, k, left, right):
        # 递归退出条件
        if left > right:
            # 查找结束
            return -1
        # 获取中间元素对应下标值
        middle = (left + right) // 2
        # 对比中间元素 和 查找元素
        if l[middle] == k:
            return middle
        elif l[middle] > k:
            # 中间值 大于 查找值
            # 查找范围是 中分后的 左边部分
            # 左侧下标值不变, 右侧下标值变为 middle 前一位
            right = middle - 1
            return func(l, k, left, right)
        else:
            # 中间值 小于 查找值
            # 查找范围是 中分后的 右边部分
            # 左侧下标值变为 middle 后一位, 右侧下标值不变
            left = middle + 1
            return func(l, k, left, right)
    
    
    """
    循环方式实现
    """
    
    
    
    def foo(l, k):
        left = 0
        right = len(l) - 1
        while left <= right:
            mid = (left + right) // 2
            if l[mid] > k:
                right = mid - 1
            elif l[mid] < k:
                left = mid + 1
            elif l[mid] == k:
                return midreturn -1
    
    
    if __name__ == '__main__':
        # l = list(range(1, 14))
        # k = 8
        # right = len(l) - 1
        # res = func(l, k, 0, right)
    
        l = list(range(1, 14))
        k = 10
        right = len(l) - 1
        res = foo(l, k)
        if res == -1:
            print("查找失败")
        else:
            print("查找成功, 第 %d 张拿到" % res)

    简单代码

    def foo(l, k):
        left = 0
        right = len(l) - 1
        while left <= right:
            mid = (left + right) // 2
            if l[mid] > k:
                right = mid - 1
            elif l[mid] < k:
                left = mid + 1
            elif l[mid] == k:
                return mid
        return -1
    
    
    if __name__ == '__main__':
        l = list(range(13))
        print(l)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
        print(foo(l, 8))  # 8

    总结

    冒泡排序

    重复走访所有要排序的数据,
    依次比较每两个相邻的元素,
    如果两者次序错误就交换
    重复上面过程 直到没有需要被调换的内容为止

    插入排序

    将数据插入到已经有序的数据中, 从而得到一个新的有序数据

    默认首元素自然有序, 取出下一个元素, 对已经有序的数据从后向前扫描

    若扫描的有序数据大于取出数据, 则该有序数据后移

    若扫描的有序数据小于取出数据, 则在该有序数据后插入取出数据

    若扫描的所有的有序数据大于取出数据, 则在有序数据的首位插入取出数据

    特点

    数据只移动不交换, 优于冒泡

    快速排序

    首先任意取一个元素作为关键数据 ( 通常取首元素 )

    然后将所有比他小的数据源放在其前面

    (从小到大)所有比它大的放在他后面

    通过一次排序将要排序的数据分为独立的两部分

    然后按照该方法再递归对两部分数据进行快速排序

    特点

    每次若能均匀分组则排序速度最快, 但是不稳定

  • 相关阅读:
    SQL 通配符
    低压电器及其控制
    计算机组成原理
    ASP.NET MVC 4 跨域
    C#排序算法小结
    C# 集合扩展快速排序算法
    C# 排序算法记录
    文件大小
    ProcDump
    C# 获取文件MD5校验码
  • 原文地址:https://www.cnblogs.com/shijieli/p/10922566.html
Copyright © 2011-2022 走看看