1. 程式人生 > >《python演算法筆記》(二)基礎知識

《python演算法筆記》(二)基礎知識

1.計算機的核心概念


  • 圖靈論文《論數字計算在決斷難題中的應用》是現代電腦科學的基石。他提出的圖靈機概念成為了計算機理論的核心概念。
  • 圖靈機(Turing machine):A Turing machine is a simple
    (abstract) device that can read from, write to, and move along an infinitely long strip of paper
  • 實際中的機器有所不同,但都叫做有限狀態機(finite state machine).
    有限狀態機(finite state machine):it has a finite set of states (some
    of which indicate that it has finished), and every symbol it reads potentially triggers reading and/or
    writing and switching to a different state. You can think of this machinery as a set of rules.
    這些看似簡單的機器完全的概述了計算機的本質。

  • 演算法(Algorithm):An algorithm is a procedure, consisting of a finite set of steps (possibly including loops and
    conditionals) that solves a given problem in finite time.

  • 圖靈機就是一種模型,準確的描述演算法解決問題的過程
    現代計算機用儲存器塊取代了紙帶,就是我們所熟知的記憶體(Random-Access machine)
  • 圖靈機是一種抽象的簡化的標準單處理計算機,並有以下特點:
    1.順序執行
    2.標準的基礎操作(例如算數,比較和記憶體存取)花費常量時間。
    3.計算機位元組(常量時間能夠處理的值得大小)並不是無限制的。
決斷難題(Entscheidungsproblem):David Hilbert提出的問題,是否存在一個演算法來判斷數學陳述的正確性

2.漸進符號


  • O:上界
  • Ω:下界
  • Θ:上下綜合
  • 漸進時間複雜度的常見例子

複雜度 名稱 例子
Θ(1) 常量時 雜湊表的查詢修改
Θ(lgn) 對數 二插樹搜尋
Θ(n) 線性 便利列表
Θ(nlgn) 對數線性 最佳排序演算法
Θ(n2) 二次方 n個物件相互比較
Θ(n3) 三次方 floyd-warshall最短路徑演算法
Θ(nk) 多項式 k層巢狀迴圈
Θ(kn) 指數 處理n個元素的每個子集(k=2)
Θ(n!) 結成 處理n個值的每個順序
  • 三種重要的情況
    1.最佳情況:
    2.最壞情況
    3.平均情況

  • 演算法的經驗評估
    演算法設計的目的是獲得低的漸進執行時間(設計高效的演算法),演算法工程的目的是減少那個漸進複雜度下的隱藏的常量。
    1.先用直接發解決問題,在考慮優化演算法。
    2.使用timeit來計算時間
    3.用分析工具來發現瓶頸
    4.畫下你的結果
    5.在你以執行時間比較為基礎做出結論時要當心隨機誤差。
    for else 結構富國迴圈沒有過早的被break終止,則執行else的子句
  • 3.實現圖和樹

    3.1圖的實現(臨接表/臨接矩陣)

    2-1 A Straightforward Adjacency Set Representation

    a, b, c, d, e, f, g, h = range(8)
    N = [
        {b, c, d, e, f},    # a
        {c, e},             # b
        {d},                # c
        {e},                # d
        {f},                # e
        {c, g, h},          # f
        {f, h},             # g
        {f, g}              # h
    ]

    2-2 Adjacency Lists

    a, b, c, d, e, f, g, h = range(8)
    N = [
        [b, c, d, e, f],    # a
        [c, e],             # b
        [d],                # c
        [e],                # d
        [f],                # e
        [c, g, h],          # f
        [f, h],             # g
        [f, g]              # h
    ]

    2-3 Adjacency dicts with Edge Weights

    a, b, c, d, e, f, g, h = range(8)
    N = [
        {b:2, c:1, d:3, e:9, f:4},    # a
        {c:4, e:3},                   # b
        {d:8},                        # c
        {e:7},                        # d
        {f:5},                        # e
        {c:2, g:2, h:2},              # f
        {f:1, h:6},                   # g
        {f:9, g:8}                    # h
    ]

    2-4 Dict with Adjacency Sets

    N = {
        'a':set('bcdef'),
        'b':set('ce'),
        'c':set('d'),
        'd':set('e'),
        'e':set('f'),
        'f':set('cgh'),
        'g':set('fh'),
        'h':set('fg'),
    }

    2-5 An Adjacency Matrix, Implemented with Nested Lists

    a, b, c, d, e, f, g, h = range(8)
    #     a b c d e f g h
    N = [[0,1,1,1,1,1,0,0],    # a
         [0,0,1,0,1,0,0,0],    # b
         [0,0,0,1,0,0,0,0],    # c
         [0,0,0,0,1,0,0,0],    # d
         [0,0,0,0,0,1,0,0],    # e
         [0,0,1,0,0,0,1,1],    # f
         [0,0,0,0,0,1,0,1],    # g
         [0,0,0,0,0,1,1,0]]    # h

    2-6 A Weight Matrix with Infinite Weight for Missing Edges

    a, b, c, d, e, f, g, h = range(8)
    _ = float('inf')
    #     a b c d e f g h
    W = [[0,2,1,3,9,4,_,_],    # a
         [_,0,4,_,3,_,_,_],    # b
         [_,_,0,8,_,_,_,_],    # c
         [_,_,_,0,7,_,_,_],    # d
         [_,_,_,_,0,5,_,_],    # e
         [_,_,2,_,_,0,2,2],    # f
         [_,_,_,_,_,1,0,6],    # g
         [_,_,_,_,_,9,8,0]]    # h

    3.2樹的實現

    2-7 A Binary Class

    class Tree:
        def __init__(self, left, right):
            self.left = left
            self.right = right
    
    >>> t = Tree(Tree("a", "b"), Tree("c", "d"))
    >>> t.right.left
    'c'

    2-8 A Multiway Tree Class

    class Tree:
        def __init__(self, kids, next=None):
            self.kids = self.val = kids
            self.next = next
    
    >>> t = Tree(Tree("a", Tree("b", Tree("c", Tree("d")))))
    >>> t.kids.next.next.val
    'c'

    Bunch Pattern(一個靈活的類,允許你在構造器中制定任一屬性)

    class Bunch(dict):
        def __init__(self, *args, **kwds):
            super(Bunch, self).__init__(*args, **kwds)
            self.__dict__ = self
    
     >>> T = Bunch
     >>> t = T(left=T(left="a", right="b"), right=T(left="c"))
     >>> t.left
     {'right': 'b', 'left': 'a'}
     >>> t.left.right
     'b'
     >>> t['left']['right']
     'b'
     >>> "left" in t.right
     True
     >>> "right" in t.right
     False

    3.3圖和樹還有其他表示方法,具體的實現要結合具體的問題

    雜湊:為任意一個物件計算出一個整數

    4.小心黑盒子(底層實現)

    如果不知道底層實現可能會增加演算法的時間複雜度。
    例如:

    1.check in list and set

    >>> from random import randrange
    >>> L = [randrange(10000) for i in range(1000)]
    >>> 42 in L
    False
    >>> S = set(L)
    >>> 42 in S
    False
    由於list其實是array,所以對list進行check的時間複雜度是線性的,set是經過雜湊的,所以對lset進行check的時間複雜度是常量時間。
    

    2.構造字串

    >>> s = ""
    >>> for chunk in input():
    ...
    s += chunk

    它起作用,因為在python中做了一些聰明的優化,但是如果到達一定的大小,優化就會崩塌,時間複雜度就會上升到二次方。每一次+=操作都會建立一個新的字串。一個更好的方法是:

    >>> chunks = []
    >>> for chunk in input():
    ...
    chunks.append(chunk)
    ...
    >>> s = ''.join(chunks)

    更進一步的簡化

    >>> s = ''.join(input())

    3.Floats的麻煩
    float的精度不高,在要求高精度的情況下請用decimal