• 算法基础


    一、什么是算法

      算法:一个计算过程,解决问题的方法。

      程序 = 数据结构 + 算法

    二、时间复杂度

      时间复杂度:用来评估算法效率的一个东西

    print('Hello World!')        O(1)
    
    for i in range(n):            O(n)
        print('Hello World!')     
    
    for i in range(n):            O(n²)
        for j in range(n):    
            print('Hello World!') 
    
    for i in range(n):            O(n³)
        for j in range(n):    
            for k in range(n):
                print('Hello World!') 

    while n>1:            O(log₂n)或者O(logn)
    print(n)
    n= n//2

      时间复杂度是用来估计算法运行时间的一个式子(单位),一般来说,时间复杂度高的算法比复杂度低的算法慢

      常见的时间复杂度(按效率排序)

        O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n²logn)<O(n³)

      不常见的的时间复杂度:O(n!),O(2ⁿ),O(nⁿ)

     如何快速的判断时间复杂度:

      1.循环减半的过程     O(logn)

      2.几层循环就是n的几次方的复杂度

    三、空间复杂度

      空间复杂度:用来评估算法内存占用大小的一个式子

      因为内存空间越来越大,相应时间要求越来越高,一般采用‘空间换时间’作为基本策略

    四、列表查找

      列表查找:从列表中查找指定元素的索引/下标      输入:列表和要查找的元素    输出:索引/下标/未找到

      列表的查找分为:顺序查找和二分查找

        1.顺序查找:从列表的第一个元素进行查找,顺序搜索,直到找到位置 (时间复杂度为O(n))

        2.二分查找:从有序列表的候选区开始,通过比对查找值和候选区中间的的大小,渐渐缩小候选区大小,即查找范围逐步缩小  (时间复杂度为O(logn))

    例子: 代码实现顺序列表中查找某个值所在的索引位置。

    li = list(range(200,100000,10))
    def bin_search(li,value):
        low = 0
        high = len(li) -1
        while low <= high:
            mid = (low + high) // 2
            if li[mid] > value:
                high = mid - 1
            elif li[mid] < value:
                low = mid + 1
            else:
                return mid
        return None
    
    if __name__ == '__main__':
        mid = bin_search(li,10001)
        print(mid)
        if mid:
            print(li[mid])
    使用while实现
    # 使用递归实现
    li = list(range(200,100000,10))
    def bin_search(li,value,low=0,high=len(li)-1):
        mid = (low + high) // 2
        if low <= high and li[mid] > value:
            return bin_search(li,value,low,mid-1)
        elif low <= high and li[mid] < value:
            return bin_search(li,value,mid+1,high)
        elif li[mid] == value:
            return mid
        else:
            return None
    
    if __name__ == '__main__':
        mid = bin_search(li,1000)
        print(mid)
        if mid:
            print(li[mid])
    使用递归实现

    备注:假设排序的时间复杂度为O(nlogn),如果对列表进行一次查找建议使用顺序查找,需要对列表进行多次查找操作建议先排序,后反复进行二分查找。

    五、列表排序

    排序方法:冒泡排序、选择排序、插入排序、快速排序、堆排序、归并排序、希尔排序

      1.冒泡排序(时间复杂度O(n²))

        原理:一趟分别两两比较大小,一趟结束后无序区中最大的元素放到无序区的最后,也是有序区的最前。

    import random
    def bubble_sort(li):
        for i in range(len(li)-1):    # 趟数
            for num in range(len(li)-i-1):
                if li[num]>li[num+1]:
                    li[num],li[num+1] = li[num+1],li[num]
    
    
    if __name__ == '__main__':
        li = list(range(50, 10000, 3))
        random.shuffle(li)
        bubble_sort(li)
        print(li)
    冒泡排序代码

       冒泡排序优化:在执行排序的一趟中没有进行交换,则此时序列以及是有序,可以直接结算算法。(时间复杂度O(n²))

      2.选择排序

        原理:一趟遍历最小的元素放到第一个位置,反复进行

    import random
    def select_sort(li):
        for i in range(len(li)-1):  # 这里的-1表示最后一个可以不用进行排序
            mid = i
            for j in range(i+1,len(li)):  # 这里没有-1
                if li[mid] > li[j]:
                    mid = j
            li[i],li[mid] = li[mid],li[i]
    if __name__ == '__main__':
        li = list(range(50, 1000, 1))
        random.shuffle(li)
        select_sort(li)
        print(li)
    选择排序

      3.插入排序(时间复杂度O(n²))

        要点: 每次取出的牌和手中有序的牌

    # 插入排序
    import random
    def inster_sort(li):
        for i in range(1,len(li)):
            j = i-1
            mid = li[i]   # 拿到的牌
            while j >= 0 and mid < li[j]:
                li[j+1] = li[j]
                j -= 1
            li[j+1] = mid
    
    if __name__ == '__main__':
        li = list(range(50, 100000, 13))
        random.shuffle(li)
        inster_sort(li)
        print(li)
    插入排序

    小结:冒泡排序,选择排序,插入排序   

          时间复杂度O(n²)

          空间复杂度O(1)

      4.快速排序  事件复杂度O(nlogn)

        快速排序思路:一、取一个元素P(第一个元素),使元素p归位;

               二、列表被p分成两部分,左边都比p小,右边都比p大;  

               三、递归完成排序;(即整理和递归)

    # 快速排序
    import random
    def partiton(li,low,high):
        mid = li[low]
        while low < high:
            while low < high and li[high] >= mid:
                high -= 1
            li[low] = li[high]
            while low < high and li[low] <= mid:
                low += 1
            li[high] = li[low]
        li[low] = mid
        return low
    
    def quick_sort(li, low, high):
        if low < high:
            mid = partiton(li,low,high)
            quick_sort(li,low,mid-1)
            quick_sort(li,mid+1,high)
    
    if __name__ == '__main__':
        li = list(range(0, 1000000))
        random.shuffle(li)
        quick_sort(li, 0, len(li)-1)
        print(li)
    快速排序

    快速排序存在两个问题:

      1.最坏情况

      2.递归最大深度    通过sys.setrecursionlimit(100)可以设置递归深度

    解决办法:

      1.随机生成比对值版本的快速排序,即:不取第一个值作为对比值,使用列表中随机的值来先和第一值进行交换,然后在继续进行操作。存在最坏情况,只是没法人为设计出来。

    六、高级排序

    堆排序

      堆排序基础:

      树: 树是一种数据结构   比如:目录结构

        树的基本概念:根节点,叶子节点,树的深度(高度),树的度,孩子节点,父节点,子树。

      二叉树:度不超过2的树(节点最多有两个叉)

        满二叉树:除最后一层无子节点外,每一层上的所有结点都有两个子结点二叉树。

        完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

      二叉树的存储方式:

        链式存储和顺序存储

      堆排序:

        大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大。

        小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小。

      堆排序过程:

        1.建立堆。

        2.得到堆顶元素,为最大元素。

        3.去掉堆顶,将对最后一个元素放到堆顶,此时可通过一次调整重新使堆有序。

        4.堆顶元素为第二大元素。

        5.重复步骤3,直到堆变为空。

      堆排序注意事项:

        1.在调整各个子树的时候,子节点的位置可以方便的设置为整个树最有一个节点。(重要)

      堆排序代码:

    # 向下调整
    def sift(li, low, high):
        i = low
        j = 2 * i + 1
        tmp = li[low]
        while j <= high:
            if j + 1 <= high and li[j] < li[j + 1]:
                j = j + 1
            if tmp < li[j]:
                li[i] = li[j]
                i = j
                j = 2 * i + 1
            else:
                break
        li[i] = tmp
    
    
    def heap_sort(li):
        for i in range(len(li) // 2 - 1, -1, -1):  # 依次调整每棵子树
            sift(li, i, len(li) - 1)
        for i in range(len(li) - 1, -1, -1):    # 挨个出数
            li[0],li[i] = li[i],li[0]
            sift(li, 0, i - 1)
    
    if __name__ == '__main__':
        li = [6, 8, 1, 9, 3, 0, 7, 2, 4, 5]
        heap_sort(li)
        print(li)
    # 堆排序
    def sift(list_obj, low, high):  # 调整树
        tmp = list_obj[low]
        i = low
        j = 2 * i + 1
        while j <= high:
            if j < high and list_obj[j] < list_obj[j + 1]:
                j = j + 1
            if tmp < list_obj[j]:
                list_obj[i] = list_obj[j]
                i = j
                j = 2 * i + 1
            else:
                break
        list_obj[i] = tmp
    
    
    def heap_sort(list_obj):
        for i in range(len(list_obj) // 2 - 1, -1, -1):  # 调整各个子树
            sift(list_obj, i, len(list_obj) - 1)
        for i in range(len(list_obj) - 1, -1, -1):  # 大的数换到最后,继续调整树
            list_obj[0], list_obj[i] = list_obj[i], list_obj[0]
            sift(list_obj, 0, i - 1)
    
    
    if __name__ == '__main__':
        list_obj = [6, 8, 1, 9, 3, 0, 7, 2, 4, 5]
        heap_sort(list_obj)
        print(list_obj)
    堆排序
  • 相关阅读:
    python_元素定位
    python_html_初识
    python_selenium_初识
    python_jenkins_集成
    python_正则表达式_re
    python_接口关联处理与pymysql中commit
    python_json与pymsql模块
    python_接口请求requests模块
    Codeforces Round #656 (Div. 3) D. a-Good String
    Codeforces Round #656 (Div. 3) C. Make It Good
  • 原文地址:https://www.cnblogs.com/40kuai/p/7797170.html
Copyright © 2020-2023  润新知