zoukankan      html  css  js  c++  java
  • Python之算法基础

    概念

    算法(Algorithm):一个计算过程,解决问题的方法

    时间复杂度与空间复杂度

    时间复杂度

    一个算法的优劣可以用时间复杂度与空间复杂度来衡量。

    通常讨论算法的复杂度:1、问题规模相同  2、机器配置相同

    常用大O表示法表示时间复杂性,注意它是某一个算法的时间复杂性。

    如何判断一个算法的时间复杂度

    • 循环减半的过程>>> O(logn)
    • 几次循环就是N的几次方的复杂度

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

    O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

    空间复杂度

    • 用来评估算法内存占用大小的一个式子
    • 算法快总要付出点代价的,利用"空间"来换取"时间"

    列表查找

    指定从一个列表的所有元素中,查找指定的元素

    1、顺序查找(利用Python内置函数index,in操作,for循环机制都可实现)

    2、二分查找(注:前提列表是有序的)

    二分查找又称为半查找, 由上图定义low(最小数索引)high(最大数索引)mid(折半数索引)

    需求:按照上图找到数字3

    • 既然是二分,每一次循环问题规模相应的要减半。mid=(low + high) // 2
    • 如果val(查找数) < mid,即在这个列表二分的左边,high = mid - 1
    • 如果val(查找数) > mid,即反之,low = mid + 1
    def bin_search(data_list, val):
        low = 0                         # 最小数下标
        high = len(data_list) - 1       # 最大数下标
        while low <= high:
            mid = (low + high) // 2     # 中间数下标
            if data_list[mid] == val:   # 如果中间数下标等于val, 返回
                return mid
            elif data_list[mid] > val:  # 如果val在中间数左边, 移动high下标
                high = mid - 1
            else:                       # 如果val在中间数右边, 移动low下标
                low = mid + 1
        return                          # val不存在, 返回None
    
    ret = bin_search(list(range(1, 10)), 3)
    print(ret)
    二分DEMO

    冒泡排序

    冒泡:因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。

    利用相邻元素比较并进行位置的互换...

    需求:一个打乱的列表,进行有效的排序

    相邻两个值进行比较,将较大的值放在右侧,依次比较!(排序好的便不再比较)

    def bubble_sort(li):
        for i in range(len(li) - 1):            # 无需在意最后一个数
            for j in range(len(li) - i - 1):    # 循环的躺数, 每一趟可以排出一个最大数
                if li[j] > li[j+1]:             # 如果当前数大于后面的数, 即调换位置
                    li[j], li[j+1] = li[j+1], li[j]
    
    
    li = list(range(10))
    random.shuffle(li)  # 打乱列表
    bubble_sort(li)
    print(li)
    冒泡DEMO
    def bubble_sort(li):
        for i in range(len(li) - 1):            # 无需在意最后一个数
            go = False                          # 设定一个标识
            for j in range(len(li) - i - 1):    # 循环的躺数, 每一趟可以排出一个最大数
                if li[j] > li[j+1]:             # 如果当前数大于后面的数, 即调换位置, 否则可能是有序的
                    li[j], li[j+1] = li[j+1], li[j]
                    go = True
            if not go:
                return
    
    
    li = list(range(1000))
    random.shuffle(li)  # 打乱列表
    bubble_sort(li)
    print(li)
    优化后的冒泡

    选择排序

    选择:

    • 选择第一个值的索引赋值给特殊变量,然后循环其他索引并进行值的比较,如果循环的值 < 特殊变量对应的值,那么将当前值的索引放入变量中,继续向后比较
    • 选择第二个值的索引赋值给特殊变量,...
    • ...
    def select_sort(li):
        for i in range(len(li) - 1):
            index = i                       # 选择一个数
            for j in range(i+1, len(li)):   # 与i+1之后的每一个数比较
                if li[j] < li[index]:       # 如果之后的每一个数小于标识代表的最小数
                    index = j               # 一直在选择最小数
            li[i], li[index] = li[index], li[i]   # 改变位置
    
    
    li = list(range(10))
    random.shuffle(li)
    select_sort(li)
    print(li)
    选择DEMO

    插入排序

    插入:

    • 列表被分为有序区和无序区两个部分。最初有序区只有一个元素。
    • 每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空
    import random
    
    
    def insert_sort(li):
        for i in range(1, len(li)):   # 从下标1开始
            tmp = li[i]               # 拿出无序区第一个数
            j = i - 1                 # 有序区最大数的下标
            while j >= 0 and tmp < li[j]:  # 条件: 下标j要大于等于0 和 拿出的数小于有序区的最大数
                li[j+1] = li[j]            # 下标j对应的数要往后挪动一个位置
                j = j - 1                  # 有序区下一个元素继续比较
            li[j+1] = tmp  # tmp重新到自己该到的位置
    
    li = list(range(100))
    random.shuffle(li)
    insert_sort(li)
    print(li)
    插入DEMO

    快速排序

    import random
    
    
    def insert_sort(li):
        for i in range(1, len(li)):   # 从下标1开始
            tmp = li[i]               # 拿出无序区第一个数
            j = i - 1                 # 有序区最大数的下标
            while j >= 0 and tmp < li[j]:  # 条件: 下标j要大于等于0 和 拿出的数小于有序区的最大数
                li[j+1] = li[j]            # 下标j对应的数要往后挪动一个位置
                j = j - 1                  # 留出一个位置给tmp
            li[j+1] = tmp  # tmp重新到自己该到的位置
    
    li = list(range(100))
    random.shuffle(li)
    insert_sort(li)
    print(li

    快速:

    • 取一个元素P(第一个元素),使元素P归位
    • 列表被P分成俩部分,左边都比P小,右边都比P大
    • 递归完成排序
    # 降序排列
    
    def quick_sort(li, left, right):
        if left < right:
            mid = partition(li, left, right)
            quick_sort(li, mid + 1, right)
            quick_sort(li, left, mid - 1)
    
    
    def partition(li, left, right):
        tmp = li[left]           # 取出最左边的数
        while left < right:      # 如果 left 与 right 值相等 表示tmp找到正确下标
            while left < right and li[right] <= tmp:  # 和右边的数比较
                right -= 1
            li[left] = li[right]                        
            while left < right and li[left] >= tmp:   # 和左边的数比较
                left += 1
            li[right] = li[left]
        li[left or right] = tmp  # tmp到达指定位置       
        return left or right     # 返回tmp下标
    
    
    data = list(range(10))
    random.shuffle(data)
    quick_sort(data, 0, len(data)-1)
    print(data)
    快排DEMO1
    # 升序排列
    
    def quick_sort(li, left, right):
        i = left
        j = right
        if i >= j:
            return li
        tmp = li[i]
        while i < j:
            while i < j and li[j] >= tmp:
                j -= 1
            li[i] = li[j]
            while i < j and li[i] <= tmp:
                i += 1
            li[j] = li[i]
        li[i] = tmp
        quick_sort(li, left, j-1)
        quick_sort(li, i+1, right)
        return li
    
    data = list(range(10))
    random.shuffle(data)
    quick_sort(data, 0, len(data)-1)
    print(data)
    快排DEMO2

    堆排序

    前传:树与二叉树简介

    • 树是一种数据结构          比如:目录结构
    • 树是一种可以递归定义的数据结构
    • 树是由n个节点组成的集合:
      如果n=0,那这是一棵空树;
      如果n>0,那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树。

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

    • 满二叉树
    • 完全二叉树
    • (完全)二叉树可以用列表来存储,通过规律可以从父亲找到孩子或从孩子找到父亲

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

    那么,堆有一定的规律,如果这个堆是这样的呢

    堆排序过程:

    1. 建立堆
    2. 得到堆顶元素,为最大元素
    3. 去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序
    4. 堆顶元素为第二大元素
    5. 重复步骤3,直到堆变空

    那么依托于这个过程,写一下代码

    import random
    
    
    def sift(data, low, high):
        """
        建堆
        :param data: 
        :param low: 
        :param high: 
        :return: 
        """
        i = low        # 堆的最高位置
        j = 2 * i + 1  # 找左孩子
        tmp = data[i]  # 最高位置对应数值
        while j <= high:  # 孩子是否存在于树内, 一直往下找
            if j+1 <= high and data[j] < data[j+1]:
                # 如果有右孩子并且右孩子比左孩子大
                j = j+1  # j指向右孩子
            if data[j] > tmp:
                # 如果孩子比父亲大
                data[i] = data[j]  # 孩子填充到父亲的空位
                i = j              # 孩子成为新父亲, 父亲成了孩子
                j = 2 * i + 1      # 到下一层的新孩子
            else:
                break
            data[i] = tmp          # 最高领导放到父亲位置
    
    
    def heap_sort(data):
        n = len(data)  # 标识 data 的长度
        # 建立好堆
        for i in range(n//2-1, -1, -1):
            sift(data, i, n-1)
        # 出数
        for i in range(n-1, -1, -1):  # i指向堆的最后
            data[0], data[i] = data[i], data[0]  # 领导退休, 刁民上位
            sift(data, 0, i-1)  # 调整出新领导
    
    
    data = list(range(100))
    random.shuffle(data)
    heap_sort(data)
    print(data)
    堆排序DEMO

    归并排序,希尔排序

    更新中...

  • 相关阅读:
    模拟tap事件和longTap事件
    jquery工具方法总结
    outline:0与outline:none区别
    babel吐槽
    兼容ie8 rgba()写法
    git删除文件夹
    css简写总结
    回调函数实例—(二)
    回调函数的那些事儿(转载)
    回调函数好文章汇总
  • 原文地址:https://www.cnblogs.com/zhangliang91/p/10547708.html
Copyright © 2011-2022 走看看