【文档说明】结构理论与实务-–-以C语言实作Data-Structures-in-C课件.ppt,共(51)页,950.501 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44674.html
以下为本文档部分文字说明:
資料結構理論與實務–以C語言實作DataStructuresinC:ConceptandImplementation2目錄•第1章:資料結構導論(Introduction)•第2章:陣列與結構(ArraysandStructures)•第3章:指標與字串(Pointersand
Strings)•第4章:鏈結串列(LinkedLists)•第5章:堆疊(Stacks)3目錄•第6章:佇列(Queues)•第7章:樹與二元樹(TreesandBinaryTrees)•第8章:圖形結構
(Graphs)•第9章:資料排序(Sorting)•第10章:資料搜尋(Searching)4第1章資料結構導論(Introduction)•1-1資料結構的基礎•1-2程式設計與演算法•1-3抽象資料型態ADT•1-4C語言的模組化程式設計•1-5遞迴函數•1-6程式的分析方
法51-1資料結構的基礎-說明•「資料結構」(DataStructures)是一門計算機科學的基礎學科,其目的是研究程式使用的資料在電腦記憶體的儲存方式,以便撰寫程式處理問題時,能夠使用最佳的資料結構,並且提供一種策略或方法來有效率的善用這些資料,以便達
到下列目的,如下所示:–程式執行速度快。–資料佔用最少的記憶空間。–更快速的存取這些資料。61-1資料結構的基礎-圖例•上述轉換資料的方法策略就是「演算法」(Algorithms)。•演算法和資料結構的關係非常的密切,因為程式使用的演算法和資料結構都會影響程式的
執行效率,換句話說,演算法加上資料結構就等於程式,如下所示:「演算法」+「資料結構」=「程式」71-2程式設計與演算法•1-2-1程式設計的過程•1-2-2演算法•1-2-3模組化•1-2-4由上而下的設計方法81-2-1程式設計的過程-階段•程式
設計是將需要解決的問題轉換成程式碼,程式碼不只能夠在電腦上正確的執行,而且可以驗證程式執行的正確性,程式設計的過程可以分成5個階段,如下所示:–需求(Requirements)–設計(Design)–分析(Analy
sis)–撰寫程式碼(Coding)–驗證(Verification)91-2-1程式設計的過程-需求•需求(Requirements):程式設計的需求是在了解問題本身,以便確切獲得程式需要輸入的資料和其產生的
結果,如下圖所示:101-2-1程式設計的過程-設計•設計(Design):在了解程式設計的需求後,我們就可以開始找尋解決問題的方法和策略,簡單的說,設計階段就是找出解決問題的步驟,如下圖所示:111-2-1程式設計的過程-分析•分析(Analysis):在解決需求時,只有一種解決
方法嗎?例如:如果有100個變數,我們可以宣告100個變數來儲存資料,或是使用陣列來儲存,在分析階段是將所有可能解決問題的演算法都寫下來,然後分析比較那一種方法比較好,選擇最好的演算法來撰寫程式。121-2-1程式設計的過程-撰寫•撰寫程式碼(Coding):現在
就可以開始使用指定的程式語言來撰寫程式碼,以本書為例是使用C程式語言,在實際撰寫程式時,可能發現另一種方法比較好,因為設計歸設計,在實際撰寫程式時才能真正發現其優劣,如果這是一個良好的設計方法,就算改為其它方法也不會太困難。131-2-1程式設計的過程
-驗證•驗證(Verification):驗證是證明程式執行的結果符合需求的輸出資料,在這個階段可以再細分成三個部分:–證明:執行程式時需要證明它的執行結果是正確的,程式符合所有輸入資料的組合,程式規格也都
符合演算法的需求。–測試:程式需要測試各種可能情況、條件和輸入資料,以測試程式執行無誤,如果有錯誤產生,就需要除錯來解決程式問題。–除錯:如果程式無法輸出正確的結果,除錯是在找出錯誤的地方,我們不但需要找出錯誤,還需要決定如何
更正它。141-2-2演算法-定義•演算法是完成目標工作的一組指令,這組指令的步驟是有限的。除此之外,演算法還必須滿足一些條件,如下所示:–輸入(Input):沒有或數個外界的輸入資料。–輸出(Output):至少有一個輸出結果。–明確性(Definiteness):每一個指令步
驟都十分明確,沒有模稜兩可。–有限性(Finiteness):這組指令一定結束。–有效性(Effectiveness):每一個步驟都可行,可以追蹤其結果。151-2-2演算法-方法•演算法只是將解決問題步驟詳細的寫出來,所以並沒有固定的方式,基本
上只要能夠描述這組指令的執行過程即可,常用的方式如下所示:–一般語言文字:直接使用文字描述來說明執行的步驟。–虛擬碼(PseudoCode):趨近程式語言的描述方法,其每一列約可轉換成一列程式碼。–流程圖(FlowCh
art):使用結構化的圖表描述執行過程,以各種不同形狀的圖形表示不同的操作。161-2-2演算法-虛擬碼範例•從1加到10演算法的虛擬碼,如下所示:/*計算1加到10*/Letcounter=1Lettotal=0whilecounter<=
10total=total+counterAdd1tocounterOutputthetotal/*顯示結果*/171-2-2演算法-流程圖範例•從1加到10演算法的流程圖,如右圖所示:181-2-3模組化-說明
•模組化主要是針對解決問題的方法,把一件大型的工作切割成多個小工作,切割的工作屬於一種結構化分析的範疇,最常使用的是「由上而下的設計方法」,其主要是使用程序為單位來切割工作,也就是所謂的「程序式程式設計」(Proced
uralDesign)。191-2-4由上而下的設計方法-說明•由上而下的設計方法(Top-downDesign)是在面對問題時,先考慮將整個解決問題的方法分解成數個大「模組」(Modules),然後針對每一個大模組,一一分割成數個小模組,如此一直細分,最後
等這些細分小問題的小模組完成後,再將它們組合起來,如此一層層的向上爬,完成整個軟體系統或應用程式的設計。201-2-4由上而下的設計方法-注意事項•獨立性:每一個分割模組間的關聯性愈少,處理起來就會愈快。所謂獨立性,是指當處理某一個子問題時,無需考慮到其它
子問題。換一句話說,獨立性是要將每一個問題都定義成一件簡單且明確的問題。•結合問題:小心控制子問題間的結合方法,而且要注意結合這些子問題的邏輯順序,避免語焉不詳的結果。•子問題間的溝通:雖然獨立性可以減少各問題間的關聯性,但是並無法避免掉全部的溝通。因此各問題間如何溝通的問題(即函
數的參數傳遞)也是十分重要的考量。211-3抽象資料型態ADT•1-3-1抽象化–塑模•1-3-2程序或函數抽象化•1-3-3抽象資料型態(ADT)221-3-1抽象化–塑模(說明)•程式設計的目的是解決問題,也就
是將現實生活中的真實問題轉換成電腦程式,讓電腦執行程式幫助我們解決問題,這個過程是找出問題的模型,稱為「塑模」(Modeling),使用抽象觀點來檢視問題,以便建立問題的模型,將問題轉換成模型的方式稱為「抽象化」(Abstra
ction),如下圖所示:231-3-1抽象化–塑模(定義屬性)•「塑模」(Modeling)的主要的目的是定義問題的二個屬性,如下所示:–資料(Data):問題影響的資料。–操作(Operators):問題產生的操作。
•例如:學生基本資料的問題,可以抽象化成Students模型,資料部分是:學號、姓名、地址和電話號碼,操作部分有:指定和取得學生的姓名、地址和電話號碼。241-3-2程序或函數抽象化-說明•程序或函數抽象化(Porcedur
eAbstractionorFunctionAbstraction)的針對傳統由上而下的程式設計方法,將問題分割成一個個子工作,分割的程序或函數並不用考量實作的程式碼,只需定義好程序或函數使用介面的參數和傳回值,將它視為一個黑盒
子,換句話說,程式可以使用任何符合介面的程序或函數來取代,稱為程序或函數抽象化。251-3-2程序或函數抽象化-範例•當定義繪出門框程序的使用介面後,如果開發出更佳的演算法,只需將程序取代成實作的新程式碼,並不用更改使用介面,就可以增加程式執行效率,如果程序擁有
此特性,稱為程序抽象化。261-3-3抽象資料型態(ADT)-說明•「抽象資料型態」(AbstractDataType)是一種自訂資料型態,包含資料和相關操作,將資料和處理資料的操作一起思考,結合在一起,操作是對外的使用介面,如下圖所示:271-3-3抽象資料型態(ADT)-範例•例如:
將學生基本資料抽象化成Students抽象資料型態,內含學號id、姓名name、地址address和電話號碼phone等資料,和setStudent()指定學生資料,getName()、getAddress(
)和getPhone()取出學生資料等操作,如下圖所示:281-4C語言的模組化程式設計-說明•「模組」(Modules)是特定功能的相關資料和函數集合,程式設計者只需知道模組對外的使用介面(即各模組函數的
呼叫方式),就可以使用模組提供的功能,而不用實際了解模組內部程式碼的實作和內部資料儲存使用的資料結構。291-4C語言的模組化程式設計-種類•模組化程式設計(ModularProgramming)就是建立相關資料和函數集合的模組,模組主要可以分成
兩個部分:–模組介面(ModuleInterface):模組介面是定義模組函數和使用的資料,即定義讓使用此模組的程式可以呼叫的函數和存取的變數資料,在C語言是使用標頭檔.h定義模組介面。–模組實作(ModuleImplementations):模組的實作部分是模組函數和資料的實際程式碼,程
式設計者需要定義哪些函數屬於公開介面,哪些只能在模組程式檔使用,C語言的程式檔案.c可以實作模組的程式碼。301-4C語言的模組化程式設計-公開與私用關鍵字•extern和static關鍵字來區分公開或內部使用的函數與變數,如下所示:–在標頭檔宣告成extern的變數和
函數:這是可供其它程式使用的外部函數和變數。–在模組程式檔宣告成static的變數和函數:只能在模組程式檔中使用。311-5遞迴函數•1-5-1遞迴的基礎•1-5-2遞迴的階層函數321-5遞迴函數•「遞迴」(Recursive)是程式設計的一個重要觀念。•「遞迴函數」
(RecursiveFunctions)可以讓函數的程式碼變的很簡潔,但是設計這類函數需要很小心,不然很容易就掉入類似無窮迴圈的陷阱。331-5-1遞迴的基礎-說明•遞迴的觀念主要是在建立遞迴函數,其基本定義,如下所示:一個問題的內涵是由
本身所定義的話,稱之為遞迴。•遞迴函數是由上而下分析方法的一種特殊的情況,因為子問題本身和原來問題擁有相同的特性,只是範圍改變,範圍逐漸縮小到一個終止條件。341-5-1遞迴的基礎-特性•遞迴函數的特性,如下所
示:–遞迴函數在每次呼叫時,都可以使問題範圍逐漸縮小。–函數需要擁有一個終止條件,以便結束遞迴函數的執行,否則遞迴函數並不會結束,而是持續的呼叫自已。351-5-2遞迴的階層函數-公式•遞迴函數最常見的應用是數學的階層函數n!,如下所示:361-5-2遞迴
的階層函數-範例•例如:計算4!的值,從上述定義n>0,使用n!定義的第2條計算階層函數4!的值,如下所示:4!=4*3*2*1=244!=4*(4-1)!=4*3!3!=3*(3-1)!=3*2!2!=2*(2-1)!=2*1!1!=1*
(1-1)!=1*0!=1*1=1•在知道1!的值後,就可以計算出2!~4!的值,如下所示:2!=2*(2-1)!=2*1!=23!=3(3-1)!=3*2!=3*2=64!=4*(4-1)!=4*3!=24
371-6程式的分析方法•1-6-1頻率計數的基礎•1-6-2頻率計數的計算•1-6-4BigOh函數•1-6-5BigOh函數的等級381-6程式的分析方法•一個好程式需要滿足一些條件,如下所示:–正確的執行結果:程式滿足分析的輸入和輸出結果。–可維護性高:程式不只需要正確,而
且是可讀、容易修改和擴充,這屬於程式設計方法和風格的問題,例如:使用模組化來設計程式和加上完整程式註解的說明。–執行效率高:執行效率是指程式執行花費的時間和所需的記憶體空間,一般來說,這兩項在大多數情況是矛盾的,因為使用較大的記憶體空間,通常可以換取程式執行效率的改進,反之亦然,至於如何找到其間
的平衡點,就需視解決的問題而定。391-6-1頻率計數的基礎-說明•程式執行效率就是在計算程式執行的時間,例如:在程式中有一列程式碼,如下所示:a=a+1;•上述程式碼將變數a的值加1。如果使用for迴圈執行此程式碼n次,如下所示:for(i
=0;i<n;i++)a=a+1;•上述程式碼執行的全部時間是n*t,t為單獨執行a=a+1程式碼所需的時間。401-6-1頻率計數的基礎-標準•如何決定時間t,其評量的標準如下所示:–執行程式碼使用的電腦種類:桌上型電腦、工作站或大型電腦。
–CPU使用的機器語言指令集是哪一種?某些CPU的機器語言指令包含乘法和除法指令,有些沒有,有些是以硬體實作,有些是軟體加持。–CPU執行機器語言指令所需的時間,即CPU的執行速度,每秒可以執行的指令數不
同,執行所需的時間當然不同。–使用的編譯程式,一個好的編譯程式可以將指令轉譯成為單一機器語言指令,相對於將它轉譯成數個機器語言指令的編譯程式,其執行時間的差異就十分明顯。411-6-1頻率計數的基礎-頻率計數•執行單位時間t的差異可能十分大,所以我們並不會直接計算程式的執行時
間,取而代之是計算程式每一列程式碼的執行頻率,也就是「頻率計數」(FrequencyCount),以程式執行的次數代替每一列程式碼實際執行的時間。•頻率計數(FrequencyCount)是以原始程式碼的每一列可執行指令作為一個執行單位,計算出程式中每一列程式
碼的執行次數,這個次數就是頻率計數。421-6-4BigOh函數-說明•在分析程式執行效率時考量的是頻率計數的級數,函數O()是用來表示參數頻率計數的級數,唸成BigOh。•O(n)表示程式執行的頻率計數和n成正比,稱為是程式或演算法的「時間複雜度」(Ti
meComplexity)。431-6-4BigOh函數-O(1)O(1):單行程式碼a=a+1;•上述程式碼a=a+1是一列單行程式碼,沒有不包含在任何迴圈中,頻率計數是1所以是O(1)。441-6-4Bi
gOh函數-O(n)O(n):線性迴圈a=0;for(i=0;i<n;i++)a=a+1;•上述程式碼執行n次的a=a+1,其頻率計數是n+1,包含最後1次的比較,不計常數所以是O(n)。451-6-4BigOh函數-O(Logn)O(L
ogn):非線性迴圈a=0;for(i=n;i>0;i=i/2)a=a+1;•或a=0;for(i=0;i<n;i=i*2)a=a+1;•上述兩個迴圈的增量是除以2或乘以2,以除來說,如果n=16,迴圈依序為8、4、2、1,其執行次數是對數Logn,其頻率計數是Logn+1,包含最後
1次的比較,不計常數所以是O(Logn)。461-6-4BigOh函數-O(nLogn)O(nLogn):巢狀迴圈擁有內層非線性迴圈a=0;for(i=0;i<n;i++)for(j=n;j>0;j=j/2)a=a+1;•上述巢狀迴圈的外層是線性迴圈的O(n),內層是
非線性迴圈的O(Logn),所以是:O(n)*O(Logn)=O(nLogn)471-6-4BigOh函數-O(n2)O(n2):巢狀迴圈a=0;for(i=0;i<n;i++)for(j=0;j<n;j++)a=a+1;•上述巢狀迴圈的外層是線性
迴圈的O(n),內層線性迴圈的O(n),所以是:O(n)*O(n)=O(n2)481-6-5BigOh函數的等級-等級•程式執行效率的時間複雜度可以使用O(1)、O(Logn)、O(n)、O(nLogn)、O(n
2)、O(n3)和O(2n)函數表示,如下表所示:491-6-5BigOh函數的等級-成長曲線圖501-6-5BigOh函數的等級-比較•如果一個問題有兩種不同的方法來解決,第一種方法的頻率計數是5n,第二種方法的頻率
計數是n^2/2,我們可以計算出頻率計數與n值的關係,如下表所示:511-6-5BigOh函數的等級-說明•當n<10時,第二種方法比第一種有效率,如果n>10時,第一種方法反而比較有效率,函數O()分別為O(n)和O(n2)
。•換句話說,當n足夠大時,頻率計數的常數就可以忽略不計,只需比較其級數,所以O(n)執行效率比O(n2)好。如果n很小時,常數就需要加以考量,如此才能真正比較出程式執行效率的優劣。