1. 程式人生 > >考研 演算法【資料結構】時間複雜度的計算 配套例子詳解

考研 演算法【資料結構】時間複雜度的計算 配套例子詳解

【資料結構】時間複雜度的計算  配套例子詳解

一、什麼是演算法:

演算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,演算法代表著用系統的方法描述解決問題的策略機制。

演算法的特徵:

一個演算法應該具有以下五個重要的特徵:

有窮性(Finiteness)

演算法的有窮性是指演算法必須能在執行有限個步驟之後終止;

確切性(Definiteness)

演算法的每一步驟必須有確切的定義;

輸入項(Input)

一個演算法有0個或多個輸入,以刻畫運算物件的初始情況,所謂0個輸入是指演算法本身定出了初始條件;

輸出項(Output)

一個演算法有一個或多個輸出,以反映對輸入資料加工後的結果。沒有輸出的演算法是毫無意義的;

可行性(Effectiveness)

演算法中執行的任何計算步驟都是可以被分解為基本的可執行的操作步,即每個計算步都可以在有限時間內完成(也稱之為有效性)。

二、演算法效率的度量:

雖然計算機能快速的完成運算處理,但實際上, 對一定規範的輸入,在有限時間內獲得所要求的輸出。如果一個演算法有缺陷,或不適合於某個問題,執行這個演算法將不會解決這個問題。不同的演算法可能用不同的時間、空間或效率來完成同樣的任務。所以,一個演算法的優劣可以用空間複雜度與時間複雜度來衡量。 演算法的效率主要由以下兩個複雜度來評估: 時間複雜度:評估執行程式所需的時間。可以估算出程式對處理器的使用程度。 空間複雜度

:評估執行程式所需的儲存空間。可以估算出程式對計算機記憶體的使用程度。

三、時間複雜度:

演算法的時間複雜度是指執行演算法所需要的計算工作量。是同一問題可用不同演算法解決,而一個演算法的質量優劣將影響到演算法乃至程式的效率。演算法分析的目的在於選擇合適演算法和改進演算法。電腦科學中,演算法的時間複雜度是一個函式,它定性描述了該演算法的執行時間。這是一個關於代表演算法輸入值的字串的長度的函式。一般來說,計算機演算法是問題規模n 的函式f(n),演算法的時間複雜度也因此記做。

T(n)=Ο(f(n))

不包括這個函式的低階項和首項係數。使用這種方式時,時間複雜度可被稱為是漸近的,它考察當輸入值大小趨近無窮時的情況。因此,問題的規模n 越大,演算法執行的時間的增長率與f(n) 的增長率正相關,稱作漸進時間複雜度(Asymptotic Time Complexity)。

大O表示法O(f(n)中的f(n)的值可以為1、n、logn、n²等,因此我們可以將O(1)、O(n)、O(logn)、O(n²)分別可以稱為常數階、線性階、對數階和平方階。

常數階 

// 常數階

int result = 100; //執行程式只執行一次  

result ++ ;  //執行一次

System.out.println ("Hello!"+result); //執行一次 

上面演算法的執行的次數的函式為f(n)=3,根據推導大O階的規則1,每次執行程式每條語句執行一次,所以這個演算法的時間複雜度仍舊是O(1),我們可以稱之為常數階。

線性階 

//線性階

for(int i=0;i<n;i++){

   System.out.println(result[i]);  //執行一次

}

線性階主要要分析迴圈結構的執行情況。上面演算法迴圈體中的程式碼執行了n次,因此時間複雜度為O(n),實際上,在for迴圈裡面的所有時間複雜度為O(1)的語句總的時間複雜度都是O(n)。

對數階 

// 對數階

int result=1;

while(result<n){

    result=result*2; //時間複雜度為O(1)

}

可以看出上面的程式碼,隨著result每次乘以2後,都會越來越接近n,當result大於等於n時就會退出迴圈。如果迴圈的次數為T,所以2^T=n於是T=log₂n,因此得出這個演算法的時間複雜度為O(logn)。

平方階 

// 平方階

for(int i=0;i<n;i++){  
 
   for(int j=0;j<n;i++){

       System.out.println(result[i][j]);  //執行一次

   }

}

這是一個迴圈巢狀的語句,很明顯內層迴圈的時間複雜度在講到線性階時就已經得知是O(n),又經過了外層迴圈n次,那麼這段演算法的時間複雜度則為O(n²)。 

多個複雜度組合:順序結構

// 多個複雜度組合

for(int i=0;i<n;i++){  
 
   for(int j=0;j<n;i++){

       System.out.println(result[i][j]);  //執行一次

   }

}

for(int i=0;i<n;i++){  

   System.out.println(result[i]);  //執行一次

}

對於順序執行的語句或者演算法,總的時間複雜度等於其中最大的時間複雜度。所以對於以上的程式碼,時間複雜度為O(n²)。 

多個複雜度組合:選擇結構

// 多個複雜度組合
if(flag){

   for(int i=0;i<n;i++){  
 
       for(int j=0;j<n;i++){

          System.out.println(result[i][j]);  //執行一次

       }

    }

}else{

    for(int i=0;i<n;i++){  

       System.out.println(result[i]);  //執行一次

    }

}

對於條件判斷語句,總的時間複雜度等於其中時間複雜度最大的路徑的時間複雜度。所以對於以上的程式碼,時間複雜度為O(n²)。 

四、例子評註說明:

//題目一
void fun(int n){
    int i,j,x=0;
    for(i=1;i<n;i++){
       for(j=n;j>=i+1;j--){
           x++;
       }
    }
}

【分析】基本運算是語句 x++,假設執行次數為T(n),則有T\left ( n \right )= \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}1=\frac{n(n-1)}{2} ,所以時間複雜度為O(n^{2})。

//題目二
void fun(int n){
    int i=0;
    while(i*i*i<=n){
        i++;
    }
}

【分析】基本運算是語句 x++,假設執行次數為T(n),則有T\left ( n \right )\times T\left ( n \right )\times T\left ( n \right )\leqslant n ,即T\left ( n \right )^{3}\leqslant n,所以時間複雜度為T\left ( n \right )\leq \sqrt[3]{n}=O(\sqrt[3]{n})

//題目三
int m=0,i,j;
for(i=1;i<=n;i++){
    for(j=1;j<=2*i;j++){
        m++;
    }
}

【分析】基本運算是語句 m++,假設執行次數為T(n),則有T\left ( n \right )= \sum_{i=1}^{n}\sum_{j=1}^{2i}1=\sum_{i=1}^{n}2i=2\sum_{i=1}^{n}i=\n(n-1)n ,所以時間複雜度為O(n^{2})。

//題目四
void fun(int n){
    int i,k;
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
            k=1;
            while(k<=n){
                k = 5*k;
            }
        }
    }
}

【分析】基本運算是語句 k = 5*k;,假設執行時間為T(n),對於j每迴圈一次,該語句的執行次數為m,有5^{m}\leq n,即m\leq \log_{5}n則有T\left ( n \right )= \sum_{i=1}^{n}\sum_{j=1}^{n}m=m \sum_{i=1}^{n}\sum_{j=1}^{n}1=mn^{2}=n^{2}\log_{5}n=O(n^{2}\log_{5}n) 。

掌握一定的解題技巧,所有同類型的就可以迎刃而解了。