遞迴呼叫分析-最大自序列求和問題
昨天開始看《資料結構與演算法分析-java語言描述》這本書,在第二章舉例了一個演算法問題“最大子序列和問題”,在第三種遞迴方法,由於開始並沒有很好理解,遞迴呼叫在演算法中有很重要,用了最簡單一個例子來加深理解!(當然這種方法在這四種演算法中不是最優的)。
先給出原始碼:
package secondCHA; public class maxSUM3 { static int MaxSubSum( int A[], int Left, int Right) //問題?初始left和right是先給定的嗎?值是多少 { int MaxLeftSum,MaxRightSum; int MaxLeftBorderSum,MaxRightBorderSum; int LeftBorderSum,RightBorderSum; int Center,i; //遞迴終點,left>right的情況是不可能出現的,除非N是負數。 if(Left == Right) { if(A[Left] > 0) return A[Left]; else return 0; } Center = (Left + Right)/2; //重點,遞迴部分 MaxLeftSum = MaxSubSum(A,Left,Center); MaxRightSum = MaxSubSum(A,Center+1,Right); // 計算left達到中間分界處的兩個最大和的和數 MaxLeftBorderSum = 0; LeftBorderSum = 0; for(i = Center;i >= Left;i--) { LeftBorderSum += A[i]; if(LeftBorderSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum; } // 計算right達到中間分界處的兩個最大和的和數 MaxRightBorderSum = 0; RightBorderSum = 0; for(i = Center+1;i <= Right;i++) { RightBorderSum += A[i]; if(RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum; } return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum); } static int Max(int a, int b, int c) { if(a>b&&a>c) return a; else if(b>a&&b>c) return b; else return c; } public static void main(String[] args) { // TODO Auto-generated method stub int[] a={4,-3,5,-2,-1,2,6,-2}; int left=0; int right=a.length-1; System.out.println(MaxSubSum(a,left,right)); } }
用8個元素的陣列進行分析:
A0 |
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
4 |
-3 |
5 |
-2 |
-1 |
2 |
6 |
-2 |
第一次:MaxSubSum(A,0,7)
A0 |
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
4 |
-3 |
5 |
-2 |
-1 |
2 |
6 |
-2 |
Int center=(0+7)/2=3
左邊(A0-A3)部分包含最後一個元素的最大值為:
LeftBorderSum=Max(A3,A3+A2,A3+A2+A1,A3+A2+A1+A0)=4
右邊(A4-A7)部分包含第一個元素的最大值為:
RightBorderSum=Max(A4,A4+A5,A4+A5+A6,A4+A5+A6+A7)=7
return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum=
MaxSubSum(A,0,7)=return Max(MaxSubSum(A,0,3),MaxSubSum(A,4,7),11);
第一次的返回值採用了中MaxLeftSum = MaxSubSum(A,0,3)和MaxRightSum = MaxSubSum(A,4,7)採用了遞迴,則需先確定MaxSubSum(A,0,3)和MaxSubSum(A,4,7),因為引出了第二次分析。
第二次:MaxSubSum(A,0,3),MaxSubSum(A,4,7)
1 MaxSubSum(A,0,3)
A0 |
A1 |
A2 |
A3 |
4 |
-3 |
5 |
-2 |
Int center=(0+3)/2=1
左邊(A0-A1)部分包含最後一個元素的最大值為:
LeftBorderSum=Max(A1,A1+A0,)=1
右邊(A2-A3)部分包含第一個元素的最大值為:
RightBorderSum=Max(A2,,A2+A3)=5
return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum=6);
MaxSubSum(A,0,3)=return Max(MaxSubSum(A,0,1),MaxSubSum(A,2,3),6);
2 MaxSubSum(A,4,7)
A4 |
A5 |
A6 |
A7 |
-1 |
2 |
6 |
-2 |
Int center=(4+7)/2=5
左邊(A4-A5)部分包含最後一個元素的最大值為:
LeftBorderSum=Max(A5,A5+A4)=2
右邊(A6-A7)部分包含第一個元素的最大值為:
RightBorderSum=Max(A6,A6+A7)=6
return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum=8);
MaxSubSum(A,4,7)=return Max(MaxSubSum(A,4,5),MaxSubSum(A,6,7),8);
第三次MaxSubSum(A,0,1),MaxSubSum(A,2,3),MaxSubSum(A,4,5),MaxSubSum(A,6,7)
1.1 MaxSubSum(A,0,1)
A0 |
A1 |
4 |
-3 |
MaxSubSum(A,0,1)=return Max(MaxSubSum(A,0,0),MaxSubSum(A,1,1),1);
1.2 MaxSubSum(A,2,3)
A2 |
A3 |
5 |
-2 |
MaxSubSum(A,2,3)=return Max(MaxSubSum(A,2,2),MaxSubSum(A,3,3),3);
2.1 MaxSubSum(A,4,5)
A4 |
A5 |
-1 |
2 |
MaxSubSum(A,4,5)=return Max(MaxSubSum(A,4,4),MaxSubSum(A,5,5),1);
2.2 MaxSubSum(A,6,7)
A6 |
A7 |
6 |
-2 |
MaxSubSum(A,6,7)=return Max(MaxSubSum(A,6,6),MaxSubSum(A,7,7),4);
第四次MaxSubSum(A,0,0),MaxSubSum(A,1,1),MaxSubSum(A,2,2),MaxSubSum(A,3,3),MaxSubSum(A,4,4),MaxSubSum(A,5,5),MaxSubSum(A,6,6),MaxSubSum(A,7,7)
這時到達遞迴終點,由left=right
if(Left == Right)
{
if(A[Left] > 0)
return A[Left];
else
return 0;
}
因此:MaxSubSum(A,0,0)=4,MaxSubSum(A,1,1)=0,MaxSubSum(A,2,2)=5,MaxSubSum(A,3,3)=0,MaxSubSum(A,4,4)=0,MaxSubSum(A,5,5)=2,MaxSubSum(A,6,6)=6,MaxSubSum(A,7,7)=0
遞迴結束,則將遞迴終點按第四次-第三次-第二次-第一次返回。
MaxSubSum(A,0,0)=4,MaxSubSum(A,1,1)=0,MaxSubSum(A,2,2)=5,MaxSubSum(A,3,3)=0,MaxSubSum(A,4,4)=0,MaxSubSum(A,5,5)=2,MaxSubSum(A,6,6)=6,MaxSubSum(A,7,7)=0.
MaxSubSum(A,0,1)=return Max(MaxSubSum(A,0,0),MaxSubSum(A,1,1),1)=4
MaxSubSum(A,2,3)=return Max(MaxSubSum(A,2,2),MaxSubSum(A,3,3),3)=5
MaxSubSum(A,4,5)=return Max(MaxSubSum(A,4,4),MaxSubSum(A,5,5),1)=2;
MaxSubSum(A,6,7)=return Max(MaxSubSum(A,6,6),MaxSubSum(A,7,7),4)=6
MaxSubSum(A,0,3)=return Max(MaxSubSum(A,0,1),MaxSubSum(A,2,3),6)=6
MaxSubSum(A,4,7)=return Max(MaxSubSum(A,4,5),MaxSubSum(A,6,7),8)=8
MaxSubSum(A,0,7)=return Max(MaxSubSum(A,0,3),MaxSubSum(A,4,7),11)=11
總結:在理解遞迴的時候可以把他看做一個黑盒子,採用歸納證明發的思想,重點關注遞迴終點和遞迴方法。例如本例子中,這個方法的思想是,最大子序列可能有三種情況:左邊,右邊和包含左右挨著的元素組。就可以求左邊最大,右邊最大,左右同時包含最大,這三者中的最大值,其中左右同時包含的最大值是可以求得的,因此只需求左最大和右最大,這裡又可以把左最大和右最大看成2個獨立元素組......遞迴迴圈。遞迴終點,就是進入死迴圈或者無法繼續,這時當left=right時,就需要終點程式。