大家好,很高兴又和大家见面了!!!今天咱们继续分享分支与循环的相关习题,以此来巩固这个章节的知识点。下面就是我们今天要分享的题目:
- 计算n的阶乘。
- 计算1!+2!+3!+……+10!
有兴趣的朋友可以先自己动手完成习题,再回过来看内容解析。接下来,我们就开始讲解咱们今天的习题;
习题演练——分支与循环篇
1.计算n的阶乘
看到这一题,我们可以马上想到n的阶乘公式:n!=1*2*3*……*(n-2)*(n-1)*n。
计算公式我们有了,接下来就是通过代码来实现这个公式了。
题目解析
第一步:我们需要实现这个公式的话,我们先要找出我们需要的元素:
一个是项数n,一个是接收乘积的n!;
但是我们在编译器中可不能直接定义n!=0,因为在C语言中!=是一个关系操作符,所以我们不能定义n!这个标识符,这里我们就用阶乘的英文factorial的前三个字母fac来表示阶乘;
第二步:我们既然是要求n!那这个n的值应该是根据我们的具体要求来定的,这里我们可以通过输入函数scanf来实现;
第三步:我们既然计算1~n之间的乘积的话,我们是不是需要先生成这些数,才能按要求完成计算呀,这里我们可以参考上一篇中打印1~100之间的奇数这一题来编写代码生成1~n之间的数,这里就需要用到循环语句来实现;
第四步:我们最终要完成的是数与数之间的乘积,既然如此,那我们就需要使这些数相乘,也就是我们需要得到i*(i+1)*(i+2)*……*(i+n-i-1)*(i+n-i),这个应该怎么实现呢?
这里我们就需要展开介绍一下循环语句的特点——每进行一次循环,循环内的指令都会执行一次。
也就是说,i从1开始进入循环的话,那就只生成了1,在递进后再次进入循环才能得到2,那我们现在就需要把每一次生成的数都给存储下来,并且还需要让这些数相乘,既然如此,那我们就通过表格来理清一下思路:
循环次数 | 变量i值 | 存储值 | fac值 |
1 | i=1 | 1 | 1 |
2 | i=2 | 2 | 1*2 |
3 | i=3 | 3 | 1*2*3 |
…… | |||
n-2 | i=n-2 | n-2 | 1*2*3*……*(n-2) |
n-1 | i=n-1 | n-1 | 1*2*3*……*(n-2)*(n-1) |
n | i=n | n | 1*2*3*……*(n-2)*(n-1)*n |
从表格中我们可以看到,我们在每一次循环如果fac的值都能与生成的值相乘的话,是不是就可以解决问题了。如果是这样,在第一次循环时我们又应该怎么处理呢?
有朋友很快就想到了,如果我将fac的值初始化为1,让1来与1相乘是不是就可以了呢?也就是我们第一次循环执行的是fac=1*1,第二次是1*1*2以此类推一直到第n项是不是就可以了。
代码实现
有了具体思路,我们就可以开始编写代码了:
//计算n!
//方法1——循环(顺序求解1*2*3*……*n)
int main()
{
//定义变量n来接收输入值
int n = 0;
//定义阶乘变量fac来接收阶乘值,并初始化为1
int fac = 1;
//通过输入函数来输入我们需要求解的值
scanf("%d", &n);
//定义循环变量i来控制循环次数
for (int i = 1; i <= n; i++)
{
//存储每一次循环的阶乘值
fac = fac * i;
}
//打印阶乘值
printf("%d!=%d\n", n, fac);
return 0;
}
这样编码,我们的思路就很清晰了,下面就是检验结果的时间了,我们知道5!=1*2*3*4*5=120,下面我们来测试一下,输入5,看能不能算出5!:
可以看到,代码很好的实现了我们的需求。到这里,这一题就被我们完成了,在开始下一题之前,我来给大家分享一下几种其它的编码思路;
思路拓展
刚刚第一种思路,我们是按照顺序思维来进行分析的,那我们可不可以通过逆向思维来分析,前面我们从1开始往后求阶乘,现在我们来尝试一下从n来往前求阶乘。在编码前,我们还是通过表格来理清思路:
循环次数 | 变量i值 | 存储值 | fac值 |
---|---|---|---|
1 | i=n | n | 1*n |
2 | i=n-1 | n-1 | 1*n*(n-1) |
3 | i=n-2 | n-2 | 1*n*(n-1)*(n-2) |
…… | |||
n-3 | i=3 | 3 | 1*n*(n-1)*(n-2)*……*3 |
n-2 | i=2 | 2 | 1*n*(n-1)*(n-2)*……*3*2 |
n-1 | i=1 | 1 | 1*n*(n-1)*(n-2)*……*3*2*1 |
从表格中我们可看到像这样编码,确实可行,接下来,我们直接开始编写代码:
//方法2——循环(逆序求解:n*(n-1)*(n-2)*……*1)
int main()
{
int n = 0;
int fac = 1;
scanf("%d", &n);
//i需要从n一直减到1,所以i的最小值应该为1
for (int i = n; i >= 1; i--)
{
fac = fac * i;
}
printf("%d!=%d\n", n, fac);
return 0;
}
代码编写好之后,我们来测试一下,这样编写的代码是否能实现我们的功能:
我们可以看到,像这样编写代码确实也能解决这个问题。接下来我们围绕这两个思路还有没有其它的编写方法呢?下面我把我自己想到的方式分享给大家:
//方法3——循环——逆序求解(n*(n-1)*(n-2)*……*1)
int main()
{
int n = 0;
int fac = 1;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
fac *= (n - i);
}
printf("%d!=%d\n", n, fac);
return 0;
}
//方法4——定义宏——顺序求解(1*2*3*……*n)
#define Fac(n,i,fac) (n>i?(fac*=i):(fac*=n))
int main()
{
int n = 0;
int fac = 1;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
fac = Fac(n, i, fac);
}
printf("%d!=%d\n", n, fac);
return 0;
}
//方法5——定义宏——逆序求解(n*(n-1)*(n-2)*……*1)
#define Fac(n,i,fac) (i==n?(fac*=n):(fac*=i))
int main()
{
int n = 0;
int fac = 1;
scanf("%d", &n);
for (int i = n; i >= 1; i--)
{
fac = Fac(n, i, fac);
}
printf("%d!=%d\n", n, fac);
return 0;
}
//方法6——定义宏——逆序求解(n*(n-1)*(n-2)*……*1)
#define Fac(n,i,fac) (i==n?(fac*=1):(fac*=(n-i)))
int main()
{
int n = 0;
int fac = 1;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
fac = Fac(n, i, fac);
}
printf("%d!=%d\n", n, fac);
return 0;
}
这里有几点需要说明一下:
1.目前我们是在分支与循环的章节来求解这一题,所以使用的主要还是循环来实现,等后面我们介绍完函数篇章,我们还可以来用函数递归与迭代的方式来求解这一题,这里我就不继续展开分享了;
2.这几种方法主要还是通过定义宏来实现的,零基础的朋友们可能还不知道什么是定义宏,函数也不太了解,没关系,这里我们只需要知道有这种方式求解就行,目前不需要深究;
3.除了上述的这些方法,肯定还会有其它的方法来求解这一题,具体可以如何做到,这就将评论区留给朋友们你们自行分享吧。
第一题的求解过程我们就分享到这里了,接下来我们继续来看第二题;
2.计算1!+2!+3!+……+10!
在上一题中,我们求的是第n项的阶乘,现在题目需要我们求解的是前10项的和,这里我们有应该怎么去解决呢?做题前先对题目进行解析,理清解题思路;
题目解析
第一步:要求前10项的和,我们应该先生成前10项才行,每一项的生成可以参考上一题;
第二步:我们要将每次生成的阶乘给存储起来,存储的方式肯定是通过变量,这里我们依旧可以使用fac来进行存储阶乘值;
第三步:我们需要求的是阶乘的和,这里我们可以通过定义变量sum来存储阶乘的和,具体如何接收,这里还是通过表格来理解:
循环次数 | 变量i值 | fac值 | sum值 |
1 | i=1 | 1*1 | 1! |
2 | i=2 | 1*1*2 | 1!+2! |
…… | |||
10 | i=10 | 1*1*2*……*10 | 1!+2!+……+10! |
通过表格,现在我们就看的很清楚了,此时我们只需要在求阶乘的代码内加上一个sum并与fac做加法,问题就解决了,这里我们可以看到,第一次循环sum是需要存储1!,既然这样,sum的初始值就只能是0,才不会改变fac的大小;
代码实现
有了思路,那我们就开始进行编码吧:
//计算1!+2!+……+10!
//方法1——循环(顺序求解)
int main()
{
//要求的是前10项的和,所以n的值可以确定为10
int n = 10;
//定义阶乘变量
int fac = 1;
//定义求和变量
int sum = 0;
//通过循环生成每一项
for (int i = 1; i <= n; i++)
{
//通过阶乘变量存储阶乘值
fac *= i;
//通过打印函数打印出阶乘生成过程
printf("%2d!=%-8d ", i, fac);
//通过求和变量存储阶乘之和
sum += fac;
//通过打印函数打印出阶乘求和过程
printf("前%2d项阶乘的和sum=%-8d\n", i, sum);
}
printf("前10项阶乘的和sum=%d\n", sum);
return 0;
}
这里可能会有朋友好奇,为什么我打印的是后是%2d和%-8d,别着急,我们先看一下打印效果再来给大家解释:
从打印结果中我们可以看到,此时我们不仅完成了题目要求,我们还展示了阶乘的生成过程与求和过程,并且排版是不是很整齐啊。这个排版就是我要给大家介绍的%nd和%-nd;
打印整型(%nd与%-nd)
我们可以看到当我们打印%2d时,打印结果的排版是呈现右对齐的状态,数的左边加入了一个空格;
当我们打印%-8d的时候,我们可以看到,打印结果是呈现左对齐的状态,数的右边加入了1~7个空格;
前一个结果和后一个结果之间有10个字符的举例,多出来的两个空格是因为我在打印结果中加入了两个空格;
由此我们可以得出整型打印的以下结论:
当打印%nd或%-nd时,输出结果会根据n的大小来决定打印的位数;
当打印的是%nd,输出结果会成右对齐状态,如果实际结果的位数<n,则打印时不足的位数会用空格填补;
当打印的是%-nd,输出的结果会成左对齐状态,如果实际结果的位数<n,则打印时不足的位数会用空格填补;
如图所示,图中就很形象的展示了整型打印的两种对齐方式,这里我是拿n=8举例,并不是说整型打印最多只能让n=8;
思路拓展
这题到现在我们就已经解决完了,但是这题的解题方式肯定不止这一种,同样的我们也可以按顺序和逆序两种方式来求解,求解的具体方法也有很多,可以像我一样使用循环直接求解,也可以通过定义宏来进行求解,这里我给大家分享一下如何通过定义宏来完成逆序求解;
#define定义宏
因为阅读本篇文章的朋友一部分可能很熟悉#define的相关知识点,还有部分朋友可能是刚刚开始学习,不太熟悉这一块内容,所以这里我先说结论;
#define定义宏可以简单的理解为通过#define这个指令定义的一个功能,这个功能的实现形式有多种,这里我们介绍的形式是类似于函数(函数的相关知识点我们会在后面进行分析)。
定义宏的格式:
#define 标识符(变量) (表达式1?表达式2:表达式3)
标识符的值
这个代码的意思就是我们在借助标识符完成这个功能时,标识符的值会根据后面的三目操作符的值来确定:当表达式1为真,则表达式2的值为标识符的值,当表达式1为假,则表达式3的值为标识符的值。
通过宏定义解题
这里我们不要混淆了,我们现在介绍的宏定义是只能完成一个功能的,所以这个宏要直接实现fac和sum两个内容肯定是不现实的。这个问题也很好解决,我们可以将其中一个功能通过宏定义完成就行,也可以将2者都进行宏定义。这里我们介绍第一种,将其中一个功能通过宏定义来实现。
第一步:我们需要通过变量n来进行n次循环生成1~n个阶乘,阶乘的生成需要通过循环变量i来实现,所以我们这里需要通过两个循环才能逆向生成n~1的阶乘;
第二步:在所有的阶乘都生成后我们才能求和,这里就可以使用宏定义来完成求和;
第三步:我们要清楚宏定义的相关元素分别是什么?
通过第一种解题方式,我们知道,此时我们需要的变量是i、fac、sum、n,那我们在宏中具体需要哪些变量呢?
从宏定义的格式我们可以看到,它是需要3个表达式的,第一个用作判断,后面两个来进行求值。第一个判断的内容是什么呢?
有的朋友反应很快,通过表示符的取值方式,能很快的联想到这个是类似于分支语句的判定,所以我们这里判断的就是实现具体内容的条件。
在一个阶乘生成后,我们就需要通过宏既然这样我们只需要判断n与1的关系就可以了。
这里我们想用逆序的方式求解,那我们的第一个数肯定是n循环结束的值肯定是1,所以我们可以在表达式1中来判断n>1是否成立:
n>1时,我们需要执行的是sum+=fac;
n=1时,我们只需要执行sum+=1就可以了。
代码如下:
//方法2——宏定义(逆序求解)
#define Sum(n,fac,sum) (n>1?(sum+=fac):(sum+=1))
int main()
{
int n = 0;
int fac = 1;
int sum = 0;
//第一种解法我们直接将10赋值给n,这里我们通过scanf来进行赋值
scanf("%d", &n);
for (n; n >= 1; n--)
{
for (int i = n; i >= 1; i--)
{
fac *= i;
}
printf("%2d!=%-8d ", n , fac);
sum = Sum(n, fac, sum);
printf("后%2d项阶乘的和sum=%-8d\n", n , sum);
fac = 1;
}
printf("前10项阶乘的和sum=%d\n", sum);
return 0;
}
下面我们就来测试一下代码的运行情况:
可以看到,我们现在也通过宏定义进行了逆序求解。
现在咱们就完成了这两题的介绍,第一题我给大家分享的写法,大家可以下去尝试一下,这第二题你们可以尝试通过不同的写法来对其进行求解。
再强调一下,我们现在还没有介绍函数,所以大家尽量用分支与循环的方式求解,可以通过宏定义来求解,以此来巩固相关知识点。
结语
这两题我们在巩固循环语句的同时,又简单介绍了一下宏定义的相关内容。宏定义大家如果还没理解的话也没关系,后续我会继续分享相关的知识点。最后感谢大家的翻阅,希望这篇能够给大家提供一些不同的解题方法,帮助大家更好的将知识点融会贯通,咱们下一篇再见。