數據結構 時間複雜度

程序設計=數據結構+算法

 

數據結構分爲 邏輯結構(面向問題) 和 物理結構(面向計算機)。

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算法也不再有效,甚至現在所有的多項式複雜度的加密算法都沒用了——不過這樣一來程序猿也可以方便地找到妹子了,說起來並不是一無是處嘛……

常用的算法的時間複雜度和空間複雜度

排序法

最差時間分析 平均時間複雜度 穩定度 空間複雜度
冒泡排序 O(n2) O(n2) 穩定 O(1)
快速排序 O(n2) O(n*log2n) 不穩定 O(log2n)~O(n)
選擇排序 O(n2) O(n2) 穩定 O(1)
二叉樹排序 O(n2) O(n*log2n) 不一頂 O(n)

插入排序

O(n2) O(n2) 穩定 O(1)
堆排序 O(n*log2n) O(n*log2n) 不穩定 O(1)
希爾排序 O O 不穩定 O(1)

1、時間複雜度
(1)時間頻度 一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。
(2)時間複雜度 在剛纔提到的時間頻度中,n稱爲問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什麼規律。爲此,我們引入時間複雜度概念。 一般情況下,算法中基本操作重複執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值爲不等於零的常數,則稱f(n)是T(n)的同數量級函數。記作T(n)=O(f(n)),稱O(f(n)) 爲算法的漸進時間複雜度,簡稱時間複雜度。
在各種不同算法中,若算法中語句執行次數爲一個常數,則時間複雜度爲O(1),另外,在時間頻度不相同時,時間複雜度有可能相同,如T(n)=n2+3n+4與T(n)=4n2+2n+1它們的頻度不同,但時間複雜度相同,都爲O(n2)。 按數量級遞增排列,常見的時間複雜度有:常數階O(1),對數階O(log2n),線性階O(n), 線性對數階O(nlog2n),平方階O(n2),立方階O(n3),..., k次方階O(nk),指數階O(2n)。隨着問題規模n的不斷增大,上述時間複雜度不斷增大,算法的執行效率越低。 2、空間複雜度 與時間複雜度類似,空間複雜度是指算法在計算機內執行時所需存儲空間的度量。記作: S(n)=O(f(n)) 我們一般所討論的是除正常佔用內存開銷外的輔助存儲單元規模。討論方法與時間複雜度類似,不再贅述。
(3)漸進時間複雜度評價算法時間性能   主要用算法時間複雜度的數量級(即算法的漸近時間複雜度)評價一個算法的時間性能。

2、類似於時間複雜度的討論,一個算法的空間複雜度(Space Complexity)S(n)定義爲該算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間複雜度也常常簡稱爲空間複雜度。
空間複雜度(Space Complexity)是對一個算法在運行過程中臨時佔用存儲空間大小的量度。一個算法在計算機存儲器上所佔用的存儲空間,包括存儲算法本身所佔用的存儲空間,算法的輸入輸出數據所佔用的存儲空間和算法在運行過程中臨時佔用的存儲空間這三個方面。算法的輸入輸出數據所佔用的存儲空間是由要解決的問題決定的,是通過參數表由調用函數傳遞而來的,它不隨本算法的不同而改變。存儲算法本身所佔用的存儲空間與算法書寫的長短成正比,要壓縮這方面的存儲空間,就必須編寫出較短的算法。算法在運行過程中臨時佔用的存儲空間隨算法的不同而異,有的算法只需要佔用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種算法是“就地\"進行的,是節省存儲的算法,如這一節介紹過的幾個算法都是如此;有的算法需要佔用的臨時工作單元數與解決問題的規模n有關,它隨着n的增大而增大,當n較大時,將佔用較多的存儲單元,例如將在第九章介紹的快速排序和歸併排序算法就屬於這種情況。

當一個算法的空間複雜度爲一個常量,即不隨被處理數據量n的大小而改變時,可表示爲O(1);當一個算法的空間複雜度與以2爲底的n的對數成正比時,可表示爲0(10g2n);當一個算法的空I司複雜度與n成線性比例關係時,可表示爲0(n).若形參爲數組,則只需要爲它分配一個存儲由實參傳送來的一個地址指針的空間,即一個機器字長空間;若形參爲引用方式,則也只需要爲其分配存儲一個地址的空間,用它來存儲對應實參變量的地址,以便由系統自動引用實參變量。

 
求1到100的和:
1、一個for
2、高斯公式:(1+n)*n/2 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章