第1章 C++回顾

1.7 递归函数

练习 19 - 26

 

  1 #include <iostream>
  2 #include <cmath> // pow(double base, double exp) 
  3 #include <ctime>
  4 using namespace std;
  5 
  6 // 《数据结构,算法与应用》中递归的相应题目
  7 // 第一章17-26
  8 // P28 ~ P30
  9 
 10 // 19. n! 
 11 int calculate_factorial_of_n_with_non_recursive_program(int n)
 12 {
 13     // 0 的阶乘是 1 
 14     if (n == 0)
 15         return 1;
 16     // 负数没有阶乘 
 17     else if (n < 0)
 18     {
 19         throw "Negative numbers have no factorials!";
 20         return -1;
 21     }    
 22     else
 23     {
 24         int factorial_result = 1;
 25         // n! = n x (n-1) x (n-2) x ... x 1 
 26         while(n > 1)
 27         {
 28             factorial_result *= n;
 29             n -= 1;
 30         }
 31         return factorial_result;
 32     }    
 33 }
 34 
 35 int calculate_factorial_of_n_with_recursive_program(int n)
 36 {
 37 // f(n) = { 1, if n = 1
 38 //            n * f(n-1), else
 39 //          }
 40     // 0 的阶乘是 1 
 41     if (n == 0)
 42         return 1;
 43     // 基础部分 
 44     else if (n == 1)
 45         return 1;
 46     // 负数没有阶乘
 47     else if (n < 0)
 48     {
 49         throw "Negative numbers have no factorials!";
 50         return -1;
 51     }
 52     // 递归部分
 53     // n! = n x (n-1) x (n-2) x ... x 1 
 54     else
 55         return n * calculate_factorial_of_n_with_recursive_program(n-1);
 56 }
 57 
 58 // 测试19 
 59 void test_calculate_factorial()
 60 {
 61     int n = 0;
 62     try
 63     {
 64         int result = calculate_factorial_of_n_with_non_recursive_program(n);
 65         cout << "With non-recursive program, factorial of n = ";
 66         cout << result;
 67     }
 68     // 捕获 n 为负数的异常    
 69     catch(const char* e)
 70     {
 71         cout << e;
 72     }    
 73     cout << endl;
 74     
 75     try
 76     {
 77         int result = calculate_factorial_of_n_with_recursive_program(n);
 78         cout << "With recursive program, factorial of n = ";
 79         cout << result;
 80     }
 81     catch(const char* e)
 82     {
 83         cout << e;
 84     }    
 85     cout << endl;
 86 }
 87 
 88 // ============================================================================================================================================= //
 89 
 90 // 20. 斐波那契数列(Fibonacci sequence) 
 91 int calculate_Fibonacci_with_recursive_funcation(int n)
 92 {
 93     if (n == 0)
 94         return 0;
 95     else if (n == 1)
 96         return 1;
 97     else 
 98         return calculate_Fibonacci_with_recursive_funcation(n-1) + calculate_Fibonacci_with_recursive_funcation(n-2);
 99 } 
100 
101 int calculate_Fibonacci_with_non_recursive_funcation(int n)
102 { 
103     int* a = new int[n+1];
104     a[0] = 0; a[1] = 1;
105     for (int i = 2; i <= n; i ++)
106         a[i] = a[i-1] + a[i-2];
107     return a[n];
108 }
109 
110 // 测试20
111 void test_calculate_Fibonacci()
112 {
113     int n = 7;
114     cout << "With recursive funcation, Fibonacci sequence F(" << n << ") = ";  
115     cout << calculate_Fibonacci_with_recursive_funcation(n);
116     cout << endl;
117     
118     cout << "With non-recursive funcation, Fibonacci sequence F(" << n << ") = ";  
119     cout << calculate_Fibonacci_with_non_recursive_funcation(n);
120     cout << endl;
121 }
122 
123 
124 // ============================================================================================================================================= //
125 
126 // 21.
127 int calculate_f_n_with_recursive_funcation(int n)
128 {
129     if(n % 2 == 0)// 偶数 
130         return n / 2;
131     else
132         return calculate_f_n_with_recursive_funcation(3*n+1);    
133 }
134 
135 int  calculate_f_n_with_non_recursive_funcation(int n)
136 {
137     if (n % 2 == 0)// 偶数
138         return n / 2;
139     else// 奇数,则 3n+1 定为偶数 
140         return  (3 * n + 1) / 2;
141 }
142 
143 // 测试21
144 void test_f_n()
145 {
146     int n = 4;
147     cout << "With recursive funcation, f(" << n << ") = ";  
148     cout << calculate_f_n_with_recursive_funcation(n);
149     cout << endl;
150     
151     cout << "With non-recursive funcation, f(" << n << ") = ";  
152     cout << calculate_f_n_with_non_recursive_funcation(n);
153     cout << endl;
154 } 
155  
156 // ============================================================================================================================================= //
157 
158 // 22. 阿克曼函数
159 int calculate_Ackermann_funcation(int i, int j)
160 {
161     if (i < 1 || j < 1)
162         return -1;
163     if (i == 1 && j >= 1)
164         return pow(2.0, j);    
165     else if (i >= 2 && j == 1)
166         return calculate_Ackermann_funcation(i-1, 2);
167     else
168         return calculate_Ackermann_funcation(i-1, calculate_Ackermann_funcation(i, j-1));
169 }
170 
171 // 测试22
172 void test_Ackermann_funcation()
173 {
174     int i = 2, j = 2;
175     cout << "Ackermann`s funcation("  << i << ", " << j << ") = ";
176     cout << calculate_Ackermann_funcation(i, j);
177     cout << endl;
178 } 
179 
180 // ============================================================================================================================================= //
181 
182 // 23. 最大公约数(Greatest Common Divisor,GCD) 
183 int calculate_GCD_with_recursive_funcation(int x, int y)
184 {
185     if (y == 0)
186         return x;
187     else
188         return calculate_GCD_with_recursive_funcation(y, x%y);        
189 }
190 
191 int calculate_GCD_with_non_recursive_funcation(int x, int y)
192 {
193     if (x < y) // 保证 x > y 
194         swap(x, y);
195     
196     while(y != 0)
197     {
198         int temp = x % y;
199         x = y;
200         y = temp;
201     }
202     return x; 
203 }
204 
205 // 测试23 
206 void test_GCD()
207 {
208     int x = 18, y = 24;
209     cout << "With recursive funcation, GCD(" << x << ", " << y << ") = ";  
210     cout << calculate_GCD_with_recursive_funcation(x, y);
211     cout << endl;
212     
213     cout << "With non-recursive funcation, GCD(" << x << ", " << y << ") = ";
214     cout << calculate_GCD_with_non_recursive_funcation(x, y);
215     cout << endl;
216 }
217 
218 // ============================================================================================================================================= //
219 
220 // 24.
221 template<class T>
222 int search_for_x_in_array_a(const T a[], const T x, int start, int end)
223 {
224     if (start > end)
225         return -1;
226     else
227     {
228         int middle = int((start + end) / 2);
229         if(a[middle] == x)
230             return middle; 
231         // cout << middle << endl;
232         else 
233         {
234             int index = search_for_x_in_array_a(a, x, start, middle-1);
235             // cout << endl << middle << endl;
236             if (index == -1) // 关键 
237                 search_for_x_in_array_a(a, x, middle+1, end);
238         }
239     }
240 }
241 
242 // 测试24
243 void test_search_x()
244 {
245     int a[] = {5, 2, 45, 7, 8, 3};
246     int a_x = 2;
247     //int a_x = 10;
248      
249     char b[] = {'a', 'c', 'w', 'p', 'r', 'o'};
250     char b_x = 'w';
251     //char b_x = 'e';
252     cout << a_x << "在数组a中的下标为:"; 
253     cout << search_for_x_in_array_a(a, a_x, 0, 6-1);
254     cout << endl;
255     cout << b_x << "在数组b中的下标为:"; 
256     cout << search_for_x_in_array_a(b, b_x, 0, 6-1);
257     cout << endl;
258 }
259 
260 // ============================================================================================================================================= //
261 
262 // 25. 子集生成方法
263 int sequence[10000][10000];
264 int subset_generation(int n)
265 {
266     if (n == 0)
267     {// 空集的子集只有空集 
268         cout << 0 << endl;
269         return 1;
270     } 
271     else if (n == 1)
272     {
273         for (int i = 0; i <= 1; i ++)
274             sequence[i][1] = i; 
275         return 2;
276     }
277     else
278     {
279         int row_length = subset_generation(n-1);
280         int cur_row_length = 2 * row_length; 
281         // 拷贝两遍 n-1 个元素的信息 
282         for (int row = row_length; row < cur_row_length; row ++)
283             for (int col = 1; col <= n-1; col ++)
284                     sequence[row][col] = sequence[row-row_length][col];
285         // 添加第 n 个元素
286         for (int row = 0; row < cur_row_length; row ++)
287             sequence[row][n] = row < row_length? 0 : 1;        
288         return cur_row_length;
289     }    
290 }
291 
292 
293 void subset_generation_with_non_recursive_funcation(const int n)
294 {// 转二进制 
295     int subset[n] = {0};
296     // n 位二进制转其能表示的最大十进制
297     int number = 1;
298     for (int i = n-1; i > 0; i --) 
299         number += pow(2.0, i);
300     
301     for (int i = 0; i <= number; i ++)
302     {
303         int temp_n = n;
304         int temp_i = i;
305         while(temp_i > 0)
306         {
307             subset[temp_n-1] = temp_i % 2;
308             temp_i /= 2;
309             temp_n --;
310         }
311         for(int j = 0; j < n; j ++)
312             cout << subset[j];
313         cout << endl;
314     }
315      
316 }
317  
318 // 测试25 
319 void test_subset_generation()
320 {
321     // n must lower than seven
322     // int n = 10;
323     int n = 3;
324     time_t start_time = time(0); 
325     // cout << start_time << endl;
326     cout << "all subsets are:" << endl;
327     int length = subset_generation(n);
328     if (length <= 1)
329         return;
330     for (int i = 0; i < length; i ++)
331     {
332         for (int j = 1; j <= n; j ++)
333             cout << sequence[i][j];
334         cout << endl;
335     }
336     time_t end_time = time(0);
337     cout << end_time - start_time << endl;
338     start_time = time(0);
339     cout << "with non-recursive_way, all subsets are:" << endl;
340     subset_generation_with_non_recursive_funcation(n);
341     end_time = time(0);
342     cout << end_time - start_time << endl;
343     // 经测试,递归快一点 
344     
345 }
346  
347  
348 // ============================================================================================================================================= //
349 
350 // 26.格雷码(Gray Code)
351 void print_Gray_code_of_n(int n)
352 {
353     if (n == 1)
354         cout << 1 << ' ';
355     else
356     {
357         print_Gray_code_of_n(n-1);
358         cout << n << ' ';
359         print_Gray_code_of_n(n-1);    
360     }    
361 } 
362 
363 // 测试26
364 void test_gray_code()
365 {
366     int n = 3;
367     cout << "Gray Code is:"; 
368     print_Gray_code_of_n(n);
369 } 
370  
371 
372 // ============================================================================================================================================= //
373 int main()
374 {
375     // 测试19 
376     test_calculate_factorial();
377     
378     // 测试20 
379     test_calculate_Fibonacci();
380     
381     // 测试21
382     test_f_n(); 
383     
384     // 测试22
385     test_Ackermann_funcation();
386     
387     // cout << 18 % 24<< endl;
388     // 18
389     // 测试23 
390     test_GCD();
391     
392     // 测试24
393     test_search_x();
394     
395     // 测试25 
396     test_subset_generation();
397     
398     // 测试26
399     test_gray_code(); 
400     return 0;
401 }
402  

 

 24. 编写一个递归模板函数,确定元素x是否属于数组a[0: n-1]。

  我编写的是一个查找无须数组的递归版折半查找法(尽管折半查找不支持无序?)

  search函数在a中查找x的步骤如下图所示

  遇到的问题:

  一开始没有第236行(黄色标记行),导致查找结果一直为-1。

  原因:

  查找结束时,递归函数返回上一层,不会中断(跳出所有的递归层)。又因为没有225行的if语句判断,故当前层的递归函数向下继续运行。

  解决办法:

  在236行加上if判断

  代码见

 

 25. [子集生成方法(Subset Generation)]编写一个C++递归函数,输出n个元素的所有子集。例如,三元素集{a,b,c}的子集是{}(空集),{a},{b},{c},{a,b},{a,c},{b,c},{a,b,c}。这些子集用0/1组成的代码序列来表示分别是000,100,010,001,110,101,011,111(0表示相应的元素不在子集中,1表示相应的元素在子集中)。因此你的程序输出长度为n的0/1序列即可。

  子集生成法的实质:n位二进制的种数。

  (1)递归法

    当 n = 0 时,即该  n 元素集为空集, 空集的子集只有一个空集,故输出为 0。

    当 n = 1 时,即 1 元素集,比如{ a },它有两个子集{ }, { a }, 故输出为 0、1。

    当 n = 2 时,即 2 元素集,比如{ a,  b },它有四个子集{ }, { a },{ b },{ a,b},故输出为 00、10、 01、 11。

    ............

    下面我们用表格来表示一下规率。


表1:n = 1
0
1

   如何由表 1 推到表 2:
    第一步:将表 1 拷贝两遍,形成表 2 的蓝色区域
    第二步:将第二个元素的两种取值(0,1)插入表 2, 如表 2 绿区域所示。

  
表2:n = 2
0 0
1 0
0 1
1 1
   表 2 推表 3 的步骤与表 1 推表 2 的步骤相同。
表3:n = 3
0 0 0
1 0 0
0 1 0
1 1 0

0 0 1
1 0 1
0 1 1
1 1 1

    上述的表 1 到 表 3 是即为程序中的sequence,它采用二维表格存储结果。

    代码见

  (2)二进制法

    代码见

 

 



 

全部代码见

  https://github.com/Hu-Xiaoming/Data-Structures/blob/master/recursive%20code/practiceOfRecursion_19-26.cpp

 

posted @ 2020-06-07 18:28  阿傥  阅读(200)  评论(0编辑  收藏  举报