一、什么是數據結構
數據結構就是把數據組織起來,為了更方便地使用數據
我們為了解決問題,需要將數據保存下來,然后根據數據的存儲方式來設計算法實現進行處理,那么數據的存儲方式不同就會導致需要不同的算法進行處理。我們希望算法解決問題的效率越快越好,於是我們就需要考慮數據究竟如何保存的問題,這就是數據結構。
數據結構的概念:
數據結構是計算機存儲、組織數據的方式。數據結構是指相互之間存在一種或多種特定關系的數據元素的集合。
二、數據結構與算法作用
程序運行的效率和開銷
遇到性能瓶頸,如何優化性能
程序 = 數據結構 + 算法
三、算法的概念和五大特性
算法的概念:
算法是計算機處理信息的本質,因為計算機程序本質上是一個算法來告訴計算機確切的步驟來執行一個指定的任務。一般地,當算法在處理信息時,會從輸入設備或數據的存儲地址讀取數據,把結果寫入輸出設備或某個存儲地址供以后再調用。
算法是獨立存在的一種解決問題的方法和思想。
算法的五大特性:
1、輸入:算法具有0個或多個輸入
2、輸出:算法至少有1個或多個輸出
3、有窮性:算法在有限的步驟之后會自動結束而不會無限循環,並且每一個步驟可以在可接受的時間內完成
4、確定性:算法中的每一步都有確定的含義,不會出現二義性
5、可行性:算法的每一步都是可行的,也就是說每一步都能夠執行有限的次數完成
四、算法效率的衡量
實現算法程序的執行時間可以反映出算法的效率,即算法的優劣。但是單純依靠運行時間來比較算法的優劣並不一定是客觀准確的
時間頻度:一個算法花費的時間與算法中語句的執行次數成正比,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度,記為T(n)。n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化
時間復雜度:算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示。如果存在一個整數函數g和實常數c>0,使得對於充分大的n總有T(n)<=c*g(n),就說函數g是T(n)函數的一個漸近函數(忽略常數),記為T(n)=O(g(n)),它稱為算法的漸進時間復雜度,簡稱時間復雜度。這種用O()來體現算法時間復雜度的記法,我們稱為大O表示法。
時間復雜度的分類:
1、最優時間復雜度:算法完成工作最少需要多少基本操作,其反映的只是最樂觀最理想的情況,沒有參考價值
2、最壞時間復雜度:算法完成工作最多需要多少基本操作,提供了一種保證,表明算法在此種程度的基本操作中一定能完成工作
3、平均時間復雜度:算法完成工作平均需要多少基本操作,沒有保證,會因為應用算法的實例分布可能並不均勻而難以計算
所以,我們主要關注算法的最壞情況,即最壞時間復雜度
時間復雜度的幾條基本計算規則:
1、基本操作,即只有常數項,認為其時間復雜度為O(1)
2、順序結構,時間復雜度按加法進行計算
3、循環結構,時間復雜度按乘法進行計算
4、分支結構,時間復雜度取最大值
5、判斷一個算法的效率時,往往只需要關注操作數量的最高次項,其它次要項和常數項可以忽略
6、在沒有特殊說明時,我們所分析的算法的時間復雜度都是指最壞時間復雜度
空間復雜度:
一個算法的空間復雜度S(n)定義為該算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間復雜度也簡稱為空間復雜度。空間復雜度是對一個算法在運行過程中臨時占用存儲空間大小的量度
對於一個算法,其時間復雜度和空間復雜度往往是相互影響的,大部分時間我們在完成一個程序時采用空間換時間的策略
算法的時間復雜度和空間復雜度合稱為算法的復雜度
五、算法的分析
時間復雜度的計算方法
六、常見時間復雜度
執行次數函數舉例 | 階 | 非正式術語 |
12 | O(1) | 常數階 |
2n+3 | O(n) | 線性階 |
3n2+2n+1 | O(n2) | 平方階 |
5log2n+20 | O(logn) | 對數階 |
2n+3nlog2n+19 | O(nlogn) | nlogn階 |
6n3+2n2+3n+4 | O(n3) | 立方階 |
2n | O(2n) | 指數階 |
注意,經常將log2n(以2為底的對數)簡寫成logn
常見時間復雜度之間的關系
所消耗的時間從小到達:
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
六、Python內置類型性能分析
timeit模塊的使用
1、作用:timeit模塊可以用來測試一小段Python代碼的執行速度。
2、使用的類:
timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)
-
Timer是測量小段代碼執行速度的類。
-
stmt參數是要測試的代碼語句(statment);
-
setup參數是運行代碼時需要的設置;
-
timer參數是一個定時器函數,與平台有關
3、類的方法:
Timer.timeit(number=1000000) Timer類中測試語句執行速度的對象方法
number參數是測試代碼時的測試次數,默認為1000000次。方法返回執行代碼的耗時,一個float類型的秒數。
4、例子:
list的操作測試
def t1(): l = [] for i in range(1000): l = l + [i] def t2(): l = [] for i in range(1000): l.append(i) def t3(): l = [i for i in range(1000)] def t4(): l = list(range(1000)) from timeit import Timer timer1 = Timer("t1()", "from __main__ import t1") print("concat ",timer1.timeit(number=1000), "seconds") timer2 = Timer("t2()", "from __main__ import t2") print("append ",timer2.timeit(number=1000), "seconds") timer3 = Timer("t3()", "from __main__ import t3") print("comprehension ",timer3.timeit(number=1000), "seconds") timer4 = Timer("t4()", "from __main__ import t4") print("list range ",timer4.timeit(number=1000), "seconds") # ('concat ', 1.7890608310699463, 'seconds') # ('append ', 0.13796091079711914, 'seconds') # ('comprehension ', 0.05671119689941406, 'seconds') # ('list range ', 0.014147043228149414, 'seconds')
insert與append比較
def t2(): li = [] for i in range(10000): li.append(i) def t5(): li = [] for i in range(10000): li.insert(0, i) timer2 = Timer('t2()', 'from __main__ import t2') print("append:", timer2.timeit(number=1000)) timer5 = Timer('t5()', 'from __main__ import t5') print("insert:", timer5.timeit(number=1000)) # append: 0.9202240769991477 # insert: 21.039387496999552
從結果可以看出,append從尾端添加元素效率遠遠高於insert從頂端添加元素
list內置操作的時間復雜度
dict內置操作的時間復雜度