伙伴鏈接:http://www.cnblogs.com/haoying1994/
一、設計思想
本次實驗是在前一次的實驗的基礎上將初始數組的頭和尾部連接起來,形成環,在環中尋找子數組中和的最大值。
關於尋找環狀數組中子數組和的最大值,在課堂上按照老師的提示,將初始數組首尾相接形成環,再將其從任意一點斷開,形成不同的數組,再從中找出子數組中和的最大值。於是我們進過思考,既然斷裂的部位是隨機的,那么初始數組中任意的一個數都可能成為斷裂后數組的第一個數,且可以利用循環可以實現,循環次數就是初始數組中數的個數。將循環套在之前計算子數組和最大值的循環的外面就可以基本實現本題目的要求。
關於返回最大子數組的問題,在每一次調整數組順序后,根據max函數選擇的子數組和變化,若當前數是和最大子數組中的一個元素,那么記錄其初始位置,使其值為該循環次數的計數器的值,同理,判斷出和最大子數組的結束位置,由於該數組是一個環,因此利用減去數組長度值來實現數組呈鏈狀向后推移。最后輸出初始位置和結束位置之間的子數組位置。
二、出現的問題
關於這次的實驗,我們在一開始對題意的理解上出現了分歧,我們其中一個認為是將初始數組的首尾相接,在環中尋找其子數組和的最大值,思路就是和設計思想中利用循環嵌套來實現,而另一個認為是將所有子數組首尾相接,在計算子數組和的時候導致了互相聽不懂對方的思路,后來經過詢問同學以及討論,最終確定了這次編程的大致方向。
在尋找環狀數組中子數組最大值的時候,最大值的判斷環節能夠順利完成,比較費周折的是輸出和最大值子數組的位置,這也就意味着需要記錄初始位置以及結束位置這兩個數值,在一般情況下,根據設計思路基本能夠實現此功能,但是在特殊情況下,比如有兩個子數組都是和最大的子數組,還有就是在所有數都是正數的時候,和所有數都是負數的時候,會出現問題,經過我們改正,使得都是正數和負數的情況下,子數組位置是正確輸出的,而在出現多個和相等且最大的子數組時,只能輸出其中的一個位置。
三、可能的解決方案
本次實驗的大致框架和思路是保持一致的,在記錄和最大子數組位置的環節,我們討論了兩種解決方案:
1.在輸入初始數組時,記錄每一個數字的位置,在判斷子數組和最大值的時候判斷當前數是初始數組的哪一個數,輸出其位置,但是初始數組中數值相同時會出現問題,因此沒有選擇這種方法。
2.在每一次調整數組順序后,根據max函數選擇的子數組和變化,若當前數是和最大子數組中的一個元素,那么記錄其初始位置,使其值為該循環次數的計數器的值,同理,判斷出和最大子數組的結束位置。
四、源程序
//2016 3.21 Cheng Qiqin Hao Ying //返回一個整數數組中最大子數組的和 #include<iostream> using namespace std; int main() { int Array[100],sumOfArray[100],location[100][2],loc=0;//sumOfArray用於存放包含目前數的子數組的和的最大值,sum用來存放不包含當前數的所有子數組的和的最大值 int i,j,length=0,sum,n=0, NegExit=0,Max;//用來記錄數組長,sum用來存放不包含當前數的所有子數組的和的最大值,NegExit用來記錄數組是否不含有正數 cout<<"請輸入數組:"<<endl; for(length=0;;) { cin>>Array[length]; if(Array[length]>0)//出現正數 { NegExit=1; } length++; if(getchar()=='\n') { break; } } cout<<"這個數組的長度為:"<<length<<endl; if(NegExit==1)//數組中有正數時,需要找到和最大的子數組,並記錄子數組的位置 { for(i=0;i<length;i++) { sumOfArray[i]=Array[0]; sum=0; location[i][0]=i; location[i][1]=i; for(j=1;j<length;j++) { sum=max(sum,sumOfArray[i]); if(sumOfArray[i]<0&&sum<Array[j]) { location[i][0]=i+j; location[i][1]=i+j; } sumOfArray[i]=max(sumOfArray[i]+Array[j],Array[j]); if(sum<sumOfArray[i]) { location[i][1]=i+j; } } int arr=Array[0];//將數組中的數向前移,實現數組首尾相連的功能 for(j=1;j<length;j++) { Array[j-1]=Array[j]; } Array[length-1]=arr; sumOfArray[i]=max(sum,sumOfArray[i]);//到數組中第i個數依次移到第一位時和最大的子數組的和 if(i>0) { if(sumOfArray[i]>sumOfArray[i-1]) { loc=i; } sumOfArray[i]=max(sumOfArray[i-1],sumOfArray[i]);//此時所有子數組的和最大的值 } } Max=sumOfArray[i-1];//這個整數數組的子數組之和的最大值 } else//當數組中不存在正數時 { Max=Array[0]; for(i=0;i<length;i++) { if(Max<=Array[i]) { Max=Array[i]; location[loc][0]=i; location[loc][1]=i; } } } cout<<"這個整數數組的子數組之和的最大值為"<<Max<<endl; cout<<"子數組之和最大子數組的位置為:"<<endl; cout<<"注:輸出的數表示這個子數組的每個元素是整數數組的第幾個數"<<endl; cout<<" 若數組中有多個子數組之和最大,輸出其中的一個"<<endl; cout<<"和最大的子數組位置為:"; for(j=location[loc][0];j<=location[loc][1];j++) { if(j<length) { cout<<"Array["<<j<<"] "; } else { cout<<"Array["<<j-length<<"] "; } } cout<<endl; return 0; }
五、結果截圖
當數值中既有正數又有負數:
當數組中都是正數:
當數組中都是負數:
六、總結
通過這次的實驗,使我獲得了許多知識和能力,在之前實驗的基礎上使我們能夠沿着之前的思路繼續進行其他的功能實現。而這次實驗主要考察的就是就是找到子數組的位置,如何找到和最大的子數組的位置這一點是比較有難度的,也是我們這周重點解決的問題。
在上次求子數組和最大值的基礎上,本次程序要將數組首尾相接,再判斷其子數組和的最大值,一開始的時候還是一頭霧水,經老師課堂上的提點,課下我們反復斟酌了老師的意思,最后完成了此功能。再此過程中,我們彼此都各有收獲和進步,首先在兩人的討論下,會發現許多自己想不到的問題,這就使我們的編程效率提高了,減少了走彎路的時間。在調試程序時,出現問題時,通過兩人討論,相互幫助,可以盡快解決問題,這也使我們之間更有默契,合作更加協調。比如在尋找子數組位置的時候,在限制條件中由於之前的測試事例都是既有正數也有負數的,因此在if語句中有大於零和小於零的限制,忽略了都是正數和都是負數的情況,在彼此的幫助和復審,調試的過程中將錯誤的地方找了出來。
在之前實驗:返回一個整數數組中最大子數組的和的基礎上學到了更多的知識,更加的鍛煉了我的邏輯思維,使我對於計算子數組和的最大值的方法得到了更加深入的了解,雖然我們知道在考慮的方面肯定還存在着不足,我們考慮的還不是很周全,但是我們在這個過程中還是收獲了許多的經驗,相信這次的編程會給我接下來的實驗一定的啟發,我會學以致用,更加努力完成接下來的實驗!
七、工作照