1. 程序員的數學的作者目錄
第1章 0 的故事
——無即是有
本章學習內容 2
小學一年級的回憶 2
10 進制計數法3
什麼是10 進制計數法3
分解25033
2 進制計數法4
什麼是2 進制計數法4
分解11005
基數轉換 6
計算機中為什麼採用2 進制計數法8
按位計數法10
什麼是按位計數法10
不使用按位計數法的羅馬數字11
指數法則12
10 的0 次方是什麼12
10-1 是什麼13
規則的擴展14
對20 進行思考14
2-1 是什麼15
0 所起的作用16
0 的作用:佔位16
0 的作用:統一標准,簡化規則16
日常生活中的017
人類的極限和構造的發現18
重溫歷史進程18
為了超越人類的極限19
本章小結20
第2章 邏輯
——真與假的二元世界
本章學習內容22
為何邏輯如此重要22
邏輯是消除歧義的工具22
致對邏輯持否定意見的讀者23
乘車費用問題——兼顧完整性和排他性 23
車費規則23
命題及其真假24
有沒有「遺漏」24
有沒有「重復」25
畫一根數軸輔助思考26
注意邊界值28
兼顧完整性和排他性28
使用if 語句分解問題28
邏輯的基本是兩個分支29
建立復雜命題30
邏輯非——不是A30
邏輯與—— A 並且B32
邏輯或—— A 或者B34
異或—— A 或者B(但不都滿足)37
相等—— A 和B 等39
蘊涵——若A則B40
囊括所有了嗎45
德?摩根定律46
德?摩根定律是什麼46
對偶性47
卡諾圖48
二燈游戲48
首先藉助邏輯表達式進行思考49
學習使用卡諾圖50
三燈游戲52
包含未定義的邏輯54
帶條件的邏輯與(&&)55
帶條件的邏輯或(||)57
三值邏輯中的否定(!)58
三值邏輯的德?摩根定律58
囊括所有了嗎59
本章小結60
第3 章 余數
——周期性和分組
本章學習內容64
星期數的思考題(1)64
思考題(100天以後是星期幾)64
思考題答案64
運用余數思考65
余數的力量——將較大的數字除一次就能分組65
星期數的思考題(2)66
思考題(10100 天以後是星期幾)66
提示:可以直接計算嗎67
思考題答案67
發現規律68
直觀地把握規律68
乘方的思考題70
思考題70
提示:通過試算找出規律70
思考題答案70
回顧:規律和余數的關系71
通過黑白棋通信71
思考題71
提示73
思考題答案73
奇偶校驗73
奇偶校驗位將數字分為兩個集合74
尋找戀人的思考題74
思考題(尋找戀人)74
提示:先試算較小的數74
思考題答案75
回顧75
鋪設草席的思考題77
思考題(在房間里鋪設草席)77
提示:先計算一下草席數77
思考題答案78
回顧78
一筆畫的思考題79
思考題(哥尼斯堡七橋問題)79
提示:試算一下80
提示:考慮簡化一下81
提示:考慮入口和出口82
思考題答案82
奇偶校驗85
本章小結86
第4 章 數學歸納法
——如何征服無窮數列
本章學習內容88
高斯求和88
思考題(存錢罐里的錢)88
思考一下89
小高斯的解答89
討論一下小高斯的解答89
歸納91
數學歸納法—— 如何征服無窮數列91
0以上的整數的斷言92
高斯的斷言93
什麼是數學歸納法93
試著征服無窮數列94
用數學歸納法證明高斯的斷言95
求出奇數的和 —— 數學歸納法實例96
奇數的和96
通過數學歸納法證明97
圖形化說明98
黑白棋思考題 —— 錯誤的數學歸納法99
思考題(黑白棋子的顏色)99
提示:不要為圖所惑100
思考題答案 100
編程和數學歸納法101
通過循環表示數學歸納法101
循環不變式 103
本章小結107
第5章 排列組合
——解決計數問題的方法
本章學習內容110
計數——與整數的對應關系110
何謂計數110
注意「遺漏」和「重復」111
植樹問題——不要忘記0111
植樹問題思考題111
加法法則115
加法法則115
乘法法則117
乘法法則117
置換121
置換121
歸納一下122
思考題(撲克牌的擺法)123
排列125
排列125
歸納一下126
樹形圖——能夠認清本質嗎128
組合130
組合130
歸納一下131
置換、排列、組合的關系132
思考題練習 134
重復組合134
也要善於運用邏輯136
本章小結139
第6章 遞歸
——自己定義自己
本章學習內容142
漢諾塔142
思考題(漢諾塔)142
提示:先從小漢諾塔著手143
思考題答案 146
求出解析式 148
解出漢諾塔的程序149
找出遞歸結構150
再談階乘151
階乘的遞歸定義152
思考題(和的定義)153
遞歸和歸納 153
斐波那契數列154
思考題(不斷繁殖的動物)154
斐波那契數列157
帕斯卡三角形159
什麼是帕斯卡三角形159
遞歸定義組合數162
組合的數學理論解釋163
遞歸圖形165
以遞歸形式畫樹165
實際作圖166
謝爾平斯基三角形167
本章小結168
第7章 指數爆炸
——如何解決復雜問題
本章學習內容172
什麼是指數爆炸 172
思考題(折紙問題)172
指數爆炸175
倍數游戲——指數爆炸引發的難題176
程序的設置選項176
不能認為是「有限的」就不假思索178
二分法查找——利用指數爆炸進行查找178
尋找犯人的思考題178
提示:先思考人數較少的情況179
思考題答案 180
找出遞歸結構以及遞推公式181
二分法查找和指數爆炸183
對數——掌握指數爆炸的工具184
什麼是對數 184
對數和乘方的關系184
以2為底的對數186
以2為底的對數練習186
對數圖表187
指數法則和對數188
對數和計算尺190
密碼——利用指數爆炸加密193
暴力破解法 193
字長和安全性的關系193
如何處理指數爆炸195
理解問題空間的大小195
四種處理方法195
本章小結196
第8章 不可解問題
——不可解的數、無法編寫的程序
本章學習內容200
反證法200
什麼是反證法200
質數思考題 202
反證法的注意事項203
可數203
什麼是可數 203
可數集合的例子204
有沒有不可數的集合206
對角論證法 207
所有整數數列的集合是不可數的207
所有實數的集合是不可數的211
所有函數的集合也是不可數的212
不可解問題 213
什麼是不可解問題213
存在不可解問題214
思考題 215
停機問題215
停機216
處理程序的程序217
什麼是停機問題217
停機問題的證明219
寫給尚未理解的讀者222
不可解問題有很多223
本章小結224
第9章 什麼是程序員的數學
——總結篇
本章學習內容226
何為解決問題229
認清模式,進行抽象化229
由不擅長催生出的智慧229
幻想法則230
程序員的數學231
2. 一個演算法的時間復雜度和其空間復雜度有何關系
一個演算法的時間復雜度和其空間復雜度的關系可這樣理解。
一個演算法要做高效率低存儲是很困難的,也就是說,演算法的時間復雜度小,可能需要較大的空間復雜度。反之亦然。也可以說,通過空間換得時間。
演算法的時間復雜度和空間復雜度可以同時很大,也可以同時很小。如T(n)=O(n)且S(n)=O(1)的情況比如一個for(i=0;i<N;i++),若循環體中為一個與問題規模無關的變數變化,則其S(n)=O(1),而T(n)=O(n)是隨著N的變化而變化的,這時可以說時間復雜度較小而空間復雜度很小。
(2)程序員的數學歸納法第四章擴展閱讀:
一個演算法的空間復雜度只考慮在運行過程中為局部變數分配的存儲空間的大小,它包括為參數表中形參變數分配的存儲空間和為在函數體中定義的局部變數分配的存儲空間兩個部分。若一個演算法為遞歸演算法,其空間復雜度為遞歸所使用的堆棧空間的大小,它等於一次調用所分配的臨時存儲空間的大小乘以被調用的次數(即為遞歸調用的次數加1,這個1表示開始進行的一次非遞歸調用)。演算法的空間復雜度一般也以數量級的形式給出。
3. 程序員的數學-讀書筆記
計數法分為 按位計數法 和 羅馬計數法
按位計數法常用的有2進制、8進制、10進制、16進制等幾種。
理論上多少進制在數學上都可以存在,瑪雅人用20進制,巴比倫人用10進制和60進制的混合計數法。瑪雅人20進制可能是和手腳趾加起來的數量有關。巴比倫人採用60進制也可能是因為記錄數字的黏土版比較難記錄文字記號,為了在大數的書寫上少佔位便採用了60進制。
從這一點來看,環境對文明和文化的形成真的是有決定性的影響。假如巴比倫人掌握了造紙術或者在竹子上書寫文字的話,60進制這種違反人類天性的計數方法一定不會出現。話說,漢莫拉比法典就是寫在黑色的玄武岩上的。能夠記錄的文字也就屈指可數吧。
作者提到了其實人也是可以採用2進制計數法的,可是同樣大小的數字用2進制書寫起來位數太多,一來書寫不方便,二來計算時易發生馬虎出現錯誤。而10進制的數天生就是順應人類人性的,即使是幼兒也可以通過數手指頭的方式來計數。
相反對於計算機的物理構造來講,0代表開關斷開,1代表開關連接,這種二極體的物理限制正好決定了計算機較為適用2進制。不過如果你想做出一個10進制的計算機也不是沒有可能的。
這一章比較有趣的是羅馬計數法,我以前也沒有接觸過超過20的羅馬數字,也不知道羅馬數字各個數位上的數字相加之和為數字本身所代表的量。例如:
反觀阿拉伯數字
由此引發作者在兩個程序領域上的思考:
關鍵詞:真值表、文氏圖、邏輯表達式、卡諾圖、三值邏輯、完整性、排他性
- 能夠判斷對錯的陳述句叫做命題(proposition)
邏輯非 --不是A
逆命題
逆否命題
德摩根定律
卡諾圖 (二燈游戲、三燈游戲引出)
未定義邏輯(undefined)
三值邏輯的德摩根定律
本章探討的是通過余數來解決存在規律、周期性的問題。通過規律和周期性的重復,將大問題簡化成容易解決的小問題。
首先作者通過解決星期幾問題,引入了余數的思考概念。
上面的問題在 大問題通過余數規律簡化為小問題 這個方法上表現的還不明顯,於是引入了第三個問題:1234567^7654321的個位數是多少。
以上三個問題是小學奧賽便涉及到的問題,然而其思想在解決真實面對的復雜問題或具象的實際問題時卻很好用。
將一個數字除以2,他的余數應該為0或者1二者之一。我們也可以叫 奇偶問題 。
書中有幾個案例:
這樣分析過來就很好解決七橋問題,確定每個點所連接的橋的點數,與上述結論做對比。
A點為3,B點為,C點為3,D點為3.
由此可以得出七橋問題不可能實現。這個問題的解決也是通過奇偶性來解決的。
作者舉了高斯求和的故事來講如何用數學歸納法來解決無窮數列的求和問題。
兩個小例子便是從0開始到N的和,以及1開始的奇數和。
數學歸納法 是證明[ 有關整數的斷言對於0以上的所有整數(0,1,2...)是否成立 ]所用的方法。
證明方法歸結為兩歩:
根據上述方法,假若某個假設成立,那麼P(0)成立,因為P(0)成立,所以P(0+1)即P(1)也成立。反復如此,對於無窮數列遵守這個規律的證明,就像多米諾骨牌,推到第一個,後面的都會按照第一個的規則倒下去。
然而要避免整個證明出錯,就要重視第二個步驟,也就是歸納。歸納在證明時一定要考慮 是否在所有定義條件下均成立 ,尤其要注意的是在P(0)的條件下是否實現。
課後對話很有意思:
計數是人類每天生活都要運用的方法。
計數的關鍵就在於 注意「遺漏」和「重復」
例如:
綜上,在計數時要發現事物的規則。
要 認清計數對象的本質
要 認清計數對象的本質
要 認清計數對象的本質
重要的事情說三遍。
將計數對象進行 歸納總結 ,使其作為普通規則來掌握。這樣一般不容易出錯。
接下來,作者在 加法法則 里寫到:
乘法法則 的概念比較有意思。
接下來,本章提到了置換、排列、組合3個概念。以下是幾個小例子。
最後提到的 重復組合 里的思考問題比較有趣。
解答的思想是:
這是一種典型的將復雜問題簡單化,並規律化的解答方法。
最後還是要強調下:
要 認清計數對象的本質
遞歸與歸納的區別
歸納(inctive) 是從個別性前提推出一般性結論。
本質上都是 將復雜問題簡化 ,但方向不同。
個人理解是
遞歸是發現第n項和前一兩項之間的關系,實證確定後,往回不斷遞推的一種個別性結論。
即這個結論不是在n為任何自然數時都成立的。需要注意n為0和1的兩項。
通過遞歸解決問題的線路是: 找到遞歸結構——建立遞推公式——找到解析式(只帶n的式子) ,如果不能以解析式的方式描述遞歸結構,也可以用遞推公式的方法描述。如下圖所示的漢諾塔的遞推公式:(它也可以描述成解析式的方式)
歸納所謂的個別性前提是指
斐波那契數列就是運用了遞歸的思想。通過研究和思考復雜問題,抓住事務本質,得到f(n)=f(n-1)+f(n-2)
所以當我們想要用遞歸的方法解決問題時,注意思考第n元素與前後元素的關系。由一個點推開,成一條貫穿始終的線。
利用帕斯卡三角形來研究Cnk=Cn-1(k-1) + Cn-1k的思考方式另闢蹊徑。將兩個加數假設成組合問題里含一個元素和不含那個元素的兩個情況。從而證明了式子。利用的便是組合的數學分析法。(這句話組合的意思不是數學意義上的)。
所以以上將復雜問題簡化的方法是遞歸解法之一,是為了在復雜問題中找到隱含的遞歸結構。其思路是:
通過思考一張1mm的紙,折多少次能夠有地月距離那麼厚,作者引出指數的概念。
這一章的內容比較簡單,對於 指數爆炸 大家應該都不陌生。而 對數 估計也很熟悉。之前接觸到的漢諾塔問題的解析式和斐波那契數列都屬於指數的范疇。
然而在解決 測試所有設定選項的程序時,檢查次數也是一個指數問題 。所以我們應該如何輕松的解決這類問題呢?
利用二分法查找
利用二分法,先詢問最中間的人,如果在左邊,就繼續在左邊的范圍內重復此項方法,直到找到罪犯。這便被稱為 2分法 。他和漢諾塔的解析式如出一轍,可以利用指數原理經過很少的步驟便可找到目標。
二分法本身也是 遞歸結構 ,經過n次詢問,可以在2^n-1人中確定目標。每判斷一次就可以查找近一半的對象。
二分法需要注意的是,所有元素一定要 按順序排列 ,這點至關重要。
指數思想也被用於加密的實現中。因為每多加密一位,暴力破解就需要指數次的運算能力的提升。原則上有限時間里根本不可能破解。指數以其數字的巨大增長能力在加密領域有基本性的作用。
對於指數問題的解決方法,主要有4種,但均不太容易應付規模大的數字。
作為指數函數的逆函數,文章涉及了對數。同時也簡單介紹了古代科學家用過的計算尺。
無窮可以分為 可數無窮 和 不可數無窮 。
所謂 可數無窮 是指 可以按照一定的規律或者表達方式來表達 。
即集合中所有元素都與正整數一一對應。如果每一個元素都可以與1.2.3....等數字對應,也就是說可以按規律表達出來就是可數無窮。
例如:
所以有不可數的集合嗎?
此時運用到了 對角論證法 和 反證法(也叫歸謬法)
假設我們要證明 所有整數數列的集合是不可數的 ,那麼反證就是 假設所有整數數列的集合是可數的 ,此處是運用的反證法。
現在我們按下圖的方式來列出所有整數數列,編號為k的整數列在表的k行。
如果按照圖中第k行的第k個元素ak單獨組出一組數列{a1,a2,a3......}的話,他也是應該包含在所有整數數列里的,然而並沒有,他是游離在所有整數數列之外的。此處得出矛盾,說明命題錯誤,命題 所有整數數列的集合是不可數的 為真。此方法被稱為 對角論證法
除此之外
-所有實數的集合是不可數的
-所有函數的集合也是不可數的
隨後書中討論到了不可解的問題
對於不可解的問題的定義是
事實上,不能寫成程序的函數是存在的。
有些函數不能用文字表達,而且要寫成程序的函數必須 嚴謹定義確切和文字表達 兩個概念。
停機問題
不可解問題的一例。定義是
有限時間並不指時間長短,而是指無論耗時多長,只要能有終止的一刻就好。
事實上,程序本身並不能判斷某一程序是否可以在有限時間內結束運行
所以停機問題也是 不可解問題 之一。
這一章是對之前8章的回顧和總結。
前幾章作者分別對 0的意義、邏輯、余數、數學歸納、排列組合、遞歸、指數爆炸、不可解問題 進行了簡單的介紹和探討。其實所有的章節最後都是在引領讀者產生如何解決問題的思考。
1.認清模式,進行抽象化
2.由不擅長催生出的智慧
3.幻想法則
本書比較適合作為第一本接觸演算法的書籍。目前開始在上 Khan的Algorithms ,9月份跟上 coursera的Algorithms Part I 的開課。
前方的路註定不好走,但是要慢慢嘗試和堅持。
4. 演算法的空間復雜度和時間復雜度的關系
論壇
活動
招聘
專題
打開CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved
搜索博文/帖子/用戶
登錄
zolalad
關注
演算法的時間復雜度和空間復雜度-總結 原創
2013-09-20 16:01:26
308點贊
zolalad
碼齡9年
關注
演算法的時間復雜度和空間復雜度-總結
通常,對於一個給定的演算法,我們要做 兩項分析。第一是從數學上證明演算法的正確性,這一步主要用到形式化證明的方法及相關推理模式,如循環不變式、數學歸納法等。而在證明演算法是正確的基礎上,第二部就是分析演算法的時間復雜度。演算法的時間復雜度反映了程序執行時間隨輸入規模增長而增長的量級,在很大程度上能很好反映出演算法的優劣與否。因此,作為程序員,掌握基本的演算法時間復雜度分析方法是很有必要的。
演算法執行時間需通過依據該演算法編制的程序在計算機上運行時所消耗的時間來度量。而度量一個程序的執行時間通常有兩種方法。
一、事後統計的方法
這種方法可行,但不是一個好的方法。該方法有兩個缺陷:一是要想對設計的演算法的運行性能進行評測,必須先依據演算法編制相應的程序並實際運行;二是所得時間的統計量依賴於計算機的硬體、軟體等環境因素,有時容易掩蓋演算法本身的優勢。
二、事前分析估算的方法
因事後統計方法更多的依賴於計算機的硬體、軟體等環境因素,有時容易掩蓋演算法本身的優劣。因此人們常常採用事前分析估算的方法。
在編寫程序前,依據統計方法對演算法進行估算。一個用高級語言編寫的程序在計算機上運行時所消耗的時間取決於下列因素:
(1). 演算法採用的策略、方法;(2). 編譯產生的代碼質量;(3). 問題的輸入規模;(4). 機器執行指令的速度。
一個演算法是由控制結構(順序、分支和循環3種)和原操作(指固有數據類型的操作)構成的,則演算法時間取決於兩者的綜合效果。為了便於比較同一個問題的不同演算法,通常的做法是,從演算法中選取一種對於所研究的問題(或演算法類型)來說是基本操作的原操作,以該基本操作的重復執行的次數作為演算法的時間量度。
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)) 為演算法的漸進時間復雜度,簡稱時間復雜度。
另外,上面公式中用到的 Landau符號其實是由德國數論學家保羅·巴赫曼(Paul Bachmann)在其1892年的著作《解析數論》首先引入,由另一位德國數論學家艾德蒙·朗道(Edmund Landau)推廣。Landau符號的作用在於用簡單的函數來描述復雜函數行為,給出一個上或下(確)界。在計算演算法復雜度時一般只用到大O符號,Landau符號體系中的小o符號、Θ符號等等比較不常用。這里的O,最初是用大寫希臘字母,但現在都用大寫英語字母O;小o符號也是用小寫英語字母o,Θ符號則維持大寫希臘字母Θ。
T (n) = Ο(f (n)) 表示存在一個常數C,使得在當n趨於正無窮時總有 T (n) ≤ C * f(n)。簡單來說,就是T(n)在n趨於正無窮時最大也就跟f(n)差不多大。也就是說當n趨於正無窮時T (n)的上界是C * f(n)。其雖然對f(n)沒有規定,但是一般都是取盡可能簡單的函數。例如,O(2n2+n +1) = O (3n2+n+3) = O (7n2 + n) = O ( n2 ) ,一般都只用O(n2)表示就可以了。注意到大O符號里隱藏著一個常數C,所以f(n)里一般不加系數。如果把T(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的不斷增大,上述時間復雜度不斷增大,演算法的執行效率越低。
從圖中可見,我們應該盡可能選用多項式階O(nk)的演算法,而不希望用指數階的演算法。
常見的演算法時間復雜度由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
一般情況下,對一個問題(或一類演算法)只需選擇一種基本操作來討論演算法的時間復雜度即可,有時也需要同時考慮幾種基本操作,甚至可以對不同的操作賦予不同的權值,以反映執行不同操作所需的相對時間,這種做法便於綜合比較解決同一問題的兩種完全不同的演算法。
(3)求解演算法的時間復雜度的具體步驟是:
⑴ 找出演算法中的基本語句;
演算法中執行次數最多的那條語句就是基本語句,通常是最內層循環的循環體。
⑵ 計算基本語句的執行次數的數量級;
只需計算基本語句執行次數的數量級,這就意味著只要保證基本語句執行次數的函數中的最高次冪正確即可,可以忽略所有低次冪和最高次冪的系數。這樣能夠簡化演算法分析,並且使注意力集中在最重要的一點上:增長率。
⑶ 用大Ο記號表示演算法的時間性能。
將基本語句執行次數的數量級放入大Ο記號中。
如果演算法中包含嵌套的循環,則基本語句通常是最內層的循環體,如果演算法中包含並列的循環,則將並列循環的時間復雜度相加。例如:
for (i=1; i<=n; i++)
x++;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
x++;
第一個for循環的時間復雜度為Ο(n),第二個for循環的時間復雜度為Ο(n2),則整個演算法的時間復雜度為Ο(n+n2)=Ο(n2)。
Ο(1)表示基本語句的執行次數是一個常數,一般來說,只要演算法中不存在循環語句,其時間復雜度就是Ο(1)。其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)稱為多項式時間,而Ο(2n)和Ο(n!)稱為指數時間。計算機科學家普遍認為前者(即多項式時間復雜度的演算法)是有效演算法,把這類問題稱為P(Polynomial,多項式)類問題,而把後者(即指數時間復雜度的演算法)稱為NP(Non-Deterministic Polynomial, 非確定多項式)問題。
一般來說多項式級的復雜度是可以接受的,很多問題都有多項式級的解——也就是說,這樣的問題,對於一個規模是n的輸入,在n^k的時間內得到結果,稱為P問題。有些問題要復雜些,沒有多項式時間的解,但是可以在多項式時間里驗證某個猜測是不是正確。比如問4294967297是不是質數?如果要直接入手的話,那麼要把小於4294967297的平方根的所有素數都拿出來,看看能不能整除。還好歐拉告訴我們,這個數等於641和6700417的乘積,不是素數,很好驗證的,順便麻煩轉告費馬他的猜想不成立。大數分解、Hamilton迴路之類的問題,都是可以多項式時間內驗證一個「解」是否正確,這類問題叫做NP問題。
(4)在計算演算法時間復雜度時有以下幾個簡單的程序分析法則:
(1).對於一些簡單的輸入輸出語句或賦值語句,近似認為需要O(1)時間
(2).對於順序結構,需要依次執行一系列語句所用的時間可採用大O下"求和法則"
求和法則:是指若演算法的2個部分時間復雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1(n)+T2(n)=O(max(f(n), g(n)))
特別地,若T1(m)=O(f(m)), T2(n)=O(g(n)),則 T1(m)+T2(n)=O(f(m) + g(n))
(3).對於選擇結構,如if語句,它的主要時間耗費是在執行then字句或else字句所用的時間,需注意的是檢驗條件也需要O(1)時間
(4).對於循環結構,循環語句的運行時間主要體現在多次迭代中執行循環體以及檢驗循環條件的時間耗費,一般可用大O下"乘法法則"
乘法法則: 是指若演算法的2個部分時間復雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1*T2=O(f(n)*g(n))
(5).對於復雜的演算法,可以將它分成幾個容易估算的部分,然後利用求和法則和乘法法則技術整個演算法的時間復雜度
另外還有以下2個運演算法則:(1) 若g(n)=O(f(n)),則O(f(n))+ O(g(n))= O(f(n));(2) O(Cf(n)) = O(f(n)),其中C是一個正常數
(5)下面分別對幾個常見的時間復雜度進行示例說明:
(1)、O(1)
Temp=i; i=j; j=temp;
以上三條單個語句的頻度均為1,該程序段的執行時間是一個與問題規模n無關的常數。演算法的時間復雜度為常數階,記作T(n)=O(1)。注意:如果演算法的執行時間不隨著問題規模n的增加而增長,即使演算法中有上千條語句,其執行時間也不過是一個較大的常數。此類演算法的時間復雜度是O(1)。
(2)、O(n2)
2.1. 交換i和j的內容
sum=0; (一次)
for(i=1;i<=n;i++) (n+1次)
for(j=1;j<=n;j++) (n2次)
sum++; (n2次)
解:因為Θ(2n2+n+1)=n2(Θ即:去低階項,去掉常數項,去掉高階項的常參得到),所以T(n)= =O(n2);
2.2.
for (i=1;i<n;i++)
{
y=y+1; ①
for (j=0;j<=(2*n);j++)
x++; ②
}
解: 語句1的頻度是n-1
語句2的頻度是(n-1)*(2n+1)=2n2-n-1
f(n)=2n2-n-1+(n-1)=2n2-2;
又Θ(2n2-2)=n2
該程序的時間復雜度T(n)=O(n2).
一般情況下,對步進循環語句只需考慮循環體中語句的執行次數,忽略該語句中步長加1、終值判別、控制轉移等成分,當有若干個循環語句時,演算法的時間復雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。
(3)、O(n)
a=0;
b=1; ①
for (i=1;i<=n;i++) ②
{
s=a+b;③
b=a;④
a=s;⑤
}
解: 語句1的頻度:2,
語句2的頻度: n,
語句3的頻度: n-1,
語句4的頻度:n-1,
語句5的頻度:n-1,
T(n)=2+n+3(n-1)=4n-1=O(n).
(4)、O(log2n)
i=1; ①
while (i<=n)
i=i*2; ②
解: 語句1的頻度是1,
設語句2的頻度是f(n), 則:2^f(n)<=n;f(n)<=log2n
取最大值f(n)=log2n,
T(n)=O(log2n )
(5)、O(n3)
for(i=0;i<n;i++)
{
for(j=0;j<i;j++)
{
for(k=0;k<j;k++)
x=x+2;
}
}
解:當i=m, j=k的時候,內層循環的次數為k當i=m時, j 可以取 0,1,...,m-1 , 所以這里最內循環共進行了0+1+...+m-1=(m-1)m/2次所以,i從0取到n, 則循環共進行了: 0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/6所以時間復雜度為O(n3).
(5)常用的演算法的時間復雜度和空間復雜度
一個經驗規則:其中c是一個常量,如果一個演算法的復雜度為c 、 log2n 、n 、 n*log2n ,那麼這個演算法時間效率比較高 ,如果是2n ,3n ,n!,那麼稍微大一些的n就會令這個演算法不能動了,居於中間的幾個則差強人意。
演算法時間復雜度分析是一個很重要的問題,任何一個程序員都應該熟練掌握其概念和基本方法,而且要善於從數學層面上探尋其本質,才能准確理解其內涵。
2、演算法的空間復雜度
類似於時間復雜度的討論,一個演算法的空間復雜度(Space Complexity)S(n)定義為該演算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間復雜度也常常簡稱為空間復雜度。
空間復雜度(Space Complexity)是對一個演算法在運行過程中臨時佔用存儲空間大小的量度。一個演算法在計算機存儲器上所佔用的存儲空間,包括存儲演算法本身所佔用的存儲空間,演算法的輸入輸出數據所佔用的存儲空間和演算法在運行過程中臨時佔用的存儲空間這三個方面。演算法的輸入輸出數據所佔用的存儲空間是由要解決的問題決定的,是通過參數表由調用函數傳遞而來的,它不隨本演算法的不同而改變。存儲演算法本身所佔用的存儲空間與演算法書寫的長短成正比,要壓縮這方面的存儲空間,就必須編寫出較短的演算法。演算法在運行過程中臨時佔用的存儲空間隨演算法的不同而異,有的演算法只需要佔用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種演算法是「就地\"進行的,是節省存儲的演算法,如這一節介紹過的幾個演算法都是如此;有的演算法需要佔用的臨時工作單元數與解決問題的規模n有關,它隨著n的增大而增大,當n較大時,將佔用較多的存儲單元,例如將在第九章介紹的快速排序和歸並排序演算法就屬於這種情況。
如當一個演算法的空間復雜度為一個常量,即不隨被處理數據量n的大小而改變時,可表示為O(1);當一個演算法的空間復雜度與以2為底的n的對數成正比時,可表示為0(10g2n);當一個演算法的空I司復雜度與n成線性比例關系時,可表示為0(n).若形參為數組,則只需要為它分配一個存儲由實參傳送來的一個地址指針的空間,即一個機器字長空間;若形參為引用方式,則也只需要為其分配存儲一個地址的空間,用它來存儲對應實參變數的地址,