讀算法導論
記錄一下讀算法導論的過程
1.算法
如果問我什么是算法(思考中)
利用數(shù)據(jù)結(jié)構(gòu),考慮時間以及空間效率,高效的解決一系列數(shù)學或是計算機問題的方法
而書中: 算法(algorithm) 就是任何良定義的計算過程,該過程取某個值或值的集合作為輸出并產(chǎn)生某個值或值的集合作為輸出。這樣算法就是把輸入轉(zhuǎn)換成輸出的計算步驟的一個序列。
- 算法解決哪些問題
書中舉例了DNA序列的儲存以及分析(30億個化學基對的序列)
互聯(lián)網(wǎng)搜索引擎的索引以及數(shù)據(jù)處理
電商的公私鑰以及數(shù)字簽名
......
其中還提到了NP完全問題(Non-deterministic Polynomial)世界七大數(shù)學難題
所有可以在多項式時間內(nèi)求解的判定問題構(gòu)成P類問題
所有的非確定性多項式時間可解的判定問題構(gòu)成NP類問題(無法直接計算得到的,只能通過間接的“猜算”來得到結(jié)果。這就是非確定性問題,比如找大質(zhì)數(shù),只能一個個試)
NP中的某些問題的復雜性與整個類的復雜性相關(guān)聯(lián).這些問題中任何一個如果存在多項式時間的算法,那么所有NP問題都是多項式時間可解的.這些問題被稱為NP-完全問題(NPC問題)
現(xiàn)在人們想要證明 NP = P 或是 NP != P
傅里葉變換
傅立葉變換,表示能將滿足一定條件的某個函數(shù)表示成三角函數(shù)(正弦和/或余弦函數(shù))或者它們的積分的線性組合
書中提到了(離散傅里葉變換把時域轉(zhuǎn)變?yōu)轭l域,數(shù)據(jù)壓縮,采樣信號中各種頻率強度)
然后我就去查了一下(還是知乎大佬牛逼)把這個抽象問題說明了
看了點知乎相關(guān)之后,再去看了下李永樂老師的數(shù)學,大致知道了傅里葉變換的應(yīng)用場景(在視頻處理和音頻處理上,甚至從事物最本質(zhì)的角度上,傅里葉變換說明了信號的波粒性質(zhì))甚至人的大腦對聲波的區(qū)分從本質(zhì)上來說就是一種傅里葉變換的體現(xiàn)
這里大致記錄一下我對傅里葉變換的一些粗淺的理解
首先從二維平面圖到數(shù)字的變換很簡單
圖上的點A(2,1),和點B(1,2)很容易就能繪制出來
然后又有一個標準正交基的概念
(?i,?j)=δij 假如i = j 則 δij = 1 , i 不等于j 則δij = 0
然后是傅里葉級數(shù)說明了任何周期函數(shù)都可以用正弦函數(shù)和余弦函數(shù)構(gòu)成的無窮級數(shù)來表示
這樣一個周期函數(shù)可以在頻域空間分解成多個正余弦函數(shù)
然后通過歐拉公式 cosX + i sinX = e ix 然而 x = w * t 角度 = 頻率 * 時間
傅里葉變換:
所以傅里葉變換里的e-iwt 就代表的順時針旋轉(zhuǎn)的一個正交基的組合
傅里葉逆變換:
以上就有點偏題了,1.2章就開始介紹算法了:
插入排序: t = C1 * n ^ 2
歸并排序: t = c2 * n * lgn
插入排序就是新建出一個數(shù)組,每次提取舊數(shù)組中的一個數(shù),加入新數(shù)組的同時并保證有序
而這種情況下如果本身數(shù)組是逆序,等于是需要 1 + 2 + 3 + ... + n - 1 = n(1 + n - 1) / 2 = 1/2 * n ^ 2
就是之前的 C1 * n ^ 2
由此則出現(xiàn)了希爾排序(Shell排序) 最糟糕的情況下 希爾排序也能實現(xiàn) t = n^(3/2) 的速度
而歸并排序的排序速度僅次于快排,有二路歸并,多路歸并。
練習1.2
假設(shè)我們正比較插入排序與并軌排序在相同機器上的實現(xiàn)。對規(guī)模為n的輸入,插入排序運行8n^2步,而歸并排序運行64nlgn布,問對哪些n值,插入排序優(yōu)于歸并排序?
求解 8 * n ^ 2 < 64 * n * lgn => n < 8 lgn 通過換底公式 In2 = 0.3, 則 n < 8 * log10 (n) / 0.3
=> n < 26.666 * log10 (n) 然后我通過計算器得到了 n = 43 時 26.666 * log10 (n) 大約是 43.5591
n = 44時 26.666 * log10 (n) 大約是 43.8254 所以n應(yīng)該是從1到43的正整數(shù) n 屬于 N* 且 [1, 43]
n的最小值為何值時,運行時間為100n2的一個算法在相同機器上快于運行時間為2n的另一個而算法
求解 100n^2 < 2 ^ n 由于n是N* 且 n = 3 時 n ^ 2 > 2 ^ n 且 n = 5時 100 < 2 ^ 5
100 * n ^ 2 則最先嘗試 n = 3 * 5 22500 < 32768 不滿足
而 n = 14 19600 > 16384 可以看出 當 n 屬于 N* 且 n >= 15 時滿足條件
2.1 插入排序
插入排序書上有個很好的例子,就是人們在打撲克牌的時候,每次抓到一張新牌,將其加入已經(jīng)整理好的手中,就是一種插入排序的體現(xiàn)。
循環(huán)不變式
初始化: 循環(huán)的第一次迭代之前,它為真
保持: 如果循環(huán)的某次迭代之前它為真,那么下次迭代之前它仍為真。
終止: 在循環(huán)終止時,不變式為我們提供一個有用的性質(zhì),性質(zhì)有助于證明算法是正確的
這部分說明有點抽象 =。=我個人的理解是
- 算法初始化前提:一般是構(gòu)建數(shù)據(jù)結(jié)構(gòu)以及解決邊界問題,在插入排序中,初始化就是
構(gòu)建一個有序數(shù)組,數(shù)組的元素是n1,然后向數(shù)組中插入一個元素(這個插入行為,就是一種循環(huán)行為)
- 所謂的保持:就是持續(xù)調(diào)用這個循環(huán)行為,從舊數(shù)組中提取元素,并將其加入有序數(shù)組。
- 終止就是舊數(shù)組中的所有元素都已經(jīng)加入到新數(shù)組中之后,這個排序操作就可以終止了。
練習:
重寫過程INSERTION-SORT,使之按非升序排序。
INSERTION-SORT(B)
for j = 2 to B.length
key = B[j]
// Insert B[j] into the sorted squenec B[1..j-1]
i = j - 1
while i > 0 and B[i] < key // 冒泡排序
B[i + 1] = B[i]
i = i - 1
A[i + 1] = key
考慮一下查找問題
輸入: n個數(shù)的一個序列A={a1,a2,...,an}和一個值v
輸出:下標i使得v=A[i]或者當v不在A中出現(xiàn)時,v為特殊值NIL.
寫出線性查找的偽代碼,它掃描整個序列來查找v。使用一個循環(huán)不表示來證明你的算法是正確的,確保你的循環(huán)不變式滿足三條必要的性質(zhì)。
SEARCH(A, v)
i = 0
while i < A.length - 1
if(A[i] == v)
return i
else
i = i + 1
return NIL
考慮把兩個n位二進制整數(shù)加起來的問題,這兩個整數(shù)分別存儲在兩個n元數(shù)組A和B中。這兩個整數(shù)的和應(yīng)按二進制形式存儲在一個(n+1)元素組C中。請給出該問題的形式化描述,并寫出偽代碼。
初始化:從最右一位開始,A[n] + B[n], 如果sum > 1 則C[n + 1] = 0 且 C[n] = 1
保持: A[n] + B[n] + C[n + 1], 如果 sum = 3 則C[n + 1] = 1, C[n] = 1; 如果 sum = 2 則C[n + 1] = 0 ,C[n] = 1; 如果 sum = 1或0, 則C[n + 1] = sum;
終止:n = 0
ADD-BINARY(A,B,C)
i = A.length() - 1
while(i > 0)
sum = A[i] + B[i] + C[i + 1]
if(sum < 1)
C[i + 1] = sum
else if(sum == 2)
C[i + 1] = 0
C[i] = 1
else
C[i + 1] = 1
C[i] = 1
i = i - 1
2.2 分析算法
書上提到,本書假定一種通用的單處理器計算模型———隨機訪問機(RAM random-access machine)來作為我們的實現(xiàn)技術(shù),算法可以用計算機程序來實現(xiàn)。
其中
最壞情況與平均情況分析
增長量級
在不同應(yīng)用場景下,有時考慮的是最壞情況(比如查看數(shù)組中是否含有某個數(shù))
而如果以及確定了數(shù)組里有某個數(shù),找到他的位置,則是考慮平均情況
至于增長量級,O(n2)這樣的寫法以及很常見了,因為相對于n2 , n 或是常數(shù)的量級基本可以忽略不記
練習
考慮排序存儲在數(shù)組A中的n個數(shù):首先找出A中的最小元素并將其與A[1]中的元素進行交換。接著,找出A中的次最小元素,并將其與A[2]中的元素進行交換。對A中前n-1個元素按該方式繼續(xù)。該算法稱為選擇算法(選擇排序),寫出其偽代碼,用O記號給出選擇排序的最好情況與最壞情況運行時間。
SELECTION-SORT(A)
i = 0
while(i < A.length - 1)
min = A[i]
key = i
for j = i to A.length - 1
if(min > A[j])
min = A[j]
key = j
else
continue
swap(i, key)
i++
最好最壞情況都是一樣,因為這個排序方式最終的耗時是
n + (n - 1) + ... + 2 這是一個等差數(shù)列 結(jié)果就是 n *(n + 2) / 2 增長量級O(n^2)
2.3 設(shè)計算法
這里提到了分治法,分治算法的核心思想就是:算法一次或多次遞歸地調(diào)用其自身以解決密切相關(guān)的若干子問題。
三個步驟:
分解(把原問題分解為若干個子問題)
解決(解決子問題,遞歸求解各個子問題)
合并(把子問題的解合并成原問題的解)
這里就舉例了二路歸并排序