一、算法
1、算法是對待定問題求解步驟的一種描述
2、衡量算法的指標:
時間復雜度:執行這個算法需要消耗多少時間,即算法計算執行的基本操作次數
空間復雜度:這個算法需要消耗多少空間,即算法在運行過程中臨時占用存儲空間大小的度量,強調的是輔助空間的大小(對數據進行操作的工作單元和存儲一些計算的輔助單元),而不是指所有數據所占用的空間
3、同一個問題可以用不同的算法解決,而一個算法的優劣將影響到算法乃至程序的效率。算法分析的目的在於為特定的問題選擇合適的算法。一個算法的評價主要從時間復雜度和空間復雜度來考慮
算法在時間的高效性和空間的高效性之間通常是矛盾的,通常我們會假設程序運行在足夠大的內存中,更多地去探究時間復雜度
二、時間復雜度
常見的時間復雜度有:常數階O(1),對數階O(log2n),線性階O(n),線性對數階O(nlog2n),平方階O(n2),立方階O(n3), k次方階O(nk),指數階O(2n)。隨着問題規模n的不斷增大,上述時間復雜度不斷增大,算法的執行效率越低。
- 去掉運行時間中的所有加法常數。
- 只保留最高階項。
- 如果最高階項存在且不是1,去掉與這個最高階相乘的常數得到時間復雜度
1、常數階
int sum = 0, n = 100; /*執行一次*/ sum = (1 + n) * n / 2; /*執行一次*/ printf("%d",sum); /*執行一次*/
2、對數階
int count = 1; while (count < n){ count = count * 2; /*時間復雜度為O(1)的程序步驟序列*/ }
由於每次count乘以2之后,就距離n更近了一分。 也就是說,有多少個2相乘后大於n,則會退出循環。 由2^x=n 得到x=log2n。 所以這個循環的時間復雜度為O(log2n)。
3、線性階
int i; for(i = 0; i < n; i++){ /*時間復雜度為O(1)的程序步驟序列*/ }
4、平方階
int i, j; for(i = 0; i < n; i++){ for(j = 0; j < n; j++){ /*時間復雜度為O(1)的程序步驟序列*/ } }
int i, j; for(i = 0; i < n; i++){ for(j = i; j < n; j++){ /*注意j = i而不是0*/ /*時間復雜度為O(1)的程序步驟序列*/ } }
由於當i=0時,內循環執行了n次,當i = 1時,執行了n-1次,……當i=n-1時,執行了1次。所以總的執行次數為:
5、立方階
int i, j; for(i = 1; i < n; i++) for(j = 1; j < n; j++) for(j = 1; j < n; j++){ /*時間復雜度為O(1)的程序步驟序列*/ }
三、空間復雜度
1、遞歸情況
int BinarySearch2(const int* ptr,const int x,const int left,const int right) { int mid=(left+right)/2; while(left<=right) { if(x<ptr[mid]) { return BinarySearch2(ptr,x,left,mid-1); } else if(x>ptr[mid]) { return BinarySearch2(ptr,x,mid+1,right); } return mid; } }
遞歸情況下的空間復雜度:遞歸深度為N*每次遞歸的輔助空間大小,如果每次遞歸的輔助空間為常數,則空間復雜度為O(N)。
對於遞歸的二分查找,遞歸深度是log2^n,每次遞歸的輔助空間為常數,所以空間復雜度為O(log2N)(2為底數下標)
2、非遞歸情況
int BinarySearch1(const int* ptr,const int x,const int len) { int left=0; int right=len-1; int mid=(left+right)/2; while(left<=right) { if(x<ptr[mid]) { right=mid-1; } else if(x>ptr[mid]) { left=mid+1; } else { return mid; } } return -1; }
在這個過程中,輔助空間為常數級別,所以空間復雜度為O(1)