本文內容python
1、簡介算法
2、動態規劃原理編程
3、遞歸原理ide
4、實驗預期現象函數
5、Python批量生成文件測試
6、遇到的困難與解決辦法優化
6.1測試數據運行時間ui
6.2批量生成文件spa
7、遞歸作法相關實驗3d
7.1源代碼
7.1.1遞歸作法求解斐波那契數列
7.1.2測試遞歸次數
7.2實驗數據
7.2.1測試運行時間
7.2.2測試遞歸次數
8、動態規劃作法相關實驗
8.1源代碼
8.1.1動態規劃作法求解斐波那契數列
8.2實驗數據
8.2.2測試運行時間
9、實驗結果比較
10、推測遞歸次數
10.1指數函數推測遞歸次數
10.2遞推公式推測遞歸次數
10.3指數函數與遞推公式求解遞歸次數對比
11、時間複雜度和空間複雜度分析
12、總結
1、簡介:
本篇博客以「斐波那契數列」爲例,採用遞歸作法和動態規劃作法對其求解,經過測量n1(1≤n1≤99,n1∈N)個數據運行時間以及測量遞歸作法n2(1≤n2≤41,n2∈N)個數據的遞歸次數,將獲得的結果以柱狀圖的形式表現出來,進而對遞作法和動態規劃作法進行分析和比較。
首先介紹斐波那契數列,斐波那契數列的排列是:1,1,2,3,5,8,13,21,34,55,89......。依次類推下去能夠發現,它後一個數等於前面兩個數的和。在這個數列中的數字,就被稱爲斐波那契數。由此能夠得出「斐波那契數列」遞推關係:
F(n)=F(n-1)+F(n-2)(n∈N*)
A* "1+1+1+1+1+1+1+1 =?" *
A: "上面等式的值是多少"
B : *計算* "8!"
A*在上面等式的左邊寫上"1+" *
A: "此時等式的值爲多少"
B : *quickly*"9!"
A : "你怎麼這麼快就知道答案了''
A: "只要在8的基礎上加1就好了"
A: "因此你不用從新計算由於你記住了第一個等式的值爲8!動態規劃算法也能夠說是'記住求過的解來節省時間''
由上面的對話能夠知道動態規劃算法的核心就是記住已經解決過的子問題的解。
動態規劃算法是經過拆分問題,定義問題狀態和狀態之間的關係,使得問題可以以遞推(或者說分治)的方式去解決。
能採用動態規劃求解的問題的通常要具備3個性質:
(1)最優化原理:若是問題的最優解所包含的子問題的解也是最優的,就稱該問題具備最優子結構,即知足最優化原理。
(2)無後效性:即某階段狀態一旦肯定,就不受這個狀態之後決策的影響。也就是說,某狀態之後的過程不會影響之前的狀態,只與當前狀態有關。
(3)有重疊子問題:即子問題之間是不獨立的,一個子問題在下一階段決策中可能被屢次使用到。(該性質並非動態規劃適用的必要條件,可是若是沒有這條性質,動態規劃算法同其餘算法相比就不具有優點。
使用動態規劃求解問題,最重要的就是肯定動態規劃三要素:
(1)問題的階段。
(2)每一個階段的狀態。
(3)從前一個階段轉化到後一個階段之間的遞推關係。
3、遞歸原理
先來分析一下遞歸算法的執行流程(以「斐波那契數列」爲例),假如輸入6,那麼執行的遞歸樹以下:
上面的遞歸樹中的每個子節點都會執行一次,不少重複的節點被執行,例如:fib(2)被重複執行了5次。因爲調用每個函數的時候都要保留上下文,因此空間上開銷也不小。這麼多的子節點被重複執行,若是在執行的時候把執行過的子節點保存起來,後面要用到的時候直接查表調用的話能夠節約大量的時間,這就是博客中提到的動態規劃算法的優點。
4、實驗預期現象
動態規劃算法的運行時間比較平穩,不隨着測試數據的增大而改變。遞歸作法當測試數據越大時,運行時間越長,而且有不少重複計算的節點,因此預計遞歸算法的運行時間會呈指數增加。
5、python批量生成文件
#include<stdio.h> main() { int i; for(i=1;i<=99;i++) { printf("ptime 文件名.exe<%d.txt>>文件名.txt\n",i); } }
3.重定向輸出:將全部執行過程當中須要的文件放在同一目錄下,在該目錄下打開控制檯,輸入:要執行的文件名.exe>>文本名.bat(此處>>能夠根據需求寫成>,>>表示追加內容,>表示覆蓋原有內容)
4.利用python寫一段程序生成99個文本文件,每一個文本中存一個測試數據。
i = 1
while (i < 100): s2 = 'C:/Users/Administrator/Desktop/a/' s = '.txt' s1 = s2+str(i) + s print(s1) f = open(s1, 'w') f.write(str(i)) f.close() i = i + 1
5.將全部執行過程當中須要的文件放入同一目錄下,在該目錄下打開控制檯,執行1過程保存的text.bat文本。以上過程便可實現批量執行。
6、遇到的困難與解決辦法
6.1測試數據運行時間
解決辦法:在每條執行語句前加ptime(ptime是測試運行時間的exe,精確到毫秒,在這個過程當中要求的時間精度比較高)。
6.2批量生成文件
解決辦法:利用python能夠自動生成文本文件,代碼如5-4。(生成的文件數量不一樣,代碼須要稍做修改)
7、遞歸方法相關實驗
7.1源代碼
7.1.1遞歸作法求解斐波那契數列
#include<stdio.h> int n = 0;//n表示輸入的測試數據 int m = 0;//m表示調用函數後計算的結果 int fun(int p) { if (p == 1 || p == 2) { return 1; } else { return fun(p - 1) + fun(p - 2); } } int main() { scanf("%d", &n); m = fun(n); printf("%d",m); return 0; }
7.1.2測試遞歸次數
#include<stdio.h> int n = 0;//n表示輸入的測試數據 int m = 0;//m表示調用函數後計算的結果 int i=0; int fun(int p,int t) { if (p == 1 || p == 2) { i++; return 1; } else { i++; return fun(p - 1,t) + fun(p - 2,t); } } int main() { scanf("%d", &n); m = fun(n,i); printf("%d\n", i); return 0; }
7.2實驗數據
7.2.1測試運行時間
測試n(1≤n≤55,n∈N)個數據運行時間實驗結果灰色列爲測試數據,白色列爲運行時間(單位S)。
圖1 遞歸方法求解「斐波那契數列」測運行時間結果
柱狀圖表示實驗結果:
圖2 遞歸方法求解「斐波那契數列」測運行時間結果柱狀圖
7.2.2測試遞歸次數
測試n(1≤n≤41,n∈N)個數據遞歸次數實驗結果。
圖3 遞歸方法求解「斐波那契數列」測遞歸次數結果
柱狀圖表示實驗結果:
圖4 遞歸方法求解「斐波那契數列」測遞歸次數結果柱狀圖
8、動態規劃相關代碼
8.1源代碼
8.1.1動態規劃作法求解斐波那契數列
#include<stdio.h>
int main() { int a[100]; int n; int i=2; a[0]=0; a[1]=1; a[2]=1; scanf("%d",&n); if(n==1) printf("1"); else{ while(1) { a[i]=a[i-1]+a[i-2]; if(i>=n) break; else i++; } printf("%d\n", a[i]); } return 0; }
8.2實驗數據
8.2.2測試運行時間
測試n(1≤n≤97,n∈N)個數據運行時間實驗結果。
圖5 動態規劃方法求解「斐波那契數列」測運行時間結果
柱狀圖表示實驗結果:
圖6 動態規劃方法求解「斐波那契數列」測運行時間結果柱狀圖
9、實驗結果比較
圖7 遞歸方法求解每一個數據運行時間實驗結果
圖8 動態規劃方法求解每一個數據運行時間實驗結果
經過兩種方法運行時間的實驗結果代表,遞歸作法的運行時間成指數增加,動態規劃作法的運行時間不隨測試數據的改變而變化。兩種方法對比能夠看出動態規劃作法下降了時間複雜度,提升效率。實驗結果與實驗預期現象一致。
10、推測遞歸次數
目的:當輸入的測試數據較大時,運行時間較長,沒法一一測試,因此須要推測測試結果。
1. 經過圖三測試不一樣輸入時遞歸的次數,能夠推測出數據呈指數增加(與圖四柱狀圖相同),設y=a^x(設x是測試數據,y是遞歸次數),代入圖三數據求解得a=1.61。指數函數爲:
y=1.61^x
2.寫一段C程序批量執行利用指數函數對不一樣的輸入求解其遞歸次數。C代碼:
#include<stdio.h> #include<math.h>
int main() { int x; float y; scanf("%d",&x); y=pow(1.61,x); printf("%f\n",y); return 0; }
3. 執行結果:灰色列是測試數據n,白色列是求解出的遞歸次數。
圖9 指數函數推測遞歸次數實驗結果
折線圖表示實驗結果:
圖10 指數函數推測遞歸次數實驗結果折線圖
結論:經過這種方法,咱們測試數據較大時,能夠推測遞歸須要的次數。
缺點:與圖三遞歸次數結果相比,能夠看出指數函數求解獲得的數據有偏差,不精確。
1.根據遞歸方法求解「斐波那契數列」代碼能夠推導出求遞歸次數的遞推公式:
f(p)=f(p-1)+f(p-2)+1
設f(p)是遞歸次數。
2.實驗結果
圖11 遞推公式求解遞歸次數實驗結果
折線圖表示實驗結果:
圖12 遞推公式求解遞歸次數實驗結果折線圖
結論:與圖七相比能夠得出,經過遞推公式求解出的數據與實驗測得的數據相同,由此能夠證實經過遞推公式推測遞歸次數偏差爲零,能夠更加精確的推測當輸入的測試數據較大時須要遞歸的次數。
10.3指數函數與遞推公式求解遞歸次數對比
圖13 指數函數與遞推公式求解遞歸次數對比圖
結論:經過對比圖能夠得出,兩種方法的大體趨勢相同,呈指數增加。不一樣的是指數函數求解問題精度不高,有偏差。而遞推公式求解此問題精確度高,偏差爲零。
11、時間複雜度和空間複雜度分析
算法複雜度分爲時間複雜度和空間複雜度。其做用:時間複雜度是指執行算法所須要的計算工做量;而空間複雜度是指執行這個算法所須要的內存空間。(算法的複雜性體如今運行該算法時的計算機所需資源的多少上,計算機資源最重要的是時間和空間(即寄存器)資源,所以複雜度分爲時間和空間複雜度。動態規劃算法不隨測試數據的增大而增大,因此動態規劃算法的時間複雜度是O(1),空間複雜度是O(1)。
如圖所示,遞歸算法的時間複雜度爲(二叉樹的節點個數):O()=2^h-1=2^n(h爲二叉樹的高度),空間複雜度爲樹的高度:h即O(n)。
12、總結
本篇博客以斐波那契數列爲例,重點對動態規劃算法和遞歸算法作分析比較,經過一系列的實驗數據代表,動態規劃算法與遞歸算法相比下降的時間複雜度和空間複雜度,從而提升工做效率,節省時間。本篇博客實驗結果與預期實驗結果一致。最後感謝老師指點,感謝高遠博師兄耐心講解相關知識,感謝代秋彤師姐每日批註,感謝李淼洋學長指出個人錯誤。感謝!