數據結構子時間復雜度
算法之時間復雜度
雖然計算機能快速的完成運算處理,但實際上,它也需要根據輸入數據的大小和算法效率來消耗一定的處理器資源。要想編寫出能高效運行的程序,我們就需要考慮到算法的效率。
算法的效率主要由二哥復雜度來評估:
時間復雜度:評估執行程序所需的時間。可以估算出程序對處理器的使用程度。
空間復雜度:評估執行程序所需的存儲空間。可以估算出程序對計算機內存的使用程度。
時間復雜度
時間頻度
一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為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))【大O表示法】,它稱為算法的漸進時間復雜度,簡稱時間復雜度。
大O表示法
像前面用O( )來體現算法時間復雜度的記法,我們稱之為大O表示法。
大O表示法O(f(n)中的f(n)的值可以為1、n、logn、n2等,因此我們可以將O(1)、O(n)、O(logn)、O(n2)分別可以稱為常數階、線性階、對數階和平方階,那麽如何推導出f(n)的值呢?我們接著來看推導大O階的方法。
推到大O階
用常數1來取代運行時間中所有加法常數。
修改後的運行次數函數中,只保留最高階項 。
如果最高階項存在且不是1,則去除與這個項相乘的常數。
舉例:
常數階
int a=1 ;//執行一次
int b-1; //執行一次
int c=a+b;//執行一次
上面算法的運行的次數的函數為f(n)=3,根據推導大O階的規則1,我們需要將常數3改為1,則這個算法的時間復雜度為O(1) 。如果int c =a+b這條語句再執行100遍,時間復雜度仍然是O(1), 因為這與問題大小n的值並沒有關系,我們可以稱之為常數階。
線性階
for(int i=0;i<n;i++) { var a=n; // 1*n次 }
上面的循環執行了n次,因此時間復雜度為O(n)。 如果再循環體裏面再加一條 var b=2n, 時間復雜度仍然為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(n2)。
常見算法的時間復雜度
冒泡排序(交換排序)
最好:O(N)
平均:O(N^2)
最壞:O(N^2)
特點:1、冒泡排序是一種用時間換空間的排序方法,n小時好 。2、最壞情況是把順序的排列變成逆序,或者把逆序的數列變成順序,最差時間復雜度O(N^2)只是表示其操作次數的數量級 3、最好的情況是數據本來就有序,復雜度為O(n)
快速排序(交換排序)
最好:O(N*log2N)
平均:O(N*log2N)
最壞:O(N^2)
特點:1、n大時好,快速排序比較占用內存,內存隨n的增大而增大,但卻是效率高不穩定的排序算法。 2、劃分之後一邊是一個,一邊是n-1個, 這種極端情況的時間復雜度就是O(N^2) 3、最好的情況是每次都能均勻的劃分序列,O(N*log2N)
直接選擇(選擇排序)
最好:O(N)
平均:O(N^2)
最壞:O(N^2)
數據結構子時間復雜度