1 二分查找算法
int BinarySearch(const ElementType A[], ElementType X, int N) { int mid, right, left; right = 0; left = N - 1; while(right <= left){ // 不斷更新左右邊界的索引(實質是每次循環將待查元素減半,實現了O(logN)時間復雜度),直到左索引大於右索引 mid = (right + left)/2; if(A[mid] > X) left = mid - 1; else if(A[mid] < X) right = mid + 1; else return mid; } return -1; }
二分查找算法適合:只需查找,不需要插入(O(N)復雜度?)和刪除的情況。如查詢元素周期表這種較穩定的數據。
2 歐幾里德算法(求最大公因數)
1 unsigned int Gcd(unsigned int M, unsigned int N) 2 { 3 unsigned int Rem; 4 5 while(N > 0){ 6 Rem = M % N; 7 M = N; 8 N = Rem; 9 } 10 11 return M; 12 }
若M > N,則第一次循環交換M和N。
若想分析其時間復雜度,則要求循環次數,即生成余數的次數。
可以證明: 當M > N, 則M % N < M / 2
證明:當N <= M/2 時,M % N < M / 2
當N > M/2時,M - N < M / 2,那么也有M % N < M/2.
結論成立。
由此可得:有M、N(M>N)兩個正整數,第一次循環后其余數小於M/2,第二次循環后其余數小於N/2,所以可以說,每兩次循環后,余數最多為原值的一半。
所以最大的求余次數為2logN = O(logN).
2logN並不精確,即使在最壞的情況(如M、N是相鄰的fibonacci數)下,仍然可被優化為1.44logN(每次M和余數的商為1.618,則求余的次數為N關於1.618的對數,即1.44logN)。歐幾里德算法的平均性能需要大量篇幅的精確計算,迭代次數的平均值約為(12ln2 lnN) / π^2+1.47。
3 求冪
最簡單的遞推公式:Xn = Xn-1 * X;
X0 = 1;
需要Θ(n)步和Θ(n)空間。
還可以: Xn = X n/2 * X n/2 = (X * X)n/2 X is even
Xn = X(n-1)/2 * X(n-1)/2 * X = (X * X)(n-1)/2 * X X is odd
long int Pow(long int X,unsigned int N) { if(N == 0) return 1;if(N % 2 == 1) return Pow(X * X, N/2); else return Pow(X * X, (N-1)/2) * X; }
需要Θ(logN)步和Θ(logN)空間。
還可以:Xn = X n/2 * X n/2 X is even
Xn = Xn-1 * X X is odd
1 long int Pow(long int X, unsigned int N) 2 { 3 if(N == 0) 4 return 1; 5 if(N % 2 == 0) 6 return Pow(X*X, N/2); 7 else 8 return Pow(X, N-1) * X; 9 }
需要Θ(logN)步和Θ(logN)空間。
在不影響正確性的前提下對代碼進行微調是很有趣的。
如對第六行的修改:
1) return Pow(Pow(X,2), N/2);
看上去正確,但當N=2時,return Pow(Pow(X,2),1)調用Pow(X,2),Pow(X,2)繼續調用Pow(X,2),每次遞歸沒有向基准情況推進,無限循環直到崩潰。
2) return Pow(Pow(X, N/2), 2);
看上去正確,但當N = 2時, 調用Pow(X,2),再調用Pow(X,2)...,同(1).
3) return Pow(X, N/2) * Pow(X, N/2);
正確,但影響效率。
每次調用都有兩次遞歸。則總步數為20 + 21 + 22 + ... 2logN = 2logN+1 -1 = 2N-1
則需O(N)步和O(N)空間。(待驗證)
以及和上述算法相同的迭代算法。
long int Pow(long int X, unsigned N) { long int a = 1; while(N > 0){ if(N % 2 != 0) a *= X; N = N/2; X *= X; } return a; }
例如 X23 = X * (X * X)11 = X * X2 * (X2 * X2)5 = X * X2 * X4 *(X4*X4)2 = X * X2 * X4 * (X8 * X8)1 = X * X2 * X4 * X16 = X23
該程序中定義了一個變量a,整個程序中保證a * XN不變,則當N = 0時,a *XN = a * X0 = a,說明這是a的值即我們要求的值。
通常,定義一個不變量,使它在狀態間保持不變,這種技術是構建迭代算法的強有力的方法。