若是解決一個問題的算法被肯定下來,並用某種證實方法證實其是正確的,那麼接下來就要判斷該算法的運行時間,以及運行時佔用的空間。這一章主要討論html
上述說法實在太過晦澀了。舉一個簡單的例子。當g(N) = N^2時,g(N) = O(N^3),g(N) = O(N^4)都是對的。g(N) = Ω(N), g(N) = Ω(1)也都是對的。g(N) = Θ(N^2)則表示g(N) = O(N^2),g(N) = Ω(N^2)。即當前的結果時最符合g(N)自己的增加趨勢的。如圖所示:算法
有三條重要的法則須要記住:編程
在用大O表示法的時候,要保留高階次冪,丟棄常數項和低階次冪。經過增加率對函數進行分類如圖:數組
咱們總能經過計算極限lim f(N) / g(N) (n->∞)來肯定兩個函數f(N)和g(N)的相對增加率。可使用洛必達準則進行計算。數據結構
好比,f(N) = NlogN和g(N) = N^1.5的相對增加率,便可計算爲f(N) / g(N) = logN / N^0.5 = log^2 N / N。又由於N的增加要快於logN的任意次冪。因此g(N)的增加快於f(N)的增加數據結構和算法
洛必達準則:若lim f(N) = ∞ (n->∞)且lim g(N) = ∞ (n->∞).則lim f(N)/g(N) = lim f'(N)/g'(N) (n->∞)。函數
爲了便於分析問題,咱們假設一個模型計算機。它執行任何一個基礎指令都消耗一個時間單元,而且假設它有無限的內存。學習
// 書上例程 // 計算i^3的累加求和 int sum (int N) { int i, PartialSum; PartialSum = 0; /*1*/ for(i = 1; i <= N; i++) /*2*/ PartialSum += i * i * i;/*3*/ return PartialSum; /*4*/ }
這裏針對每行進行分析:編碼
合計花費1+2N+2+4N+1=6N+4個時間單元。設計
可是實際上咱們不用每次都這樣分析,由於面對成百上千行的程序時,咱們不可能每一行都這樣分析。只需計算最高階。可以看出for循環佔用時間最多。所以時間複雜度爲O(N)
for (i = 0; i < N; i++) for (j=0; j < N; j++) k++; // 1 * N * N = N^2,時間複雜度爲O(N^2)
for (i = 0; i < N; i++) A[i] = 0; // O(N) for (i = 0; i < N; i++) for (j = 0; j < N; j++) A[i] += A[j] + i + j; // O(N^2) // 總時間爲O(N) + O(N^2),所以取最高階,總時間複雜度爲O(N^2)
咱們要避免在遞歸調用中作重複的工做。
最大子序列問題:給定整數A1, A2, ... , AN(可能有負數),求任意連續整數和的最大值。若是全部整數均爲負數,則最大子序列和爲0
// 書上例程 int MaxSubsequenceSum(const int A[], int N) { int ThisSum, MaxSum, i, j, k; MaxSum = 0; for (i = 0; i < N; i++) { for (j = i; j < N; j++) { ThisSum = 0; for (k = i; k <= j; k++) { ThisSum += A[k]; } if (ThisSum > MaxSum) { MaxSum = ThisSum; } } } return MaxSum; }
int MaxSubsequenceSum(const int A[], int N) { int ThisSum, MaxSum, i, j, k; MaxSum = 0; for (i = 0; i < N; i++) { ThisSum = 0; for (j = i; j < N; j++) { ThisSum += A[k]; if (ThisSum > MaxSum) { MaxSum = ThisSum; } } } return MaxSum; }
// 書上例程 int max3(int a, int b, int c) { int x; x = a > b? a: b; return (x > c? x: c); } int MaxSubsequenceSum(const int A[], int Left, int Right) { int MaxLeftSum, MaxRightSum; int MaxLeftBorderSum, MaxRightBorderSum; int MaxLeftThisSum, MaxRightThisSum; int Center; int cnt; if (Left == Right) { if (A[Left] > 0) { return A[Left]; } else { return 0; } } Center = (Left + Right) / 2; MaxLeftSum = MaxSubsequenceSum(A, Left, Center); MaxRightSum = MaxSubsequenceSum(A, Center + 1, Right); MaxLeftBorderSum = 0; MaxLeftThisSum = 0; for (cnt = Center; cnt >= Left; cnt--) { MaxLeftThisSum += A[cnt]; if (MaxLeftThisSum > MaxLeftBorderSum) { MaxLeftBorderSum = MaxLeftThisSum; } } MaxRightBorderSum = 0; MaxRightThisSum = 0; for (cnt = Center + 1; cnt <= Right; cnt++) { MaxRightThisSum += A[cnt]; if (MaxRightThisSum > MaxRightBorderSum) { MaxRightBorderSum = MaxRightThisSum; } } return max3(MaxLeftSum, MaxRightSum, MaxRightBorderSum + MaxLeftBorderSum); }
//書上例程 int MaxSubsequenceSum(const int A[], int N) { int ThisSum, MaxSum, j; ThisSum = MaxSum = 0; for (j = 0; j < N; j++) { ThisSum += A[j]; if (ThisSum > MaxSum) { MaxSum = ThisSum; } else if (ThisSum < 0) { ThisSum = 0; } } return MaxSum; }
若是一個算法用常數時間(O(1))將問題的大小消減爲其一部分(一般是1/2),那麼該算法就是O(logN)。另外一方面,若是使用常數時間只是把問題減小一個常數(如將問題減小1),那麼這種算法就是O(N)的。
// 書上例程,時間複雜度爲O(logN) #define NotFound -1 int BinarySearch(const ElementType A[], ElementType X, int N) { int low, high, mid; low = 0; high = N - 1; mid = (low + high) / 2; while (low <= high) { if (A[mid] < X) { low = mid + 1; } else if (A[mid] > X) { high = mid - 1; } else { return mid; } } return NotFound; }
// 書上例程:展轉相除法,時間複雜度O(logN) int test(unsigned int M, ungisned int N) { unsigned int Rem; while (N > 0) { Rem = M % N; M = N; N = Rem; } return M; }
// 書上例程,時間複雜度O(logN) long int Pow(long int X, unsigned int N) { if (N == 0) { return 1; } else if (N == 1) { return X; } if (isEven(N)) { return Pow(X * X, N / 2); } else { return Pow(X * X, N / 2) * X; } }
//書上例程,時間複雜度O(N^2) void test(int N) { int Rel = 0, Tot = 0; int i, j; for( i = 1; i <= N; i++) { for ( j = i + 1, j <= N; j++) { Tot++; if (Gcd(i,j) == 1) { Rel++; } } } printf("%f", (double)Rel / Tot); }
有時分析會估計過大。那麼或者須要分析的更細緻,或者平均運行時間顯著小於最壞情形的運行時間而又沒辦法對所得的界加以改進。許多算法,最壞的界實經過某個不良輸入達到的,可是實踐中它一般是估計過大的。對於大多數這種問題,平均情形的分析是極其複雜的,或者未解決的。最壞情形的界有些過度悲觀可是它是最好的已知解析結果。
敬告:
本文原創,歡迎你們學習轉載_
轉載請在顯著位置註明:
博主ID:CrazyCatJack
原始博文連接地址:http://www.javashuo.com/article/p-tggaygmo-hu.html