哔哩大学计算机学院-C语言编程2023-P38练习

https://www.bilibili.com/video/BV1cq4y1U7sg

1.计算 n的阶乘。

首先初始化n和temp两个局部变量,n用来存放输入的数值,temp用来存放循环计算的中间值,最后输出temp。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 计算n的阶乘
int main()
{
int n = 0;
int temp = 1;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
temp = temp * i;
}
printf("n的阶乘是:%d\n", temp);
return 0;
}

2.计算 1!+2!+3!+..+10!

在上一题的思路上进行扩展,此时已指定为1!+2!+3!+..+10!,则不需要再输入n作为操作数。

同样设置temp_1和temp_2两个变量作为中间值的缓存,其中temp_1存放所有temp_2相加的值,即“temp_1 = temp_1 + temp_2;”放在第一个for循环里。

第一个for循环里面嵌套一个for循环用于计算当前i的值所属的阶乘,i则从1取到10,最后将结果存放在temp_1中,输出temp_1即1!+2!+3!+..+10!的值,可以通过将i设置为小一点的数如3进行验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 计算1!+2!+3!+..+10!
int main()
{
int temp_1 = 0;
for (int i = 1; i <=10; i++)
{
int temp_2 = 1;
for (int j = 1; j <= i; j++)
{
temp_2 = temp_2 * j;
}
temp_1 = temp_1 + temp_2;
}
printf("1!+2!+3!+..+10!=%d\n", temp_1);
return 0;
}

当然,两层循环的时间复杂度更高,有没有更优的算法呢?通过继续观看视频发现老师的思路非常妙,从阶乘中寻找规律:

2!= 1 * 2;

3!= 1 * 2 * 3;

4!= 1 * 2 * 3 * 4;

……

由此可以发现,往后的阶乘都是在前一个阶乘的基础上乘以他本身,所以得出一个更优的算法,只用一次循环,就可以计算出1!+2!+3!+..+10! 降低时间复杂度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

// 计算1!+2!+3!+..+10!
int main()
{
int temp_1 = 0;
int temp_2 = 1;
for (int i = 1; i <=10; i++)
{
temp_2 = temp_2 * i;
temp_1 = temp_1 + temp_2;
}
printf("1!+2!+3!+..+10!=%d\n", temp_1);
return 0;
}

3.在一个有序数组中査找具体的某个数字n;

当数据量小的时候可以使用直接使用循环进行对比查找,如果想等则输出v[i]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
int v[10] = { 1,2,3,4,5,6,7,8,9,10 };
//有序数组假设值为1~10,当数据量小的时候可以使用循环进行对比查找
//输入要查找的数字
int n = 0;
scanf("%d", &n);
for (int i = 0; i < 10; i++)
{
if (n == v[i])
printf("您要找的数字是%d\n", v[i]);
}
return 0;
}

但是对于一个有序的数组来说,或者当数据量较大的时候,还从头循环进行比对效率太低。因为他是有序的数组,不管数字多少,都是从小到大排列的,假设我每次都从中间开始进行判断,如果中间的数字比他大,就说明这个数在前半段区间,然后往复比较中间值最后得出结果,这样的方法肯定效率更高。(二分法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
int v[10] = { 1,2,3,4,5,6,7,8,9,10 }; // 假设有序数组为1-10
int len = sizeof(v) / sizeof(v[0]);
int n = 0;
scanf("%d", &n);// 输入要查找的数字
int left = 0; // 设置查找的左下标
int right = len; // 设置查找的右下标
int mid = 0;
while (left <= right)
{
mid = (left + right) / 2;
if (v[mid] < n) // 要查找的数字在中间值的右边,则使左下标为中间值+1
{
left = mid + 1;
}
else if (v[mid] > n)
{
right = mid - 1;
}
else
{
printf("要查找的数字为:%d\n", mid + 1);
break;
}
}
if (left > right)
{
printf("error");
}
return 0;
}

当输入数字不在数组中,则输出error。

4.编写代码,演示多个字符从两端移动,向中间汇聚。

要实现的目标即类似如下:

假设要打印”Hello World!”,则不断从两端打印,最后输出完整字符串。

“H————–!”

“He———–d!”

……

“Hello World!”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <Windows.h>

int main()
{
char arr1[] = "Hello World!";
char arr2[] = "************";
int left = 0;
int right = strlen(arr1)-1;
for (int i = 0; i < strlen(arr1); i++)
{
if (left > right)
{
break;
}
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(500); // 延时0.5s
system("cls"); // 清空屏幕
left++;
right--;
}
printf("%s\n", arr2); // 清空屏幕后再显示完整字符串
}

通过替换数组的左右下标的值达到效果,逐行输出。引用”windows.h”头文件的Sleep()函数达到一个延时输出的效果。

5.编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成,如果三次均输入错误,则退出程序。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <Windows.h>

int main()
{
char password[20] = "123456"; // 假设正确密码为:123456
char input[20] = { 0 };
for (int i = 0; i < 3; i++)
{
printf("请输入密码:>");
scanf("%s", input);
if (strcmp(input, password) == 0)
{
printf("登录成功\n");
break;
}
else if (i == 2)
{
printf("错误次数超过三次,退出程序\n");
break;
}
else
{
printf("登录失败,请重试!\n");
}
}
}