數(shù)據(jù)結構與算法算法篇_第1頁
數(shù)據(jù)結構與算法算法篇_第2頁
數(shù)據(jù)結構與算法算法篇_第3頁
數(shù)據(jù)結構與算法算法篇_第4頁
數(shù)據(jù)結構與算法算法篇_第5頁
已閱讀5頁,還剩50頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第八章數(shù)據(jù)結構與算法算法篇數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第1頁。一、算法概述算法的概念算法的特征算法的表示算法的復雜性數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第2頁。1、算法概念:是在有限步驟內求解某一問題所使用的一組定義明確的規(guī)則。通俗點說,就是計算機解題的過程。在這個過程中,無論是形成解題思路還是編寫程序,都是在實施某種算法。前者是推理實現(xiàn)的算法,后者是操作實現(xiàn)的算法。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第3頁。2、算法特征一個算法應該具有以下五個重要的特征:

有窮性:

一個算法必須保證執(zhí)行有限步之后結束;

確切性:

算法的每一步驟必須有確切的定義;

輸入:一個算法有0個或多個輸入,以刻畫運算對象的初始情況,所謂0個輸入是指算法本身定除了初始條件;

輸出:一個算法有一個或多個輸出,以反映對輸入數(shù)據(jù)加工后的結果。沒有輸出的算法是毫無意義的;

可行性:

算法原則上能夠精確地運行,而且人們用筆和紙做有限次運算后即可完成。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第4頁。3、算法表示文字描述用純粹的文件描述一個算法。優(yōu)點較易理解,缺點是難于用計算機語言實現(xiàn)。程序流程圖用圖形的方式描述算法過程。優(yōu)點是較為直觀,缺點與具體語言相關,編寫代碼不易。程序源代碼寫出的算法。優(yōu)點是能直接運行,缺點是難于閱讀。偽語言用類似程序語言的風格寫出算法,克服了上述各種方法的缺點。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第5頁。3、算法的復雜性(算法效率)時間上即描述算法在執(zhí)行中的運行效率,原則上要求算法盡可能地少花時間,即在短時間內得到結果,一個算法的時間效率與該算法處理的問題的規(guī)模及算法程序中的循環(huán)與遞歸的量有關。一般而言,規(guī)模越大,處理所花的時間就越長;算法中循環(huán)與遞歸越多,效率就成指數(shù)級下降??臻g上即算法在運行中消耗的存儲容量。原則上要求算法盡可能地少占用存儲單元。時空上,程序算法是一個矛盾的對立統(tǒng)一。一般來說,兩者成反比。有時是以空間換效率,有時用犧牲效率換空間,視具體情形而言數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第6頁。二、程序流程圖N-S盒圖PAD圖程序流程圖E-R圖數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第7頁。1、N-S盒圖N-S圖也被稱為盒圖或CHAPIN圖。

流程圖由一些特定意義的圖形、流程線及簡要的文字說明構成,它能清晰明確地表示程序的運行過程。在使用過程中,人們發(fā)現(xiàn)流程線不一定是必需的,為此,人們設計了一種新的流程圖,它把整個程序寫在一個大框圖內,這個大框圖由若干個小的基本框圖構成,這種流程圖簡稱N-S圖.數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第8頁。N-S圖結構1.順序結構N-S圖2.選擇結構N-S圖AB條件真假A塊B塊3.循環(huán)結構N-S圖1)當型循環(huán)

2)直到型循環(huán)循環(huán)體當條件為真時循環(huán)體直到條件為真時數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第9頁。PAD圖PAD是問題分析圖(ProblemAnalysisDiagram)的英文縮寫,自1973年由日立公司發(fā)明以來,已經(jīng)得到一定程度的推廣。它用二維數(shù)形結構的圖表示程序的控制流,將這種圖轉換為程序代碼比較容易。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第10頁。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第11頁。程序流程圖

1.

程序流程圖的作用

程序流程圖是人們對解決問題的方法、思路或算法的一種描述。

2.

流程圖采用的符號

(1)起始框

(2)終止框

(3)執(zhí)行框

(4)判別框

(5)進程框(6)數(shù)據(jù)框

主要元素:

(1)方框:表示一個處理步驟

(2)菱形框:表示一個邏輯條件

(3)箭頭:表示控制流向數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第12頁。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第13頁。E-R圖即實體-聯(lián)系圖(EntityRelationshipDiagram),提供了表示實體型、屬性和聯(lián)系的方法,用來描述現(xiàn)實世界的概念模型。

構成E-R圖的基本要素是實體型、屬性和聯(lián)系,其表示方法為:

·實體型(Entity):用矩形表示,矩形框內寫明實體名;比如學生張三豐、學生李尋歡都是實體。如果是弱實體的話,在矩形外面再套實線矩形。

·屬性(Attribute):用橢圓形表示,并用無向邊將其與相應的實體連接起來;比如學生的姓名、學號、性別、都是屬性。如果是多值屬性的話,再橢圓形外面再套實線橢圓。如果是派生屬性則用虛線橢圓表示。

·聯(lián)系(Relationship):用菱形表示,菱形框內寫明聯(lián)系名,并用無向邊分別與有關實體連接起來,同時在無向邊旁標上聯(lián)系的類型(1:1,1:n或m:n)。

比如老師給學生授課存在授課關系,學生選課存在選課關系。如果是弱實體的聯(lián)系則在菱形外面再套菱形。

數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第14頁。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第15頁。三、程序算法要使計算機能完成人們預定的工作,首先必須為如何完成預定的工作設計一個算法,然后再根據(jù)算法編寫程序。計算機程序要對問題的每個對象和處理規(guī)則給出正確詳盡的描述,其中程序的數(shù)據(jù)結構和變量用來描述問題的對象,程序結構、函數(shù)和語句用來描述問題的算法。算法,數(shù)據(jù)結構是程序的兩個重要方面。算法是問題求解過程的精確描述,一個算法由有限條可完全機械地執(zhí)行的、有確定結果的指令組成。指令正確地描述了要完成的任務和它們被執(zhí)行的順序。計算機按算法指令所描述的順序執(zhí)行算法的指令能在有限的步驟內終止,或終止于給出問題的解,或終止于指出問題對此輸入數(shù)據(jù)無解。通常求解一個問題可能會有多種算法可供選擇,選擇的主要標準是算法的正確性和可靠性,簡單性和易理解性。其次是算法所需要的存儲空間少和執(zhí)行更快等。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第16頁。

主要算法:迭代法窮舉搜索法遞推法貪婪法回溯法分治法動態(tài)規(guī)劃法etc數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第17頁。1、迭代法迭代法是用于求方程或方程組近似根的一種常用的算法設計方法。設方程為f(x)=0,用某種數(shù)學方法導出等價的形式x=g(x),然后按以下步驟執(zhí)行:(1)選一個方程的近似根,賦給變量x0;(2)將x0的值保存于變量x1,然后計算g(x1),并將結果存于變量x0;(3)當x0與x1的差的絕對值還小于指定的精度要求時,重復步驟(2)的計算。若方程有根,并且用上述方法計算出來的近似根序列收斂,則按上述方法求得的x0就認為是方程的根。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第18頁?!舅惴ā康ㄇ蠓匠痰母鵾x0=初始近似根;do{x1=x0;x0=g(x1);/*按特定的方程計算新的近似根*/}while(fabs(x0-x1)>Epsilon);printf(“方程的近似根是%f\n”,x0);}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第19頁。2、窮舉搜索法窮舉搜索法是對可能是解的眾多候選解按某種順序進行逐一枚舉和檢驗,并從眾找出那些符合要求的候選解作為問題的解?!締栴}】將A、B、C、D、E、F這六個變量排成如圖所示的三角形,這六個變量分別取[1,6]上的整數(shù),且均不相同。求使三角形三條邊上的變量之和相等的全部解。如圖就是一個解。程序引入變量a、b、c、d、e、f,并讓它們分別順序取1至6的證書,在它們互不相同的條件下,測試由它們排成的如圖所示的三角形三條邊上的變量之和是否相等,如相等即為一種滿足要求的排列,把它們輸出。當這些變量取盡所有的組合后,程序就可得到全部可能的解。細節(jié)見下面的程序。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第20頁。【程序1】#includevoidmain(){inta,b,c,d,e,f;for(a=1;a<=6;a++)for(b=1;b<=6;b++){if(b==a)continue;for(c=1;c<=6;c++){if(c==a)||(c==b)continue;for(d=1;d<=6;d++){if(d==a)||(d==b)||(d==c)continue;for(e=1;e<=6;e++){if(e==a)||(e==b)||(e==c)||(e==d)continue;f=21-(a+b+c+d+e);if((a+b+c==c+d+e))&&(a+b+c==e+f+a)){printf(“%6d,a);printf(“%4d%4d”,b,f);printf(“%2d%4d%4d”,c,d,e);scanf(“%*c”);}}}}}}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第21頁。3、遞推法是利用問題本身所具有的一種遞推關系求問題解的一種方法。設要求問題規(guī)模為N的解,當N=1時,解或為已知,或能非常方便地得到解。能采用遞推法構造算法的問題有重要的遞推性質,即當?shù)玫絾栴}規(guī)模為i-1的解后,由問題的遞推性質,能從已求得的規(guī)模為1,2,…,i-1的一系列解,構造出問題規(guī)模為I的解。這樣,程序可從i=0或i=1出發(fā),重復地,由已知至i-1規(guī)模的解,通過遞推,獲得規(guī)模為i的解,直至得到規(guī)模為N的解。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第22頁。在遞推階段,必須要有終止遞歸的情況。{intn,i,box_count,box_volume,*a;它的一般的算法設計模式如下:{intk,i=strlen(a),j=strlen(b);時空上,程序算法是一個矛盾的對立統(tǒng)一。算法是問題求解過程的精確描述,一個算法由有限條可完全機械地執(zhí)行的、有確定結果的指令組成。A=B=C,A=B<C,A<B=C,A<B<C,A<C<B,A=C<B,B<A=C,輸出:一個算法有一個或多個輸出,以反映對輸入數(shù)據(jù)加工后的結果。它用二維數(shù)形結構的圖表示程序的控制流,將這種圖轉換為程序代碼比較容易。這時只要棧頂元素(3)出棧,即表示從結點(1,2,3)回溯到結點(1,2)。elseif(c[i-1][j]>=c[i][j-1])其次是算法所需要的存儲空間少和執(zhí)行更快等。優(yōu)點是較為直觀,缺點與具體語言相關,編寫代碼不易。這時只要棧頂元素(3)出棧,即表示從結點(1,2,3)回溯到結點(1,2)。(2)解決:若子問題規(guī)模較小而容易被解決則直接解,否則遞歸地解各個子問題;如果元素1進棧,則表示建立并遍歷(1)結點;carry=r/10;if(c[i][j]==c[i-1][j])i–;能采用遞推法構造算法的問題有重要的遞推性質,即當?shù)玫絾栴}規(guī)模為i-1的解后,由問題的遞推性質,能從已求得的規(guī)模為1,2,…,i-1的一系列解,構造出問題規(guī)模為I的解。printf(“\n”);yi←Divide-and-Conquer(Pi)△遞歸解決Pi樹T上的任意一個葉子結點被稱為問題P的一個解狀態(tài)結點;(2)c[i][j]=c[i-1][j-1]+1如果I,j>0,且a[i-1]=b[j-1];當遍歷到葉子結點(1,2,5)時,由于它已是一個回答結點,則保存(或輸出)該結點,并回溯到其雙親結點,繼續(xù)深度遍歷;問題描述:編寫程序,對給定的n(n≦100),計算并輸出k的階乘k!以下先用實例說明動態(tài)規(guī)劃方法的使用。3、回溯法的一般流程和技術計算機程序要對問題的每個對象和處理規(guī)則給出正確詳盡的描述,其中程序的數(shù)據(jù)結構和變量用來描述問題的對象,程序結構、函數(shù)和語句用來描述問題的算法。繼續(xù)這一過程,得到候選組合1,2,3。for(q=j->next;q!=NULL&&q->link!=NULL;q=q->link);【問題】階乘計算問題描述:編寫程序,對給定的n(n≦100),計算并輸出k的階乘k?。╧=1,2,…,n)的全部有效數(shù)字。由于要求的整數(shù)可能大大超出一般整數(shù)的位數(shù),程序用一維數(shù)組存儲長整數(shù),存儲長整數(shù)數(shù)組的每個元素只存儲長整數(shù)的一位數(shù)字。如有m位成整數(shù)N用數(shù)組a[]存儲:N=a[m]×10m-1+a[m-1]×10m-2+…+a[2]×101+a[1]×100并用a[0]存儲長整數(shù)N的位數(shù)m,即a[0]=m。按上述約定,數(shù)組的每個元素存儲k的階乘k!的一位數(shù)字,并從低位到高位依次存于數(shù)組的第二個元素、第三個元素……。例如,5!=120,在數(shù)組中的存儲形式為:3021……首元素3表示長整數(shù)是一個3位數(shù),接著是低位到高位依次是0、2、1,表示成整數(shù)120。計算階乘k!可采用對已求得的階乘(k-1)!連續(xù)累加k-1次后求得。例如,已知4!=24,計算5!,可對原來的24累加4次24后得到120。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第23頁。#include#include#defineMAXN1000voidpnext(inta[],intk){int*b,m=a[0],i,j,r,carry;b=(int*)malloc(sizeof(int)*(m+1));for(i=1;i<=m;i++)b[i]=a[i];for(j=1;j<=k;j++){for(carry=0,i=1;i<=m;i++){r=(ia[i]=r%10;carry=r/10;}if(carry)a[++m]=carry;}free(b);a[0]=m;}voidwrite(int*a,intk){inti;printf(“%4d!=”,k);for(i=a[0];i>0;i–)printf(“%d”,a[i]);printf(“\n\n”);}voidmain(){inta[MAXN],n,k;printf(“Enterthenumbern:“);scanf(“%d”,&n);a[0]=1;a[1]=1;write(a,1);for(k=2;k<=n;k++){pnext(a,k);write(a,k);getchar();}}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第24頁。4、遞歸是設計和描述算法的一種有力的工具,由于它在復雜算法的描述中被經(jīng)常采用,為此在進一步介紹其他算法設計方法之前先討論它。能采用遞歸描述的算法通常有這樣的特征:為求解規(guī)模為N的問題,設法將它分解成規(guī)模較小的問題,然后從這些小問題的解方便地構造出大問題的解,并且這些規(guī)模較小的問題也能采用同樣的分解和綜合方法,分解成規(guī)模更小的問題,并從這些更小問題的解構造出規(guī)模較大問題的解。特別地,當規(guī)模N=1時,能直接得解。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第25頁?!締栴}】編寫計算斐波那契(Fibonacci)數(shù)列的第n項函數(shù)fib(n)。斐波那契數(shù)列為:0、1、1、2、3、……,即:fib(0)=0;fib(1)=1;fib(n)=fib(n-1)+fib(n-2)(當n>1時)。寫成遞歸函數(shù)有:intfib(intn){if(n==0)return0;if(n==1)return1;if(n>1)returnfib(n-1)+fib(n-2);}遞歸算法的執(zhí)行過程分遞推和回歸兩個階段。在遞推階段,把較復雜的問題(規(guī)模為n)的求解推到比原問題簡單一些的問題(規(guī)模小于n)的求解。例如上例中,求解fib(n),把它推到求解fib(n-1)和fib(n-2)。也就是說,為計算fib(n),必須先計算fib(n-1)和fib(n-2),而計算fib(n-1)和fib(n-2),又必須先計算fib(n-3)和fib(n-4)。依次類推,直至計算fib(1)和fib(0),分別能立即得到結果1和0。在遞推階段,必須要有終止遞歸的情況。例如在函數(shù)fib中,當n為1和0的情況。在回歸階段,當獲得最簡單情況的解后,逐級返回,依次得到稍復雜問題的解,例如得到fib(1)和fib(0)后,返回得到fib(2)的結果,……,在得到了fib(n-1)和fib(n-2)的結果后,返回得到fib(n)的結果。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第26頁。5、回溯法回溯法也稱為試探法,該方法首先暫時放棄關于問題規(guī)模大小的限制,并將問題的候選解按某種順序逐一枚舉和檢驗。當發(fā)現(xiàn)當前候選解不可能是解時,就選擇下一個候選解;倘若當前候選解除了還不滿足問題規(guī)模要求外,滿足所有其他要求時,繼續(xù)擴大當前候選解的規(guī)模,并繼續(xù)試探。如果當前候選解滿足包括問題規(guī)模在內的所有要求時,該候選解就是問題的一個解。在回溯法中,放棄當前候選解,尋找下一個候選解的過程稱為回溯。擴大當前候選解的規(guī)模,以繼續(xù)試探的過程稱為向前試探。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第27頁。1)、回溯法的一般描述可用回溯法求解的問題P,通常要能表達為:對于已知的由n元組(x1,x2,…,xn)組成的一個狀態(tài)空間E={(x1,x2,…,xn)∣xi∈Si,i=1,2,…,n},給定關于n元組中的一個分量的一個約束集D,要求E中滿足D的全部約束條件的所有n元組。其中Si是分量xi的定義域,且|Si|有限,i=1,2,…,n。我們稱E中滿足D的全部約束條件的任一n元組為問題P的一個解。解問題P的最樸素的方法就是枚舉法,即對E中的所有n元組逐一地檢測其是否滿足D的全部約束,若滿足,則為問題P的一個解。但顯然,其計算量是相當大的。我們發(fā)現(xiàn),對于許多問題,所給定的約束集D具有完備性,即i元組(x1,x2,…,xi)滿足D中僅涉及到x1,x2,…,xi的所有約束意味著j(jj。因此,對于約束集D具有完備性的問題P,一旦檢測斷定某個j元組(x1,x2,…,xj)違反D中僅涉及x1,x2,…,xj的一個約束,就可以肯定,以(x1,x2,…,xj)為前綴的任何n元組(x1,x2,…,xj,xj+1,…,xn)都不會是問題P的解,因而就不必去搜索它們、檢測它們。回溯法正是針對這類問題,利用這類問題的上述性質而提出來的比枚舉法效率更高的算法。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第28頁。回溯法首先將問題P的n元組的狀態(tài)空間E表示成一棵高為n的帶權有序樹T,把在E中求問題P的所有解轉化為在T中搜索問題P的所有解。樹T類似于檢索樹,它可以這樣構造:設Si中的元素可排成xi(1),xi(2),…,xi(mi-1),|Si|=mi,i=1,2,…,n。從根開始,讓T的第I層的每一個結點都有mi個兒子。這mi個兒子到它們的雙親的邊,按從左到右的次序,分別帶權xi+1(1),xi+1(2),…,xi+1(mi),i=0,1,2,…,n-1。照這種構造方式,E中的一個n元組(x1,x2,…,xn)對應于T中的一個葉子結點,T的根到這個葉子結點的路徑上依次的n條邊的權分別為x1,x2,…,xn,反之亦然。另外,對于任意的0≤i≤n-1,E中n元組(x1,x2,…,xn)的一個前綴I元組(x1,x2,…,xi)對應于T中的一個非葉子結點,T的根到這個非葉子結點的路徑上依次的I條邊的權分別為x1,x2,…,xi,反之亦然。特別,E中的任意一個n元組的空前綴(),對應于T的根。因而,在E中尋找問題P的一個解等價于在T中搜索一個葉子結點,要求從T的根到該葉子結點的路徑上依次的n條邊相應帶的n個權x1,x2,…,xn滿足約束集D的全部約束。在T中搜索所要求的葉子結點,很自然的一種方式是從根出發(fā),按深度優(yōu)先的策略逐步深入,即依次搜索滿足約束條件的前綴1元組(x1i)、前綴2元組(x1,x2)、…,前綴I元組(x1,x2,…,xi),…,直到i=n為止。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第29頁。在回溯法中,上述引入的樹被稱為問題P的狀態(tài)空間樹;樹T上任意一個結點被稱為問題P的狀態(tài)結點;樹T上的任意一個葉子結點被稱為問題P的一個解狀態(tài)結點;樹T上滿足約束集D的全部約束的任意一個葉子結點被稱為問題P的一個回答狀態(tài)結點,它對應于問題P的一個解。【問題】組合問題問題描述:找出從自然數(shù)1、2、……、n中任取r個數(shù)的所有組合。例如n=5,r=3的所有組合為:(1)1、2、3(2)1、2、4(3)1、2、5(4)1、3、4(5)1、3、5(6)1、4、5(7)2、3、4(8)2、3、5(9)2、4、5(10)3、4、5則該問題的狀態(tài)空間為:E={(x1,x2,x3)∣xi∈S,i=1,2,3}其中:S={1,2,3,4,5}約束集為:x1顯然該約束集具有完備性。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第30頁。2)、回溯法的方法對于具有完備約束集D的一般問題P及其相應的狀態(tài)空間樹T,利用T的層次結構和D的完備性,在T中搜索問題P的所有解的回溯法可以形象地描述為:從T的根出發(fā),按深度優(yōu)先的策略,系統(tǒng)地搜索以其為根的子樹中可能包含著回答結點的所有狀態(tài)結點,而跳過對肯定不含回答結點的所有子樹的搜索,以提高搜索效率。具體地說,當搜索按深度優(yōu)先策略到達一個滿足D中所有有關約束的狀態(tài)結點時,即“激活”該狀態(tài)結點,以便繼續(xù)往深層搜索;否則跳過對以該狀態(tài)結點為根的子樹的搜索,而一邊逐層地向該狀態(tài)結點的祖先結點回溯,一邊“殺死”其兒子結點已被搜索遍的祖先結點,直到遇到其兒子結點未被搜索遍的祖先結點,即轉向其未被搜索的一個兒子結點繼續(xù)搜索。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第31頁。在搜索過程中,只要所激活的狀態(tài)結點又滿足終結條件,那么它就是回答結點,應該把它輸出或保存。由于在回溯法求解問題時,一般要求出問題的所有解,因此在得到回答結點后,同時也要進行回溯,以便得到問題的其他解,直至回溯到T的根且根的所有兒子結點均已被搜索過為止。例如在組合問題中,從T的根出發(fā)深度優(yōu)先遍歷該樹。當遍歷到結點(1,2)時,雖然它滿足約束條件,但還不是回答結點,則應繼續(xù)深度遍歷;當遍歷到葉子結點(1,2,5)時,由于它已是一個回答結點,則保存(或輸出)該結點,并回溯到其雙親結點,繼續(xù)深度遍歷;當遍歷到結點(1,5)時,由于它已是葉子結點,但不滿足約束條件,故也需回溯。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第32頁。3、回溯法的一般流程和技術在用回溯法求解有關問題的過程中,一般是一邊建樹,一邊遍歷該樹。在回溯法中我們一般采用非遞歸方法。下面,我們給出回溯法的非遞歸算法的一般流程:在用回溯法求解問題,也即在遍歷狀態(tài)空間樹的過程中,如果采用非遞歸方法,則我們一般要用到棧的數(shù)據(jù)結構。這時,不僅可以用棧來表示正在遍歷的樹的結點,而且可以很方便地表示建立孩子結點和回溯過程。例如在組合問題中,我們用一個一維數(shù)組Stack[]表示棧。開始??眨瑒t表示了樹的根結點。如果元素1進棧,則表示建立并遍歷(1)結點;這時如果元素2進棧,則表示建立并遍歷(1,2)結點;元素3再進棧,則表示建立并遍歷(1,2,3)結點。這時可以判斷它滿足所有約束條件,是問題的一個解,輸出(或保存)。這時只要棧頂元素(3)出棧,即表示從結點(1,2,3)回溯到結點(1,2)。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第33頁。【問題】組合問題問題描述:找出從自然數(shù)1,2,…,n中任取r個數(shù)的所有組合。采用回溯法找問題的解,將找到的組合以從小到大順序存于a[0],a[1],…,a[r-1]中,組合的元素滿足以下性質:(1)a[i+1]>a[i],后一個數(shù)字比前一個大;(2)a[i]-i<=n-r+1。按回溯法的思想,找解過程可以敘述如下:首先放棄組合數(shù)個數(shù)為r的條件,候選組合從只有一個數(shù)字1開始。因該候選解滿足除問題規(guī)模之外的全部條件,擴大其規(guī)模,并使其滿足上述條件(1),候選組合改為1,2。繼續(xù)這一過程,得到候選組合1,2,3。該候選解滿足包括問題規(guī)模在內的全部條件,因而是一個解。在該解的基礎上,選下一個候選解,因a[2]上的3調整為4,以及以后調整為5都滿足問題的全部要求,得到解1,2,4和1,2,5。由于對5不能再作調整,就要從a[2]回溯到a[1],這時,a[1]=2,可以調整為3,并向前試探,得到解1,3,4。重復上述向前試探和向后回溯,直至要從a[0]再回溯時,說明已經(jīng)找完問題的全部解。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第34頁?!境绦颉?defineMAXN100inta[MAXN];voidcomb(intm,intr){inti,j;i=0;a[i]=1;do{if(a[i]-i<=m-r+1{if(i==r-1){for(j=0;jprintf(“%4d”,a[j]);printf(“\n”);}a[i]++;continue;}else{if(i==0)return;a[--i]++;}}while(1)}main(){comb(5,3);}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第35頁。六、貪婪法貪婪法是一種不追求最優(yōu)解,只希望得到較為滿意解的方法。貪婪法一般可以快速得到滿意的解,因為它省去了為找最優(yōu)解要窮盡所有可能而必須耗費的大量時間。貪婪法常以當前情況為基礎作最優(yōu)選擇,而不考慮各種可能的整體情況,所以貪婪法不要回溯。例如平時購物找錢時,為使找回的零錢的硬幣數(shù)最少,不考慮找零錢的所有各種發(fā)表方案,而是從最大面值的幣種開始,按遞減的順序考慮各幣種,先盡量用大面值的幣種,當不足大面值幣種的金額時才去考慮下一種較小面值的幣種。這就是在使用貪婪法。這種方法在這里總是最優(yōu),是因為對其發(fā)行的硬幣種類和硬幣面值的巧妙安排。如只有面值分別為1、5和11單位的硬幣,而希望找回總額為15單位的硬幣。按貪婪算法,應找1個11單位面值的硬幣和4個1單位面值的硬幣,共找回5個硬幣。但最優(yōu)的解應是3個5單位面值的硬幣。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第36頁?!締栴}】裝箱問題問題描述:裝箱問題可簡述如下:設有編號為0、1、…、n-1的n種物品,體積分別為v0、v1、…、vn-1。將這n種物品裝到容量都為V的若干箱子里。約定這n種物品的體積均不超過V,即對于0≤i<n,有0<vi≤V。不同的裝箱方案所需要的箱子數(shù)目可能不同。裝箱問題要求使裝盡這n種物品的箱子數(shù)要少。若考察將n種物品的集合分劃成n個或小于n個物品的所有子集,最優(yōu)解就可以找到。但所有可能劃分的總數(shù)太大。對適當大的n,找出所有可能的劃分要花費的時間是無法承受的。為此,對裝箱問題采用非常簡單的近似算法,即貪婪法。該算法依次將物品放到它第一個能放進去的箱子中,該算法雖不能保證找到最優(yōu)解,但還是能找到非常好的解。不失一般性,設n件物品的體積是按從大到小排好序的,即有v0≥v1≥…≥vn-1。如不滿足上述要求,只要先對這n件物品按它們的體積從大到小排序,然后按排序結果對物品重新編號即可。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第37頁。裝箱算法簡單描述如下:{輸入箱子的容積;輸入物品種數(shù)n;按體積從大到小順序,輸入各物品的體積;預置已用箱子鏈為空;預置已用箱子計數(shù)器box_count為0;for(i=0;i{從已用的第一只箱子開始順序尋找能放入物品i的箱子j;if(已用箱子都不能再放物品i){另用一個箱子,并將物品i放入該箱子;box_count++;}else將物品i放入箱子j;}}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第38頁。上述算法能求出需要的箱子數(shù)box_count,并能求出各箱子所裝物品。下面的例子說明該算法不一定能找到最優(yōu)解,設有6種物品,它們的體積分別為:60、45、35、20、20和20單位體積,箱子的容積為100個單位體積。按上述算法計算,需三只箱子,各箱子所裝物品分別為:第一只箱子裝物品1、3;第二只箱子裝物品2、4、5;第三只箱子裝物品6。而最優(yōu)解為兩只箱子,分別裝物品1、4、5和2、3、6。若每只箱子所裝物品用鏈表來表示,鏈表首結點指針存于一個結構中,結構記錄尚剩余的空間量和該箱子所裝物品鏈表的首指針。另將全部箱子的信息也構成鏈表。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第39頁?!境绦颉?includetypedefstructele{intvno;structele*link;}ELE;typedefstructhnode{intremainder;ELE*head;Structhnode*next;}HNODE;voidmain(){intn,i,box_count,box_volume,*a;HNODE*box_h,*box_t,*j;ELE*p,*q;Printf(“輸入箱子容積\n”);Scanf(“%d”,&box_volume);Printf(“輸入物品種數(shù)\n”);Scanf(“%d”,&n);A=(int*)malloc(sizeof(int)*n);Printf(“請按體積從大到小順序輸入各物品的體積:”);For(i=0;iBox_h=box_t=NULL;Box_count=0;For(i=0;i{p=(ELE*)malloc(sizeof(ELE));p->vno=i;for(j=box_h;j!=NULL;j=j->next)if(j->remainder>=a)break;if(j==NULL){j=(HNODE*)malloc(sizeof(HNODE));j->remainder=box_volume-a;j->head=NULL;if(box_h==NULL)box_h=box_t=j;elsebox_t=boix_t->next=j;j->next=NULL;box_count++;}elsej->remainder-=a;數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第40頁。for(q=j->next;q!=NULL&&q->link!=NULL;q=q->link);if(q==NULL){p->link=j->head;j->head=p;}else{p->link=NULL;q->link=p;}}printf(“共使用了%d只箱子”,box_count);printf(“各箱子裝物品情況如下:”);for(j=box_h,i=1;j!=NULL;j=j->next,i++){printf(“第%2d只箱子,還剩余容積%4d,所裝物品有;\n”,I,j->remainder);for(p=j->head;p!=NULL;p=p->link)printf(“%4d”,p->vno+1);printf(“\n”);}}數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第41頁。七、分治法1、分治法的基本思想任何一個可以用計算機求解的問題所需的計算時間都與其規(guī)模N有關。問題的規(guī)模越小,越容易直接求解,解題所需的計算時間也越少。例如,對于n個元素的排序問題,當n=1時,不需任何計算;n=2時,只要作一次比較即可排好序;n=3時只要作3次比較即可,…。而當n較大時,問題就不那么容易處理了。要想直接解決一個規(guī)模較大的問題,有時是相當困難的。分治法的設計思想是,將一個難以直接解決的大問題,分割成一些規(guī)模較小的相同問題,以便各個擊破,分而治之。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第42頁。2、分治法的適用條件分治法所能解決的問題一般具有以下幾個特征:(1)該問題的規(guī)模縮小到一定的程度就可以容易地解決;(2)該問題可以分解為若干個規(guī)模較小的相同問題,即該問題具有最優(yōu)子結構性質;(3)利用該問題分解出的子問題的解可以合并為該問題的解;(4)該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子子問題。上述的第一條特征是絕大多數(shù)問題都可以滿足的,因為問題的計算復雜性一般是隨著問題規(guī)模的增加而增加;第二條特征是應用分治法的前提,它也是大多數(shù)問題可以滿足的,此特征反映了遞歸思想的應用;第三條特征是關鍵,能否利用分治法完全取決于問題是否具有第三條特征,如果具備了第一條和第二條特征,而不具備第三條特征,則可以考慮貪心法或動態(tài)規(guī)劃法。第四條特征涉及到分治法的效率,如果各子問題是不獨立的,則分治法要做許多不必要的工作,重復地解公共的子問題,此時雖然可用分治法,但一般用動態(tài)規(guī)劃法較好。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第43頁。3、分治法的基本步驟分治法在每一層遞歸上都有三個步驟:(1)分解:將原問題分解為若干個規(guī)模較小,相互獨立,與原問題形式相同的子問題;(2)解決:若子問題規(guī)模較小而容易被解決則直接解,否則遞歸地解各個子問題;(3)合并:將各個子問題的解合并為原問題的解。它的一般的算法設計模式如下:Divide_and_Conquer(P)if|P|≤n0thenreturn(ADHOC(P))將P分解為較小的子問題P1、P2、…、Pkfori←1tokdoyi←Divide-and-Conquer(Pi)△遞歸解決PiT←MERGE(y1,y2,…,yk)△合并子問題Return(T)數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第44頁?!締栴}】大整數(shù)乘法問題描述:通常,在分析一個算法的計算復雜性時,都將加法和乘法運算當作是基本運算來處理,即將執(zhí)行一次加法或乘法運算所需的計算時間當作一個僅取決于計算機硬件處理速度的常數(shù)。這個假定僅在計算機硬件能對參加運算的整數(shù)直接表示和處理時才是合理的。然而,在某些情況下,我們要處理很大的整數(shù),它無法在計算機硬件能直接表示的范圍內進行處理。若用浮點數(shù)來表示它,則只能近似地表示它的大小,計算結果中的有效數(shù)字也受到限制。若要精確地表示大整數(shù)并在計算結果中要求精確地得到所有位數(shù)上的數(shù)字,就必須用軟件的方法來實現(xiàn)大整數(shù)的算術運算。請設計一個有效的算法,可以進行兩個n位大整數(shù)的乘法運算。設X和Y都是n位的二進制整數(shù),現(xiàn)在要計算它們的乘積XY。我們可以用小學所學的方法來設計一個計算乘積XY的算法,但是這樣做計算步驟太多,顯得效率較低。如果將每2個1位數(shù)的乘法或加法看作一步運算,那么這種方法要作O(n2)步運算才能求出乘積XY。下面我們用分治法來設計一個更有效的大整數(shù)乘積算法。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第45頁。functionMULT(X,Y,n);{X和Y為2個小于2n的整數(shù),返回結果為X和Y的乘積XY}beginS=SIGN(X)*SIGN(Y);{S為X和Y的符號乘積}X=ABS(X);Y=ABS(Y);{X和Y分別取絕對值}ifn=1thenif(X=1)and(Y=1)thenreturn(S)elsereturn(0)elsebeginA=X的左邊n/2位;B=X的右邊n/2位;C=Y的左邊n/2位;D=Y的右邊n/2位;ml=MULT(A,C,n/2);m2=MULT(A-B,D-C,n/2);m3=MULT(B,D,n/2);S=S*(m1*2n+(m1+m2+m3)*2n/2+m3);return(S);end;end;數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第46頁。八、動態(tài)規(guī)劃法經(jīng)常會遇到復雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地采用把大問題分解成子問題,并綜合子問題的解導出大問題的解的方法,問題求解耗時會按問題規(guī)模呈冪級數(shù)增加。為了節(jié)約重復求相同子問題的時間,引入一個數(shù)組,不管它們是否對最終解有用,把所有子問題的解存于該數(shù)組中,這就是動態(tài)規(guī)劃法所采用的基本方法。以下先用實例說明動態(tài)規(guī)劃方法的使用。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第47頁?!締栴}】求兩字符序列的最長公共字符子序列問題描述:字符序列的子序列是指從給定字符序列中隨意地(不一定連續(xù))去掉若干個字符(可能一個也不去掉)后所形成的字符序列。令給定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一個嚴格遞增下標序列,使得對所有的j=0,1,…,k-1,有xij=yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一個子序列。給定兩個序列A和B,稱序列Z是A和B的公共子序列,是指Z同是A和B的子序列。問題要求已知兩序列A和B的最長公共子序列。數(shù)據(jù)結構與算法算法篇全文共55頁,當前為第48頁。如采用列舉A的所有子序列,并一一檢查其是否又是B的子序列,并隨時記錄所發(fā)現(xiàn)的子序列,最終求出最長公共子序列。這種方法因耗時太多而不可取??紤]最長公共子序列問題如何分解成子問題,設A=“a0,a1,…,am-1”,B=“b0,b1,…,bm-1”,并Z=“z0,z1,…,zk-1”為它們的最長公共子序列。不難證明有以下性質:(1)如果am-1=bn-1,則zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一個最長公共子序列;(2)如果am-1!=bn-1,則若zk-1!=am-1,蘊涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一個最長公共子序列;(3)如果am-1!=bn-1,則若zk-1!=bn-1,蘊涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一個最長公共子序列。這樣,在找A和B的公共子序列時,如有am-1=bn-1,則進一步解決一個子問題,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一個最長公共子序列;如果am-1!=bn-1,則要解決兩個子問題,找出“a0,a

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論