第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。
............
下面我们用表格来表示一下规率。
0 |
1 |
如何由表 1 推到表 2:
第一步:将表 1 拷贝两遍,形成表 2 的蓝色区域
第二步:将第二个元素的两种取值(0,1)插入表 2, 如表 2 绿区域所示。
0 | 0 |
1 | 0 |
0 | 1 |
1 | 1 |
表 2 推表 3 的步骤与表 1 推表 2 的步骤相同。
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)二进制法
全部代码见