V2.0
C++基础教程<br />——<br />作业及参考答案全部汇总文档<br/>节3函数阶段作业<br/><br/>最新版本V2.0
<br>王道C++团队<br/>COPYRIGHT ⓒ 2021-2024. 王道版权所有基础题篇函数基础语法练习题函数基础语法练习题2交互式简易计算器-函数/全局变量递归练习题扩展题篇扩展:打印目标步骤汉诺塔移动轨迹The End
Gn!
下面都是一些基础的语法、概念编程练习题。
Gn!
编写函数实现以下功能:
键盘录入一个正整数,请判断它是否是一个素数,然后控制台输出对应的结果。要对键盘录入的数据做参数校验,素数是一个大于1的自然数,它仅能被1和自身整除。
键盘录入两个整数:底(base)和幂指数(exponent),计算base的exponent次幂,并打印输出对应的结果。(注意底和幂指数都可能是负数)
提示:求幂运算时,基础的思路就是先无脑把指数转换成正数,然后累乘,最后再根据指数是否是负数决定是否取倒数。
参考代码如下:
参考代码:
第一题,判断素数:
xxxxxxxxxx
1234// 不要忘记包含头文件math.h
56
7bool is_prime(int num) {
8// 如果num是1甚至比1还小,那它一定不是素数
9if (num <= 1) {
10return false;
11}
12// 将num从2开始除,一直除到该数的平方根
13for (int i = 2; i <= sqrt(num); i++) {
14if (num % i == 0) {
15// 此过程中只要有一个除尽了,那么就不是素数
16return false;
17}
18
19return true;
20}
21}
22
23int main(void) {
24int num;
25
26printf("请输入一个整数: ");
27scanf("%d", &num);
28
29if (is_prime(num)) {
30printf("%d是一个素数!\n", num);
31}
32else {
33printf("%d不是一个素数!\n", num);
34}
35
36return 0;
37}
第二题参考代码:
xxxxxxxxxx
1// 计算 base 的 exponent 次幂 - 循环累乘求解
2double power(int base, int exponent) {
3double result = 1.0; // 存储计算结果
4// 若幂指数是0,则直接返回1
5if (exponent == 0) {
6return result;
7}
8/*
9在计算幂运算的过程中
10幂指数有可能是负数,但为了简化计算可以先将指数转换成正数求解
11计算完毕后,若指数是一个负数则取倒数就可以了
12*/
13int positive_exponent = exponent > 0 ? exponent : -exponent; // 确保幂指数是一个正数
14
15// 累乘 base
16for (int i = 0; i < positive_exponent; i++) {
17result *= base;
18}
19// 如果原幂指数是一个负数,则取倒数
20if (exponent < 0) {
21result = 1.0 / result;
22}
23return result;
24}
25
26int main() {
27int base, exponent;
28printf("请输入底数和指数(用空格分隔):");
29scanf("%d %d", &base, &exponent);
30
31double result = power(base, exponent);
32// 为了更好的显示负指数的小数结果,可以保留更多小数点后面的有效数字
33printf("%d 的 %d 次幂是 %.20lf\n", base, exponent, result);
34return 0;
35}
以上。
Gn!
键盘录入三个边长(带小数),然后用海伦公式计算三角形的面积(如果它确实是一个三角形的话)
海伦公式求三角形面积:
要求基于下列两个函数完成这个编程题:
1// 判断abc是否可以组成三角形,true表示可以组成,false表示不可以
2bool is_triangle(int a, int b, int c);
3
4// 利用海伦公式在abc可以构成三角形的前提下,求三角形面积
5double get_area(int a, int b, int c);
注意:不要忘记使用sqrt函数要包含头文件<math.h>
参考代码如下:
参考代码:
xxxxxxxxxx
12345
6
7// 判断abc是否可以组成三角形,true表示可以组成,false表示不可以
8bool is_triangle(int a, int b, int c);
9
10// 利用海伦公式在abc可以构成三角形的前提下,求三角形面积
11double get_area(int a, int b, int c);
12
13bool is_triangle(int a, int b, int c) {
14// 任意两边之和必须大于第三边
15return (a + b > c) && (a + c > b) && (b + c > a);
16}
17
18double get_area(int a, int b, int c) {
19double s = (a + b + c) / 2.0; // 计算半周长
20return sqrt(s * (s - a) * (s - b) * (s - c)); // 使用海伦公式计算面积
21}
22
23int main(void) {
24int a, b, c; // 三角形的三个边长
25printf("请您键盘输入三角形的三个边长:");
26scanf("%d%d%d", &a, &b, &c);
27
28if (!is_triangle(a, b, c)){
29// 不能组成三角形
30printf("Error: 无法组成三角形!\n");
31return -1;
32}
33
34// 可以组成三角形,于是计算三角形的面积
35double area = get_area(a, b, c);
36printf("三角形的面积是: %.2lf\n", area);
37
38return 0;
39}
以上。
Gn!
实现一个终端交互式的简易计算器,交互的形式大体如下:
要求至少提供四种运算加减乘除,如下:
xxxxxxxxxx
41int add(int a, int b);
2int subtract(int a, int b);
3int multiply(int a, int b);
4float divide(int a, int b);
并且在结束进程时,打印总共执行操作的次数。(也就是这些函数调用的次数)
注意:除法的实现,要求判断除数不为0,并且在除数为0时使用exit表示异常退出进程。
参考代码如下:
参考代码:
x1234
5// 全局变量,用于记录操作次数
6int operation_count = 0;
7
8// 函数声明
9int add(int a, int b);
10int subtract(int a, int b);
11int multiply(int a, int b);
12float divide(int a, int b);
13void print_operation_count();
14
15int main() {
16int a, b;
17char operator;
18char choice;
19
20do {
21printf("请输入要计算的表达式(例如,5 + 3): ");
22scanf(" %d %c %d", &a, &operator, &b);
23
24switch (operator) {
25case '+':
26printf("结果: %d\n", add(a, b));
27break;
28case '-':
29printf("结果: %d\n", subtract(a, b));
30break;
31case '*':
32printf("结果: %d\n", multiply(a, b));
33break;
34case '/':
35printf("结果: %.2f\n", divide(a, b));
36break;
37default:
38printf("无效的运算符。\n");
39}
40// 询问用户是否继续
41printf("是否继续? (y/n): ");
42scanf(" %c", &choice);
43printf("\n");
44} while (choice == 'y' || choice == 'Y');
45
46print_operation_count();
47return 0;
48}
49
50int add(int a, int b) {
51operation_count++;
52return a + b;
53}
54
55int subtract(int a, int b) {
56operation_count++;
57return a - b;
58}
59
60int multiply(int a, int b) {
61operation_count++;
62return a * b;
63}
64
65float divide(int a, int b) {
66if (b == 0) {
67printf("error:除数为零!\n");
68exit(1);
69}
70operation_count++;
71return (float)a / b;
72}
73
74void print_operation_count() {
75printf("总共执行的操作次数为: %d次\n", operation_count);
76}
以上。
Gn!
(1) 汉诺塔
有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
每次只能移动一个圆盘;
大盘不能叠在小盘上面。
利用递归的方式,打印出移动轨迹。运行结果如下图所示:
(2) 十进制转换成二进制
给定任意一个非负十进制整数,请利用递归的方式,求解它的二进制表示方式
基本的思路是:把该整数除以2得到余数,然后倒着输出余数。
思考一下:如何实现倒着打印余数呢?
参考代码如下:
参考代码如下:
第一题,求解汉诺塔移动轨迹,参考代码:
xxxxxxxxxx
123
4/*
5递归求解汉诺塔的移动轨迹
6假如有三座塔:A B C
7
8扩展:
9给定n个盘子,然后再给一个整数m,请你打印m + 1时,汉诺塔问题的移动轨迹
10*/
11
12// n个盘子的时候 start是原始塔 target是目标塔 sup是辅助塔
13void move(int n, char start, char target, char sup) {
14// 递归的出口
15// 当n=1时,直接将start上的唯一一个最大的盘子,移动到target上去
16if (n == 1) {
17printf("%c --> %c\n", start, target);
18return;
19}
20// 递归体
21// 1.第一步:把n-1个盘子从start移动到sup,这个过程需要target辅助
22// 第一步的n-1个盘子的时候 start是原始塔 sup是目标塔 target是辅助塔
23move(n - 1, start, sup, target);
24
25// 2.第二步:把最大的盘子从start移动到target
26printf("%c --> %c\n", start, target);
27
28// 3.第三步:把n-1个盘子从sup移动到target,这个过程需要start辅助
29// 第三步的n-1个盘子的时候 sup是原始塔 target是目标塔 start是辅助塔
30move(n - 1, sup, target, start);
31}
32
33void hanoi_track(int n) {
34long long steps = (1LL << n) - 1;
35printf("%d个盘子的汉诺塔问题,至少需要移动%lld步完成!\n", n, steps);
36
37// 该函数不能用于直接递归打印移动轨迹,所以需要一个辅助函数来完成递归,这种写法在递归中特别常见
38/*
39第二个参数是盘子的原始位置
40第三个参数是盘子移动完成汉诺塔问题的目标位置
41第四个参数是完成n个盘子汉诺塔问题时,需要的辅助塔
42*/
43move(n, 'A', 'C', 'B');
44}
45int main(void) {
46// 4表示汉诺塔问题中盘子的个数
47hanoi_track(4);
48return 0;
49}
第二题,十进制转换成二进制参考代码:
xxxxxxxxxx
123
4void decimal_to_binary(unsigned int n) {
5// 递归的出口
6// 0和1的十进制二进制表示是一样的
7if (n == 0 || n == 1) {
8printf("%u", n);
9return; // 直接返回,不再递归
10}
11
12// 递归体
13// 只要n不是0或1,那就递归调用除以2
14decimal_to_binary(n / 2);
15
16// 打印余数
17/*
18十进制转换成二进制
19最终要将余数进行倒读
20如何实现倒读余数呢?
21只需要将递归体放在打印余数的上面即可
22
23这种写法利用了栈的先进后出的特点
24先入栈也就是先求余数的,更大的数,反而最后打印余数
25后入栈也就是后求余数的,更小的数,反而最先打印余数
26这样就实现倒读余数
27*/
28printf("%u", n % 2);
29}
30
31
32int main(void) {
33decimal_to_binary(777);
34printf("\n");
35
36return 0;
37}
以上。
Gn!
以下题目都属于扩展题。
Gn!
汉诺塔移动轨迹的扩展题,感兴趣且学有余力可以研究一下,不做统一要求。
现在你已经知道如何打印n个盘子汉诺塔问题的移动轨迹了,那么在这个的基础上,我们进行以下扩展:
对于n个盘子的汉诺塔问题,给定一个整数m,要求在控制台打印出m + 1步的移动轨迹。
程序的运行图如下所示:
提示:
既然要打印m + 1步的移动轨迹,那么肯定需要计数器记录移动的步骤,需要用什么变量呢?
核心思路就还是move函数的递归,但要加上一个计数器,实际编码时注意边界值就可以了。
参考代码如下:
参考代码如下:
xxxxxxxxxx
123
4/*
5curr_steps用于指示当前移动的步数
6用static修饰的全局变量可以限制此变量仅在文件内部生效
7为什么不用静态局部变量呢?
8如果在move函数内部使用静态局部变量, 那么就无法将它归1了
9*/
10static int curr_steps;
11
12void move(int n, int m, char start, char target, char sup) {
13
14// 递归的出口
15if (n == 0) {
16// 没有盘子啥也不做,直接结束递归
17return;
18}
19// 递归体
20// 分解成三步
21// 1.第一步: 将n-1个盘子,从start塔移动到sup塔,target塔用于辅助
22move(n - 1, m, start, sup, target);
23
24// 2.第二步: 将1个盘子,从start塔移动到target塔,这里可以直接打印
25if (curr_steps == m + 1) {
26printf("%c --> %c\n", start, target);
27}
28curr_steps++;
29
30// 3.第三部: 将n-1个盘子,从sup塔移动到target塔,start塔用于辅助
31move(n - 1, m, sup, target, start);
32}
33void next_move_track(int n, int m) {
34if (n <= 0) {
35printf("error: 盘子数量小于等于0.\n");
36return;
37}
38int total_steps = (1LL << n) - 1;
39
40if (m < 0 || m >= total_steps) {
41printf("error: %d个盘子的汉诺塔问题没有%d步.\n", n, (m + 1));
42return;
43}
44curr_steps = 1;
45printf("%d个盘子的汉诺塔问题, 第%d步的移动轨迹是: ", n, (m + 1));
46move(n, m, 'A', 'C', 'B');
47}
48
49int main(void) {
50next_move_track(2, 2);
51next_move_track(3, 2);
52next_move_track(4, 10);
53return 0;
54}
以上。