主題:簡介課程,漸近概念的大局觀,插入排序和歸並排序,遞歸式函數時間分析(遞歸樹方法)
教材:《算法導論》
收獲:很感動地看到算法分析那個log(n)是為什么出現了,更深層還要聽第二講,若不是因為要准備SAS,恨不得馬上看。
內容:
1 何為算法分析?
計算機程序運行性能和存儲空間的理論分析,叫算法分析。也就是關注2點:1 性能,就是程序跑得快不快; 2 存儲空間,即占用了多大的內存。但是主要還是關注性能。(可能是因為時間就是金錢吧,而且現在計算機硬件發展速度還不錯)
2 比性能更加重要的因素都有哪些?
比如成本,正確性,功能特征(features),用戶用好,模塊化性等等。
3 那為何還學習算法和性能?
很妙的引入方法,你都說了上面那些東西比性能還重要,那尼瑪干嘛還要學習算法?
學習算法的原因:
A performance measures the line between the feasible and the infeasible.
對於很多比性能更重要的因素,其實他們跟性能是密切相關的,比如用戶用好,就需要你的程序響應時間控制在一定范圍內。算法總是處在解決問題的最前沿。
B algorithms give us a language for talking about program behavior.
算法給出了程序行為的描述。
其實形象的比喻就是:水,食物這些東西都比錢重要,你為什么還需要錢?算法就像經濟社會中的“貨幣”,它給出了衡量的一般標准。比如你付出了性能來追求安全穩健性,用戶友好性等等。
比如JAVA程序一直很流行,其實它的性能比起C語言要差3倍多,但是由於它本身的面向對象,異常機制等原因,使得人們還是很願意犧牲性能來追求可拓展性,安全性這些東東。個人的理解就是,比如在軟件設計中,你要着重追求某些方面,那在哪種程度范圍內是可以接受的呢?性能就是一個標准,比如犧牲3倍性能可以接受,10倍就不行。
C tons of fun
追求速度總是很有趣的,所以人們才會熱衷於賽車,火箭等東西。
4 引入插入排序
插入排序(Insertion Sort)
4.1 描述:
輸入 A[1…n],要輸出 A’[1,…n],使得A’中的元素按升序排序,也就是a’(1)<=a’(2)<=a’(3)…
4.2 偽代碼:
For j=2 to n
{
Do key=a[j]
i=j-1;
While i>0 and a[i]>key
{
Do a[i+1]=a[i]
I=i-1;
}
A[i+1]=key
}
4.3 舉例:
1 7 3 6 4 20 13 9
T1:看第二個元素,7,比1大,放在第二位
T2:看第三個元素,3,比7小,把7放到第三位,3再跟1 比較,比1大,所以3放在第二位,結果1 3 7
T3:類似,分析6,結果1 3 6 7
T4..
T7:1 3 4 6 7 9 13 20
4.4 本質:
每次循環后前面已經排好序的部分保持不變(這里的不變應該是指不用管了,而不是位置絕對不變),每次循環的目的是完成增量,使得已經排序的長度+1
5 通過插入排序,看運行時間依賴哪些因素,引入算法分析的漸近分析符號
5.1 運行時間依賴因素
A 輸入的數列,如果已經排好序,工作量近似為0,而如果是逆序的,工作量最大
B 輸入的數列規模n。6個數VS 6億個數,所以后續的運行時間分析時,我們把時間看成是n的函數
5.2 T(n)引入
一般我們都想知道運行時間的下屆,就是最差的情況,這樣子對用戶是一個保證,你可以跟人家說這個程序最多不超過3s,但是你不會說最少要3s吧,天知道最好3s,最差要多久,說不定是一輩子。
所以在算法分析中,我們一般是做最壞情況分析,可以用T(n)表示最長的運行時間,
T(n)is the max time on any input size n.
有時候我們也討論平均情況。此時T(n) is the expected time over all input size n.也就是T(N)表示期望時間。
(什么是期望時間,數學上的公式是每種輸入運行時間*每種輸入出現的概率,通俗來講就是加權平均。)
那么每種輸入出現的概率是多大呢?我們假設一種統計分布:均勻分布,當然也可以選擇其他分布。均勻分布,也就是說,每種輸入出現的概率是一樣的。
最好情況分析,這個是假象,一般是拿來忽悠人的。沒什么用。
運行時間依賴於具體的機器,所以一般分析的時候是考慮相對速度,也就是在同一台機器上的運行速度。(相反的就是絕對速度,也就是在不同機器上做比較)
6 算法的大局觀:The Big idea of algorithm——漸近分析
6.1 基本思路是:
忽略掉那些依賴於機器的常量(比如某條具體操作運行時間,如賦值操作),而且,不是去檢查實際運行時間,而是關注運行時間的增長。什么意思呢?就是關注的是當輸入規模n——》無窮時,T(n)是什么情況,而不是說n=10的時候的詳細比較。
6.2 具體
漸近符號:Θ(n)
運算法則:對於一個公式,棄去它的低階項,並忽略前面的常數因子。比如
Θ(3n^3+90n^2-5n+69)=Θ(n^3)
簡單吧!
其實Θ(n)是有嚴格的數學定義的(下節課再一起講),所以算法導論這門課既是講數學,也是講計算機科學的。
6.3 數學與工程的trade-offs

從圖中(這個圖畫得不是一般的丑)可以看出,當n0趨於無窮時,Θ(n2)<<Θ(n3)
有時候交點n0太大,計算機無法運行,所以我們有時會對一些相對低速算法感興趣。應該就是理論與實際的妥協trade-offs。
7 插入排序運行時間分析
插入排序最壞情況:
T(n)=2+3+…+n=(2+n)(n-1)/2=Θ(n^2)
插入排序算不算快?
對於較小的n,還算是很快的,但是對於大n,它就不算快了,更快的一種排序算法是歸並排序。
8 引入歸並排序
8.1 歸並排序步驟
S1:如果n=1,那么結束;
S2:否則,遞歸地排序A[1,…[n/2]]和A[[n/2]+1,…n]
S3: 將2個已經排序好的表合並在一起(’Merge’)
8.2 歸並子程序
這里用到了一個歸並子程序,這也是這個算法的關鍵。
假設2張已經按照從小到大排序好的表,如何合並?
因為最小的元素一定是2張表中首個元素之一。所以每次對比2張表中最小元素即可。
舉例:
1 7 11 13 15 19
3 4 9 18 20 22
首先比較1,3,取1,然后第一個表划掉1
然后比較7和3,取3,然后第二個表划掉3
然后比較7和9,取7,然后第一個表划掉7
以此類推
這個過程運行時間是Θ(n),因為每個元素用了一次對比,是常數時間,然后做了n次,所以是Θ(n),也就是線性時間。
9 歸並排序運行時間分析(遞歸樹方法)
所以T(n)={Θ(1) if n=1;
2T(n/2)+Θ(n)(if n>1)(注意:Θ(n)+Θ(1)=Θ(n)}
已經知道遞歸式子了,那么運行時間如何求解?
可以用遞歸樹的方法求解運行時間,具體的在Lecture2 會講到,我們只要考慮n>1的情況即可
此時T(n)可以表示成為2*T(n/2)+C*n
構造遞歸樹方法:
1 先把遞歸式子的左半部分寫出來

注意:式子右邊樹上的葉子加起來正好就是T(n),比如第一顆樹,T(n)=Cn+T(n/2)*2
高度(層數)約為log(n)(視頻上寫着log(n),個人覺得應該是表示log2(n),后面也直接用log(n)表示)
這里強調“約”,是因為n不一定是2的整數冪,但是接近。
假設n是2的整數冪,那么講到Θ(1),正好有log(n)步,n->n/2->n/4->…1,實際上是log(n)的常數倍。
最底層的葉子節點數目是n
T(n)表達式?
為了得到T(n),考慮把所有樹上葉子加起來是多少。
除了最后一層,每一層的綜合都是C*n,最后一層不一定是C*n,因為邊界情況可能存在別的值,記為Θ(n)
所以總數T(n)=Cn*log(n)+Θ(n)(第一項比第二項高)=Θ(n*logn)
考慮漸近情況下,Θ(n*logn)比Θ(n2)要快,所以歸並排序在一個充分大的輸入規模n下將優於插入排序。
10待解決疑問:
1比如遞歸樹原理,有待下一講一些理論
2 為什么在漸近情況下,Θ(n*logn)<<Θ(n2)
