1.演算法的效率
兩個維度
時間複雜度 :評估執行程式所需的時間。可以估算出程式對處理器的使用程度。
空間複雜度 : 評估執行程式所需的儲存空間。可以估算出程式對計算機記憶體的使用程度。
2.時間複雜度
時間頻度 一個演算法的執行時間與語句執行次數成正比,一個演算法中語句執行的次數稱為語句頻度或者是時間頻度。記為 T(n)
時間複雜度
前面提到的時間頻度T(n)中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道
它變化時呈現什麼規律,為此我們引入時間複雜度的概念。一般情況下,演算法中基本操作重複執行的次數是問題規模n
的某個函式,用T(n)表示,若有某個輔助函式f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱
f(n)是T(n)的同數量級函式,記作T(n)=O(f(n)),它稱為演算法的漸進時間複雜度,簡稱時間複雜度。
3.大O表示法
像前面用O( )來體現演算法時間複雜度的記法,我們稱之為大O表示法。
推導大O階
推導大O階,我們可以按照如下的規則來進行推導,得到的結果就是大O表示法:
1.用常數1來取代執行時間中所有加法常數。
2.修改後的執行次數函式中,只保留最高階項
3.如果最高階項存在且不是1,則去除與這個項相乘的常數。
常數階
先舉了例子,如下所示。
int sum = 0,n = 100; //執行一次 sum = (1+n)*n/2; //執行一次 System.out.println (sum); //執行一次
上面演算法的執行的次數的函式為f(n)=3,根據推導大O階的規則1,我們需要將常數3改為1,則這個演算法的時間複雜度為O(1)。如果sum = (1+n)*n/2這條語句再執行10遍,因為這與問題大小n的值並沒有關係,所以這個演算法的時間複雜度仍舊是O(1),我們可以稱之為常數階。
線性階
線性階主要要分析迴圈結構的執行情況,如下所示。
for(int i=0;i<n;i++){ //時間複雜度為O(1)的演算法 ... }
上面演算法迴圈體中的程式碼執行了n次,因此時間複雜度為O(n)。
對數階
接著看如下程式碼:
int number=1; while(number<n){ number=number*2; //時間複雜度為O(1)的演算法 ... }
可以看出上面的程式碼,隨著number每次乘以2後,都會越來越接近n,當number不小於n時就會退出迴圈。假設迴圈的次數為X,則由2^x=n得出x=log₂n,因此得出這個演算法的時間複雜度為O(logn)。
平方階
下面的程式碼是迴圈巢狀:
for(int i=0;i<n;i++){ for(int j=0;j<n;i++){ //複雜度為O(1)的演算法 ... } }
內層迴圈的時間複雜度在講到線性階時就已經得知是O(n),現在經過外層迴圈n次,那麼這段演算法的時間複雜度則為O(n²)。
接下來我們來算一下下面演算法的時間複雜度:
for(int i=0;i<n;i++){ for(int j=i;j<n;i++){ //複雜度為O(1)的演算法 ... } }
需要注意的是內迴圈中int j=i,而不是int j=0。當i=0時,內迴圈執行了n次;i=1時內迴圈執行了n-1次,當i=n-1時執行了1次,我們可以推算出總的執行次數為:
n+(n-1)+(n-2)+(n-3)+……+1
=(n+1)+[(n-1)+2]+[(n-2)+3]+[(n-3)+4]+……
=(n+1)+(n+1)+(n+1)+(n+1)+……
=(n+1)n/2
=n(n+1)/2
=n²/2+n/2
根據此前講過的推導大O階的規則的第二條:只保留最高階,因此保留n²/2。根據第三條去掉和這個項的常數,則去掉1/2,最終這段程式碼的時間複雜度為O(n²)。
其他常見覆雜度
除了常數階、線性階、平方階、對數階,還有如下時間複雜度:
f(n)=nlogn時,時間複雜度為O(nlogn),可以稱為nlogn階。
f(n)=n³時,時間複雜度為O(n³),可以稱為立方階。
f(n)=2ⁿ時,時間複雜度為O(2ⁿ),可以稱為指數階。
f(n)=n!時,時間複雜度為O(n!),可以稱為階乘階。
f(n)=(√n時,時間複雜度為O(√n),可以稱為平方根階。
---------------------
點贊好用: https://blog.csdn.net/itachi85/article/details/54882603