程序設計=數據結構+算法
數據結構分爲 邏輯結構(面向問題) 和 物理結構(面向計算機)。
1、邏輯結構:數據元素之間的相互關係。
集合結構、線性結構(一對一)、樹形結構(一對多)、圖形結構(多對多)
2、物理結構:數據的邏輯結構在計算機中的存儲形式。
順序存儲結構:
數據元素放在地址連續的存儲單元裏,數據間的邏輯關係和物理關係是一致的。
鏈式存儲結構:
時常要變化的結構,有添加、有刪除。
把數據元素存放在任意存儲單元,存儲單元可以連續可以不連續。
單線聯繫。
數據類型:原子類型、結構類型、抽象數據類型
抽象數據類型(ADT):一個數據對象、數據對象中各數據元素之間的關係 及 對數據元素的操作。
體現了程序設計中問題分解、抽象和信息隱藏的特性。
標準格式:
ADT 抽象數據類型名
Data
數據元素之間邏輯關係的定義
Operation
操作1
初始條件
操作結果描述
操作2
……
操作3
……
endADT
算法:
對合法輸入產生輸出;
對非法輸入產生輸出;
對刁難的測試數據產生輸出。
算法效率的度量:
測定運行時間的可靠方法,計算對運行時間有消耗的的基本操作的執行次數。運行時間與這個計數成正比。
基本操作數量表示成 輸入規模的函數。
函數的漸進增長性。
推斷算法效率時,常數和其他次要項可以忽略,應關注主項(最高階項)的階數。
大O記法:
常數1取代所有加法常數;
修改後的運行次數函數,只保留最高項;
若最高項存在不爲1,取出這個項的係數,變爲1.
最壞時間複雜度,是最重要的需求,一般提到的時間複雜度 都指這個。
平均運行時間 最有意義。
注意到所有的對數只不過相差一個常數,所以這裏都用了常用對數。另外一般程序只處理32位的數據,因此最大整數是2^32-1,大約等於10^9。因此log n可以認爲是近似等於10的常數,也就是說O(log n)的近似等於O(1),O(n * log n)近似等於O(n),這點也在上表中有所反應。
在時間複雜度計算中常見的級別有O(1)< O(log n) < O(n)<O(n * log n) <O(n^k)<O(a^n)<O(n!)<O(n^n),其大小逐級上升.
複雜度舉例:
* O(1) 常數級複雜度,也就是說程序運行的時間與需要處理的數據大小無關。通常把比較大小、加減乘除等簡單的運算都當做常數級複雜度。 值得注意的是,在處理大數(二進制下數據長度超過32位或者十進制下超過8位)時,將加減乘除等運算當做常數複雜度不再適用。
* O(log n) 將一個10進制整數轉化爲2進制整數
* O(n):判斷一個元素是否屬於一個大小爲n的集合/列表;找出n個數中的最大值;
* O(n * log n) 快速排序法
* O(n^2) 最直白的兩兩比較然後排序方法,需要n*(n-1)/2次比較,所以是O(n^2)級。
* O(2^n) 列出所有長度爲n的0,1字符串之類的窮舉計算
* O(n!) 列出n個元素的全排列之類的窮舉計算
一般來說多項式級的複雜度是可以接受的,很多問題都有多項式級的解——也就是說,這樣的問題,對於一個規模是n的輸入,在n^k的時間內得到結果,稱爲P問題。有些問題要複雜些,沒有多項式時間的解,但是可以在多項式時間裏驗證某個猜測是不是正確。比如問4294967297是不是質數?如果要直接入手的話,那麼要把小於4294967297的平方根的所有素數都拿出來,看看能不能整除。還好歐拉告訴我們,這個數等於641和6700417的乘積,不是素數,很好驗證的,順便麻煩轉告費馬他的猜想不成立。大數分解、Hamilton迴路之類的問題,都是可以多項式時間內驗證一個“解”是否正確,這類問題叫做NP問題。(據信程序猿找妹子也是一個NP問題。。)
P問題顯然都是NP問題——既然你能在多項式時間裏得到答案,那麼只要比較一下答案和猜測是不是一樣就可以驗證一個解。反過來,多數人相信,NP問題不都是P問題。幾個月前看到一篇論文說NP不等於P,但沒有看到後續報道,也讀不懂原文,攤手……如果NP問題都是P問題,那麼大數分解不再是難題,從而基於大數分解的RSA加密系統頓時崩潰;同樣md5算法也不再有效,甚至現在所有的多項式複雜度的加密算法都沒用了——不過這樣一來程序猿也可以方便地找到妹子了,說起來並不是一無是處嘛……
常用的算法的時間複雜度和空間複雜度