1. 程式人生 > 實用技巧 >資料結構與演算法-資料結構和演算法概述、評判程式優劣、資料結構

資料結構與演算法-資料結構和演算法概述、評判程式優劣、資料結構

據結構和演算法概述

什麼是電腦科學?

  • 首先明確的一點就是電腦科學不僅僅是對計算機的研究,雖然計算機在科學發展的過程中發揮了重大的作用,但是它只是一個工具,一個沒有靈魂的工具而已。所謂的電腦科學實際上是對問題、解決問題以及解決問題的過程中產生產生的解決方案的研究。例如給定一個問題,電腦科學家的目標是開發一個演算法來處理該問題,最終得到該問題的解、或者最優解。所以說電腦科學也可以被認為是對演算法的研究。因此我們也可以感受到,所謂的演算法就是對問題進行處理且求解的一種實現思路或者思想

如何形象化的理解演算法

  • 一個常勝將軍在作戰之前都會進行戰略的制定,目的是為了能夠在最短的時間切成本消耗最低的情況下獲取最終的勝利。如果將編碼作為戰場,則程式設計師就是這場戰役的指揮官,你如何可以將你的程式可以在最短且消耗資源最小的情況下獲取最終的執行結果呢?演算法就是我們的策略

意義

  • 資料結構和演算法思想的通用性異常的強大,在任何語言中都被使用,它們將會是我們編碼生涯中伴隨我們最長久利器(左膀右臂)。有一定經驗的程式設計師最終拼的就是演算法和資料結構。
  • 資料結構和演算法思想也可以幫助我們拓展和歷練編碼的思維,可以讓我們更好的融入到程式設計世界的角角落落。

什麼是演算法分析?

  • 剛接觸程式設計的學生經常會將自己編寫的程式和別人的程式做比對,獲取在比對的過程中會發現雙方編寫的程式很相似但又各不相同。那麼就會出現一個有趣的現象:兩組程式都是用來解決同一個問題的,但是兩組程式看起來又各不相同,那麼哪一組程式更好呢?
  • a+b+c = 1000 ,a2 + b
    2 = c**2 (a,b,c均為自然數),求出a,b,c可能的組合?
# 方式一:耗時特別長
for a in range(0,1001):
    for b in range(0,1001):
        for c in range(0,1001):
            if a+b+c == 1000 and a**2+b**2 == c**2:
                print(a,b,c)

# 方式二:耗時特別短
for a in range(0,1001):
    for b in range(0,1001):
        c = 1000-a-b
        if a+b+c == 1000 and
a**2+b**2 == c**2: print(a,b,c) 0 500 500 200 375 425 375 200 425 500 0 500

評判程式優劣的方法

  • 消耗計算機資源和執行效率(不推薦,無法直觀)
  • 計算演算法執行的耗時(適當推薦,因為會受機器和執行環境的影響)
  • 時間複雜度(推薦)

時間複雜度

  • 評判規則:量化演算法執行的操作/執行步驟的數量
  • 最重要的項:時間複雜度表示式中最有意義的項
  • 時間複雜度的表現形式:大O記法
    • O(最有意義的項)
    • 常見的時間複雜度:
      • O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

def sumOfN(n):
    theSum = 0   # 執行步驟 1 次
    for i in range(1,n+1):
        theSum = theSum + i # 執行步驟 n 次

    return theSum 

print(sumOfN(10))
# 總的執行步驟 n+1 次
# O(n)  括號內放計算執行步驟最有意義的項
# 這串程式碼執行的演算法數量為O(n)


a=5
b=6
c=10
# 3
for i in range(n):
   for j in range(n): # 3*n**2
      x = i * i
      y = j * j
      z = i * j

for k in range(n): # 2*n
   w = a*k + 45
   v = b*b

d = 33 # 1
# 4+2n+3n**2
# O(n**2)

計算演算法執行的耗時

目標

本節的目標是告訴大家Python列表和字典操作的 大O 效能。然後我們將做一些基於時間的實驗來說明每個資料結構的花銷和使用這些資料結構的好處

實操

  • 在列表的操作有一個非常常見的程式設計任務就是是增加一個列表。我們馬上想到的有兩種方法可以建立更長的列表,可以使用 append 方法或拼接運算子。但是這兩種方法那種效率更高呢。這對你來說很重要,因為它可以幫助你通過選擇合適的工具來提高你自己的程式的效率。
  • 例項化一個空列表,然後將0-n範圍的資料新增到列表中。(四種方式)
  • timeit模組:該模組可以用來測試一段python程式碼的執行速度/時長。

  • Timer類:該類是timeit模組中專門用於測量python程式碼的執行速度/時長的。原型為:class timeit.Timer(stmt='pass',setup='pass')。

    • stmt引數:表示即將進行測試的程式碼塊語句。

    • setup:執行程式碼塊語句時所需要的設定。

    • timeit函式:timeit.Timer.timeit(number=100000),該函式返回程式碼塊語句執行number次的平均耗時。

def test01():
    alist = []
    for i in range(1000):
        alist.append(i)

def test02():
    alist = []
    for i in range(1000):
        alist = alist + [i]

def test03():
    alist = [i for i in range(1000)]

def test04():
    alist = list(range(1000))

#四種方式中哪種方式新增列表元素的效率最高呢?

from timeit import Timer
if __name__ == '__main__':

    t1 = Timer('test01()','from __main__ import test01')
    print(t1.timeit(1000))
    t1 = Timer('test02()','from __main__ import test02')
    print(t1.timeit(1000))
    t1 = Timer('test03()','from __main__ import test03')
    print(t1.timeit(1000))
    t1 = Timer('test04()','from __main__ import test04')
    print(t1.timeit(1000))


0.0860275
1.4280624
0.03301989999999999
0.014072400000000096

資料結構

  • 概念:對於資料(基本型別的資料(int,float,char))的組織方式就被稱作為資料結構(一個載體或容器)。資料結構解決的就是一組資料如何進行儲存,儲存形式是怎樣的

案例: 需要儲存一些學生的學生資訊(name,score),那麼這些資料應該如何組織呢?查詢某一個具體學生的時間複雜度是什麼呢?(三種組織方式)

# 方式一 需要遍歷才能找到目標資訊  時間複雜度為O(n)
[{
    'name':'xxx',
    'score':'xxx'
},{
    'name':'xxx',
    'score':'xxx'
},{
    'name':'xxx',
    'score':'xxx'
}]

[{'name': 'xxx', 'score': 'xxx'},
 {'name': 'xxx', 'score': 'xxx'},
 {'name': 'xxx', 'score': 'xxx'}]

# 方式二:同上 時間複雜度為O(n)
[
    ('name','score'),
    ('name','score'),
    ('name','score')
]

[('name', 'score'), ('name', 'score'), ('name', 'score')]

# 方式三:可直接按照KEY找到目標資訊 時間複雜度為O(1)
{
    'zhangsan':{'score':'xxx'},
    'lisi':{'score':'xxx'}
}

{'zhangsan': {'score': 'xxx'}, 'lisi': {'score': 'xxx'}}