遞迴與遞推學習
程式碼記錄
/*遞推【優於遞迴,減少重複工作】*/
//一·斐波拉契數列 A(n)=A(n-1)+A(n-2),輸入整數第n月,輸出每月兔子【1 1 2 3 5 8....】
//使用陣列儲存每一次結果,而不是函式自己執行自己
//#include<stdio.h>
//int main(){
// int a[10] = {0};//宣告陣列,60比50稍微大一點,避免陣列越界
// int n;
// scanf("%d",&n);
// a[1] = 1;
// a[2] = 1;
// for(int i=3;i<=n;i++){//之前忘記改資料了,i = 3,如果i = 0,編譯器將會產生不可知的行為
/*在程式設計中,每個程式都有自己的記憶體空間,這個空間被分為幾個部分,比如棧(stack)、堆(heap)和靜態儲存區(static storage)。當你宣告一個變數時,編譯器會為這個變數分配一塊記憶體,這塊記憶體是屬於你的程式的。
但是,如果你嘗試訪問一塊不屬於你的程式的記憶體,那麼就會發生“記憶體越界”或者“記憶體訪問錯誤”。這通常發生在以下幾種情況:
陣列越界:比如你有一個大小為10的陣列,但是你嘗試訪問陣列的第11個元素(比如array[10]),那麼你就會訪問到不屬於你的記憶體。
指標錯誤:如果你有一個指標,你沒有正確地初始化它,然後你嘗試透過這個指標訪問記憶體,那麼你可能會訪問到不屬於你的記憶體。
動態記憶體分配錯誤:如果你使用了動態記憶體分配(比如在C語言中使用malloc或new),但是你沒有正確地管理這些記憶體,比如忘記釋放或者釋放了之後還嘗試訪問,那麼你可能會訪問到不屬於你的記憶體。
當你訪問到不屬於你的記憶體時,可能會導致以下幾種結果:
程式崩潰:這是最常見的,因為作業系統會檢測到你的程式正在嘗試訪問不屬於它的記憶體,然後會終止你的程式。
資料損壞:如果你的程式修改了不屬於它的記憶體,那麼可能會導致其他程式或者作業系統的資料被破壞。
未定義行為:C語言標準將訪問不屬於你的記憶體定義為“未定義行為”,這意味著編譯器可以做任何它想做的事情,比如什麼也不做,或者讓你的程式崩潰,或者讓你的程式執行得很好,但是輸出錯誤的結果。*/
// a[i] = a[i-1] + a[i-2];
//
// }
// for(int i=1;i<=n;i++){
// printf("%d\n",a[i]);
// }
// return 0;
//}
//二·小方塊的堆積【遞推式 A(n) = A(n-1) + n 輸入一個整數n,顯示A(1).....A(n)】
//#include<stdio.h>
//int main(){
//// int arr[] = {0};這裡會出現陣列越界,就是說自己後面輸入一個值當作陣列長度,之前不預判長度的話就會出現陣列越界[這就是動態規劃導致的陣列越界]
///* 索引錯誤:最常見的原因是索引錯誤。例如,如果你的陣列有10個元素,索引範圍是0到9,但你嘗試訪問arr[10]或arr[-1],這就超出了陣列的範圍。
// 迴圈條件錯誤:在迴圈中處理陣列時,如果迴圈的條件設定得不正確,可能會導致陣列越界。例如,如果你的迴圈條件是i <= n,而陣列的大小是n,那麼當i等於n時,你將嘗試訪問arr[n],這會越界。
// 陣列大小動態變化:在某些情況下,陣列的實際大小可能會在程式執行時變化(例如,透過動態記憶體分配)。如果你沒有正確地跟蹤陣列的大小,可能會導致越界。
// 使用者輸入:如果你的程式依賴於使用者輸入來確定陣列的索引,而使用者輸入了一個超出範圍的值,這也可能導致陣列越界。
// 陣列初始化錯誤:如果你沒有正確地初始化陣列,可能會訪問到未初始化的記憶體。雖然這不一定是陣列越界,但它可能導致未定義的行為,這通常與陣列越界有關。*/
// int arr[50] = {0};
// int n = 0;
// scanf("%d",&n);
// arr[1]=1;
// for(int i=2;i<=n;i++){
// arr[i] = arr[i-1] + i;
// }
// for(int i=1;i<=n;i++){
// printf("%d\n",arr[i]);
// }
// return 0;
//}
//變式:顯示一共有多少個方塊
//#include<stdio.h>
//int main(){
// int n, sum = 0, ret;//一定要初始化sum!!!!!!!
// scanf("%d",&n);
// if(n == 1){
// printf("1");
// }else{
// for(int i=1;i<=n;i++){
// ret = 2 * i ;//就是找規律解決,反而沒有例一難
// sum += ret;
// }printf("%d",sum);
// }
//
// return 0;
//}
//二.猴子吃桃子
//#include<stdio.h>
//int main(){
// int sum = 0;
// for(int i=1;i<=2;i++){
// sum = (i + 1) * 2;
// int ret = sum;
// printf("%d\n",sum);
// }
// printf("%d",sum);
// return 0;
//}
//!!!!沒有快取sum,迴圈又從i = 2,開始
//#include<stdio.h>
//int main(){
// int arr[20] = {0};
// arr[1] = 1;//要錄入第一天桃子資料
// for(int i=2;i<=10;i++){
// arr[i] = (arr [i-1] + 1) * 2;
//// printf("%d",arr[i]);
// }
// printf("%d",arr[10]);
// return 0;
//}
//三·求解有規律的式子前n項和【1/1 +1/2 +2/3 +3/5 +5/8+... 輸入整數n,輸出小數,代表前n項和(保留三位小數)】
//遞迴法
//#include<stdio.h>
//int f(int n){
// int res = 0;
// if(n == 1||n ==2){
// return 1;
// }else{
// res += f(n-1) + f(n-2);
// return res;
// }
//}//計算分子
//int h(int n){
// int res = 0;
// if(n == 1){
// return 1;
// }else if(n == 2){
// return 2;//當時這裡也出錯了,有個else if
// }
// else{
// res += h(n-1) + h(n-2);//記住了,是兩項的遞迴,怎麼當時就寫一項去了
// return res;
// }
//}//計算分母
//int main(){
// double arr[50]={0} ,sum = 0 ,n = 0;
// scanf("%lf",&n);
//// arr[1] = 1;
//// arr[2] = 1 / 2.0;
// for(int i=1;i<=n;i++){
// arr[i] = (double)f(i) / h(i);
// sum += arr[i];
//// printf("%f ",sum);
// }
// printf("%.3f",sum);
// return 0;
//}
//遞推法
//#include<stdio.h>
//int main(){
// int arr[50] = {0},a[50] = {0} ,n = 0;
// double sum=0 ,ret = 0;
// scanf("%d",&n);
// arr[1] = 1;
// arr[2] = 1;
// a[1] = 1;
// a[2] = 2;
// if(n == 1){
// printf("1.000") ;
// }else if(n == 2){
// printf("1.500");
// }else{
// for(int i=3;i<=n;i++){
// arr[i] = arr[i-1] + arr[i-2];
// a[i] = a[i-1] + a[i -2];
// ret = (double) arr[i] / a[i];
// sum += ret ;
// }
// printf("%.3f",sum+3/2.0);//注意要分類討論,不然前兩項沒有加到,而且一定注意 3/2 ==1!!!
// }
// return 0;
//}