數據結構與算法(一)

算法效率的度量方法:算法

1. 過後統計方法:經過設計好的測試程序和數據,利用計算機計時器對不一樣算法編制的程序的運行時間進行比較,從而肯定算法效率的高低。數組

缺陷:是根據以及編制好的程序去測試,若是測試的是糟糕的算法,會功虧一簣。函數

2. 事前分析估算方法:在計算機程序編寫前,依據統計方法對算法進行估算。測試

高級語言編寫的程序在計算機上運行時所消耗的時間取決於下列因素:spa

  1. 算法採用的策略,方案。
  2. 編譯產生的代碼質量
  3. 問題的輸入規模
  4. 機器執行指令的速度

因此:一個程序的運行時間依賴於算法的好壞和問題的輸入規模。設計

 在編寫程序的時候,咱們不關心語言、所用的計算機只關心它所實現的算法。code

在分析程序的運行時間的時候,最重要的是把程序當作是獨立於程序設計語言的算法或一系列步驟,把基本操做的數量和輸入模式進行關聯。blog

 函數漸進增加:io

n=1時,算法A1效率不如算法B1;當n=2時,二者效率相等;當n>2時,算法A1開始優於算法B1,隨着n的繼續增長,算法A1比算法B1逐漸拉大差距。因此整體上算法A1比算法B1優秀編譯

定義:給定2個函數f(n)和g(n),若是存在一個整數N,使得對於全部的n>N,f(n)老是比g(n)大,那麼,咱們說f(n)的增加漸進快於g(n)

例如以下算法的增加率:

 

 

經過這組數據能夠看出,當n的值很是大的時候,3n+1已經不能和2n^2的結果進行比較,最終幾乎是能夠忽略不計的,算法G在跟算法I基本已經重合了,

結論:判斷一個算法的時候,函數中的常數和其餘次要項經常能夠忽略,關注主項(最高項)的階數。

注意:不能經過少許的數據來判斷一個算法的好壞。

 算法時間複雜度:
定義:在進行算法分析時,語句總的執行次數T(n)是關於問題規模n的函數,進而分析T(n)隨n的變化狀況並肯定T(n)的數量級,算法的時間複雜度,也就是算法的時間量度,記做:T(n)=O(f(n))。他表示隨問題規模n的增大,算法執行時間的增加率和f(n)的增加率相同,稱做算法的漸進時間複雜度,簡稱爲時間複雜度,其中f(n)是問題規模n的某個函數。

用大O()來體現算法時間複雜度的記法,通常狀況下隨着輸入規模n的增大,T(n)增加最慢的算法爲最優算法。

 推導大O階的方法

  1. 用常數1取代運行時間中的全部加法常數。
  2. 在修改後的運行函數中,只保留最高項。
  3. 若是最高項存在且不是1,則除這個項相乘的常數。
  4. 獲得的最後的結果就是O()階

例如:

1.常數階

int sum=0,n=100;

printf("hello word\n");

printf("hello word\n");

printf("hello word\n");

printf("hello word\n");

sum=(1+n)*n/2

全部常數項都可以看作是1,時間複雜度爲O(1);

 2.線性階:

含有非嵌套循環涉及線性階,就是隨着問題規模n的擴大,對應計算次數呈直線增加。

int i,n=100,sum=0;

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

sum=sum+i;

}

循環中的代碼須要執行n次,因此時間複雜度爲O(n)

 3.平方階:

int i,j,n=100;
for(i=0;i<n;i++)
{   
for(j=0;j<n;j++){   printf("hello word")   } }

外層執行一次,內層執行100次,須要執行100*100次,n的平方次,因此時間複雜度爲O(n^2),

若是有三個這樣的循環,則時間複雜度爲O(n^3)

分析下,因爲當i=0時,內循環執行了n次,當i=1時,內循環則執行n-1次.....當i=n-1時,內循環執行1次,因此總的執行次數應該是:- n+(n-1)+(n-2)+...+1 = n(n+1)/2,用咱們推導大O的攻略,第一條忽略,由於沒有常數相加。第二條只保留最高項,因此n/2這項去掉。第三條,去除與最高項相乘的常數,最終得O(n^2)。

 4.對數階

int i=1,n=100;
while(i<n){
i=i*2;
}

因爲2^x=n獲得x=log(2)n,因此這個循環的時間複雜度爲O(log(2)n)

 函數調用的時間複雜度分析:

例1:

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

function(i);

}

void function(int count){

printf("%d",count);

}

 函數體是打印這個參數,function函數的時間複雜度是O(1),因此總體的時間複雜度就是循環的次數O(n)。

例2:

void function(int count){

int j;

for(j=count;j<n;j++){

printf("%d",j);
}
count++;
}

function內部的循環次數隨count的增長而減小,因此它的時間複雜度爲O(n^2)。

 例3:

n++; ##1

function(n);##一個內部循環的函數 O(N^2)
for(i=0;i<n;i++){ function(i);##內部循環的函數 } ## O(N^2)   for(i=0;i<n;i++){   for(j=i;j<n;j++){   printf("%d",j);   }}##O(n^2)

時間複雜度爲O(n^2)

 常見的時間複雜度:

經常使用時間複雜度所耗費的時間從小到大依次是:

O(1)<O(logn)<(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)

最壞狀況與平均狀況:

算法的分析也是相似,咱們查找一個有n個隨機數字數組中的某個數字,最好的狀況是第一個數字就是,那麼算法的時間複雜度爲O(1),但也有可能這個數字就在最後一個位置,它的時間複雜度爲O(n),平均運行時間是指望的運行時間,最壞的運行時間是一種保證,在應用中,這是一種最重要的需求,一般除非特別的指定,咱們提到的運行時間都是最壞狀況的運行時間。

算法的空間複雜度:

 算法的空間複雜度經過計算算法所需的存儲空間實現,算法的空間複雜度的計算公式爲:S(n)=O(f(n)),其中n爲問題的規模,f(n)爲語句關於n所佔空間的函數。

通常狀況"複雜度"指的是時間複雜度 

相關文章
相關標籤/搜索