zoukankan      html  css  js  c++  java
  • python基本算法

    算法优劣评判标准

    时间复杂度:

    定义:用来评估算法运行效率的一个式子

    print('Hello World')  O(1)
    
    for i in range(n):
    	print('Hello World')  O(n)
    
    for i in range(n):
    	for j in range(n):
    		print('Hello World')  O(n^2)
    
    for i in range(n):
    	for j in range(n):
    		for k in range(n):
    			print('Hello World')  O(n^3)
    
    注:O(1)、O(n)、O(n2)..是一个单位,且当n足够大时,n2的值可以忽略n的大小,所以计算时间复杂度时不会出现O(3)、O(n^2+n)的情况。
    while n>1:
    	print(n)
    	n = n//2
    
    输入:64
    
    输出:  64  32  16  8  4  2
    
    
    计算:2^6=64,执行次数6=log2 64
    
    时间复杂度:O(logn)
    
    小节:

    时间复杂度是用来估计计算法运行时间的一个式子。

    一般来说,时间复杂度高的算法比复杂度低的算法慢。

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

    O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^2logn)<O(n^3)
    

    复杂问题的时间复杂度
    O(n!) O(2^n) O(n^n)

    如何简单快速地判断算法复杂度
    1. 确定问题规模n
    2. 循环减半过程 -》 logn
    3. k层关于n的循环 n^k

    复杂情况:根据算法执行过程判断

    空间复杂度

    定义:用来评估算法内存占用大小的式子

    空间复杂的表示方式与实践复杂度完全一样

    算法使用了几个变量:O(1)
    
    算法使用了长度为n的一位列表:O(n)
    
    算法使用了m行n列的二维列表:O(mn)
    

    空间换时间

    递归算法

    递归的两个特点:

    1. 调用自身
    2. 结束条件

    递归:汉诺塔问题

    def hanoi(n,a,b,c):
        if n>0:
            hanoi(n-1,a,c,b)
            print("moving [%s] from %s to %s" %(n,a,c))
            hanoi(n-1,b,a,c)
    
    hanoi(3,"a","b","c")
    

    查找问题

    查找:在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程

    列表查找(线性表查找):从列表中产兆指定元素

      输入:列表、待查找元素

      输出:元素下表(未找到元素之一般返回None或-1)

    内置列表查找函数:index()

    方法一:顺序查找

    顺序查找:也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止。

    # 顺序查找
    def linear_search(li,val):
        for i,v in enumerate(li):
            if v == val:
                return i
        else:
            return None
    
    #i = linear_search([1,2,3,6,7],6)
    #print(i)
    

    复杂度:O(n)

    方法二:二分查找

    二分查找:又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半。

    # 二分法查找
    def binary_search(li,val):
        left,right = 0,len(li)-1
        while left<=right:  # 候选区有值
            mid = (left+right)//2
            if li[mid]==val:
                return mid
            elif li[mid]<val:
                left = mid+1
            else:
                right = mid=1
        else:
            return None
    
            
    i = binary_search([1,2,3,6,7],10)
    print(i)
    

    复杂度:O(logn)

    对比:使用二分查找的速度远远大于顺序查找,但是二分查找只能应用于线性排序的列表。

    列表排序

    排序:将一组“无序”的记录序列调整为“有序的记录序列”。

    列表排序:将无序列表变为有序列表

      输入:列表

      输出:有序列表

    升序和降序

    内置排序函数:sort()

    冒泡排序

    列表每两个相邻的数,如果前面比后面大,则交换这两个数。

    一趟排序完成后,则无序区减少一个数,有序区增加一个数。

    代码关键:趟,无序区范围。

    #冒泡排序
    
    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]
    import random
    
    li = [random.randint(1,1000) for _ in range(30)]
    print(li)
    bubble_sort(li)
    print(li)
    

    时间复杂度:O(n^2)

    优化冒泡排序
    #冒泡排序,当列表不再改变时 无需再循环
    
    def bubble_sort(li):
        for i in range(len(li)-1):
            exchange = 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]
                    exchange = True
            print(li)
            if not exchange:
                return
    
            
    import random
    
    li = [1,2,3,7,6,8,9]
    print(li)
    bubble_sort(li)
    

    选择排序

    每次选出列表中最大值或者最小值,放在列表的首位或者末尾。

    def select_sort(li):
        for i in range(len(li)-1):
            min_loc = i
            for j in range(i+1,len(li)):
                if li[j]<li[min_loc]:
                    min_loc = j
            li[min_loc],li[i] = li[i],li[min_loc]
    
    li = [1,2,3,7,6,8,9]
    print(li)
    select_sort(li)
    print(li)
    

    插入排序

    拿到手里的牌和之前的所有牌比较,如果比之前的牌小,则记录该位置,最后记录的值就是手里的牌正确排序后的位置。

    def insert_sort(li):
        for i in range(len(li)):
            tmp = li[i]
            j = i - 1  # 候选区开头索引-1 就是有序区的结尾
            while j >= 0 and tmp < li[j]:
                li[j + 1] = li[j]
                j -= 1
            li[j + 1] = tmp
    
    
    li = [9, 5, 6, 7, 3]
    insert_sort(li)
    

    快速排序

    快速排序:快

    快速排序思路:

      取一个元素p(第一个元素),使元素p归位;

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

      递归完成排序。

    def partition(li,left,right):
        temp = li[left]
        while left < right:
            while left < right and li[right] >= temp:
                right -= 1
            li[left] = li[right]
            while left < right and li[left] <= temp:
                left += 1
            li[right] = li[left]
        li[left] = temp
        return left
    
    
    def quick_sort(li,left,right):
        if left<right:
            mid = partition(li,left,right)
            quick_sort(li,left,mid-1)
            quick_sort(li,left+1,right)
    
    li = [9,4,3,6,8,15,3,31]
    quick_sort(li,0,len(li)-1)
    print(li)
    

    快速排序的效率:

      快速排序的时间复杂度 O(mlogn)

    快速排序的问题:

      最坏情况
      递归

    堆排序

    树与二叉树

    堆是一种特殊的完全二叉树

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

    堆的向下调整:
      假设:节点的左右子树都是堆,但是自身不是堆。

    堆排序过程

    堆排序过程:

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

    堆的向下调整

    向下调整函数

    def sift(li,low,high):
        i = low
        tmp = li[i]
        j = i*2+1
        while j<=high:
            if j<high and li[j+1]>li[j]:
                j = j+1
            if tmp<=li[j]:
                li[i]=li[j]
                i = j
                j = i*2+1
            else:
                break
        li[i] = tmp
    li = [1,9,8,7,6,5,0,2]
    sift(li,0,len(li)-1)
    print(li)
    

    堆排序函数

    def heap_sort(li):
        n = len(li)
        # 建堆
        for i in range(n//2-1,-1,-1):
            sift(li,i,n-1)
        # 建堆完成
        for i in range(n-1,-1,-1):
            li[i],li[0]=li[0],li[i]
            sift(li,0,i-1)
    
    li = [2,6,4,6,8,5,3,10]
    heap_sort(li)
    print(li)
    
    堆排序的内置模块heapq
    import heapq
    import random
    li = list(range(100))
    random.shuffle(li)
    heapq.heapify(li)
    print(li)
    for i in range(len(li)-1):
    	print(heapq.heappop(li),end=' ')
    

    归并排序

    假设li是以mid为分界线的左右两边都是正序列表的列表

    从头比较两边分列表的值,较小的取出放在新列表里,再比较该分列表下一个值和另一列表的当前值大小

    def merge(li, low, mid, high):
        i = low
        j = mid + 1
        ltmp = []
        while i <= mid and j <= high:
            if li[i] < li[j]:
                ltmp.append(li[i])
                i += 1
            else:
                ltmp.append(li[j])
                j += 1
        li[low:high + 1] = ltmp + li[i:mid + 1] + li[j:high + 1]
    
    def merge_sort(li, low, high):
        if low < high:
            mid = (low + high) // 2
            merge_sort(li, low, mid)
            merge_sort(li, mid + 1, high)
            merge(li, low, mid, high)
    
    li = [3, 6, 4, 5, 8, 1, 2, 9, 0, 7]
    merge_sort(li, 0, len(li) - 1)
  • 相关阅读:
    CCF-CSP201512-3 画图
    CCF-CSP201512-2 消除类游戏
    CCF-CSP201606-4 游戏(BFS)
    CCF-CSP201604-2 俄罗斯方块
    HDU1035 Robot Motion(dfs)
    Java Srting之Calendar日历类(五)——Calendar中计算时间的方法add()
    java如何获取当前日期和时间
    double 类型怎样不用科学计数法表示并且使用Java正则表达式去掉Double类型的数据后面多余的0
    @SpringBootApplication(exclude={DataSourceAutoConfiguration.class})注解作用
    java.util.Date.toString()方法实例
  • 原文地址:https://www.cnblogs.com/LTEF/p/9757064.html
Copyright © 2011-2022 走看看