《數據結構與算法分析》學習筆記(二)——算法分析


一、對算法分析方法的最簡單的理解和使用方法

1、首先大家可能一般會被那些數學的概念搞暈,其實簡單理解下來,就是假設任何語句執行的效率都是一樣的,所以設定每一個語句的執行時間都是一個時間單位,那么只要計算這個程序到底執行了多少語句,就可以算出其時間復雜度。

2、其次就是我們要明白,我們是個估算,所以可以進行化簡,明顯我們可以忽略那些相對來說低階的項,只分洗最高階項。然后主要就是有這些常見的法則:

(1)FOR循環

一次for循環的運行時間至多是該for循環內語句的運行時間乘以迭代次數。

(2)嵌套的FOR循環

肯定是計算最內層循環語句的執行次數,然后再乘以所以循環的迭代次數。

(3)整個程序

其實找到循環迭代次數最多,嵌套最多的進行計算就好。

3、當然,我們計算的只是大概值,而且為了計算的簡便,我們一邊進行適當的放大,即只考慮最壞最壞的情況,算出其時間復雜度即可。

二、最大子序列

書中通過4種不同的解法來進一步強化我們應該如何計算時間復雜度,小白我也好好學習了下,在此寫下學習筆記。

題目:算出一個整數序列中最大的子序列的值。

算法一:

int MaxSubsequenceSum1(const int A[],int N)

{

int thisSum , MaxSum;

MaxSum=0;

for (int i =0; i<N; i++)

{

for (int j=i; j<N; j++)

{

thisSum=0;

for (int K =i; K<=j; K++)

{

thisSum+=A[K];

}

if(thisSum>MaxSum)

{

MaxSum=thisSum;

}

}

}

  

if(MaxSum==0)

{

int i;

for(i=0;i<N;i++)

{

if(A[i]!=0)

break;

}

if(i!=N)

{

int Max=A[0];

for(int j=0;j<N;j++)

{

if(A[j]>Max)

{

Max=A[j];

}

}

MaxSum=Max;

  

}

}

 

  

  

return MaxSum;

  

 

}


我們可以看出其最大的for循環有三重,而且最壞的可能迭代次數都是N,所以我們可以很容易的得出,此算法的時間復雜度為O(N^3),其中資源最明顯的浪費就在重復計算了從低i到第k的子序列的值,所以算法二便是進行了簡單的修改。
算法二:

int MaxSubsequenceSum2(const int A[],int N)

{

int thisSum,MaxSum;

MaxSum=0;

for (int i=0; i<N; i++)

{

thisSum=0;

for (int j=i; j<N; j++)

{

thisSum+=A[j];

if(thisSum>MaxSum)

{

MaxSum=thisSum;

}

}

}

  

  

if(MaxSum==0)

{

int i;

for(i=0;i<N;i++)

{

if(A[i]!=0)

break;

}

if(i!=N)

{

int Max=A[0];

for(int j=0;j<N;j++)

{

if(A[j]>Max)

{

Max=A[j];

}

}

MaxSum=Max;

  

}

}

  

  

return MaxSum;

 

 

}


其實改變的地方即使采用的累加的策略而已,但卻使效率大大的提高了,所以這里也是提高算法效率的一個小小的技巧,即盡力減少不必要的計算,盡量利用現有的計算結果。
算法三:

int Max3(const int a,const int b,const int c)

{

int temp = (a>b)?a:b;

temp=(temp>c)?temp:c;

return temp;

}

 

 

 

int MaxSubSum(const int A[],int Left,int Right)

{

int MaxLeftSum,MaxRightSum;

int MaxLeftBorderSum,MaxRightBorderSum;

int LeftBorderSum,RightBorderSum;

  

if(Left==Right)

{

if(A[Left]>0)

return A[Left];

else

return 0;

}

  

int center=(Right+Left)/2;

  

MaxLeftSum=MaxSubSum(A, Left, center);

MaxRightSum=MaxSubSum(A, center+1, Right);

  

LeftBorderSum=MaxLeftBorderSum=0;

for(int i=center;i>=Left;i--)

{

LeftBorderSum+=A[i];

if(LeftBorderSum>MaxLeftBorderSum)

{

MaxLeftBorderSum=LeftBorderSum;

}

}

  

RightBorderSum=MaxRightBorderSum=0;

for(int i=center+1;i<=Right;i++)

{

RightBorderSum+=A[i];

if (RightBorderSum>MaxRightBorderSum)

{

MaxRightBorderSum=RightBorderSum;

}

}

  

return Max3(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);

  

}

 

int MaxSubsequenceSum3(const int A[],int N)

{

int MaxSum = MaxSubSum(A, 0, N-1);

  

if(MaxSum==0)

{

int i;

for(i=0;i<N;i++)

{

if(A[i]!=0)

break;

}

if(i!=N)

{

int Max=A[0];

for(int j=0;j<N;j++)

{

if(A[j]>Max)

{

Max=A[j];

}

}

MaxSum=Max;

  

}

}

 

return MaxSum;

 

}

 

這個算法使用了分治的思想,還有遞歸的思想,即把一個問題不斷的分解成類似的規模更小的子問題來解決,所以這里我們要求一個序列的最大子序列,其實就是求左半部分,有伴部分和中間部分的最大子序列,而求左半部分,后半部分的最大子序列顯然是將問題的規模變小了,所以可以遞歸使用,直到剩下一個數的情況.而中間部分呢,則取左右兩邊,左邊從右往左,右邊從左往右的最大子序列。然后加起來作為中間部分的值,最后比較中間部分,左半部分,后半部分三部分的值就可以得到結果啦。

 

 

算法四:

int MaxSubsequenceSum4(const int A[],int N)

{

int thisSum,MaxSum;

thisSum = MaxSum=0;

  

for(int i=0;i<N;i++)

{

thisSum+=A[i];

if(thisSum>MaxSum)

{

MaxSum=thisSum;

}

else if(thisSum<0)

{

thisSum=0;

}

}

  

  

if(MaxSum==0)

{

int i;

for(i=0;i<N;i++)

{

if(A[i]!=0)

break;

}

if(i!=N)

{

int Max=A[0];

for(int j=0;j<N;j++)

{

if(A[j]>Max)

{

Max=A[j];

}

}

MaxSum=Max;

  

}

}

  

return MaxSum;

 

}

 

 

最后一個算法就比較牛逼啦,這個算法竟然只是N階的,大家可以想想這個算法的速度有多快,而且如果不考慮全是負數的情況的話,還可以做到隨時讀入,隨時釋放內存的強大功能,在此深深膜拜一下。

 









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM