1>>前言
函数递归函数递归,当小白听到这样的词会感到无比陌生,请不要惊慌,这是正常的,以至于都不是很经常用到,但是它的算法,它的思想是值得我们深入思考的。还有一些复杂操作符,如按位与按位或等等,今天一并说说,希望大家能学到东西。
2>>函数递归
函数的递归分为递推与回归,就是将一个重复的事情逐渐化小,这就叫递推,类似于高等数学的微分,回归就是将缩小的事情再放大,这就是回归,类似于积分。这里我们给出一个题目,输入一个数,使用函数递归求出该数阶乘。我们借助题目能更好理解递归的概念。
2.1>>附:阶乘概念
首先我们需要知道,阶乘是从1开始逐步乘到需要的数,如5的阶乘就是1*2*3*4*5。3的阶乘就是1*2*3,用3!表示,6的阶乘就用6!表示。一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。亦即n!=1×2×3×...×(n-1)×n。
2.2>>递推
在我们了解了阶乘的概念后,我们就可以引入递推了,将大事化小,如5的阶乘可以写作5*4!而4的阶乘可以写作4*3!这里以此类推,可以发现n!=n*n(-1)!那么我们将它代入函数就可以做到递推,这边看代码,然后我放一张图具体解释同学们就懂了。
#include<stdio.h>
//题目:输入一个数,使用函数递归求出该数的阶乘。
int Fact(a)
{
if (a<=0)
return 1;
else
return a*Fact(a-1);
}
int main()
{
int a=0;
scanf("%d",&a);
int c=Fact(a);
printf("%d\n",c);
return 0;
}
这里我们计算5的阶乘为例子,a=5进入Fact函数,因为a>0所以进入else语句
这里5进来又遇到了函数Fact,此时把4代入以此类推,直到a=0开始返回数值。
2.3>>回归
开始返回值时并不是一下子返回到主函数,而是像前面的递推一样,一步步回归
先从1返回到上一步执行的函数,相当于1*0!,而0的阶乘又是1,所以相当于1*1
接下来又返回1,而此时a是2,相当于2*1的阶乘,以此类推我们可以得到
5的阶乘为120,这就是函数的递归。
2.4>>个人感觉
函数的递归在C语言中并不是很常用,主要还是使用迭代,也就是循环,当然递归我也感觉很神奇,很多题目我都想尝试使用递归去做,但我现在能力还不够,也可能是递归只有在一些特定场景下才能使用,才能发挥它的无穷力量!
3>>操作符的深入
操作符这边会讲到按位与&,按位或|,按位异或^,还有按位取反~的用法。
3.1>>补充:进制转换
首先我们需要知道十进制如何转换为二进制的,十进制整数转换为二进制整数采用"除2取余,逆序排列"法。具体做法是:用2整除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数。如此进行,直到商为小于1时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。如13,我们除2得到6余1,6除2得到3余0,3除2得到1余1,最后余1,然后将余数逆序排列得到1101这就是13的二进制数。
要进行转换也很简单二进制数1111每个代表的分别是8421,每往左边一个1就乘2,若10000这个1就代表16。而1101就是对应十进制数相加,就是8+4+1=13.
3.2>>补充:原码、反码、补码的概念
知道了进制转换现在我们就可以知道13的原码(这边注意正数原码反码补码三者相同,负数反码按位取反但是符号位不变(取反的意思就是0为1,1为0),补码则为反码+1)13的原码为:0000 0000 0000 0000 0000 0000 0000 1101,这里要32位二进制数,代表整形四个字节,那么再举一个例子(这里注意正负数的二进制位第一位为符号位,1为负数,0为正数)
-1的原码为:1000 0000 0000 0000 0000 0000 0000 0001
-1的反码为:0111 1111 1111 1111 1111 1111 1111 1110
-1的补码为:1111 1111 1111 1111 1111 1111 1111 1111
到这里,大家对原码反码补码的概念应该清楚一点了。接下来讲解操作符。
3.3>>按位与&,按位或|,按位异或^,按位取反~
按位与&的用法就是两1为1,其余情况为0,如101 & 111 结果就是 101,可以理解为:多选题,全选对了则是对。
按位或|的用法就是有一个1就是1,两0才为0,如100 | 001 结果就是101,可以理解为:我现在是个渣男/渣女,需要买一个金戒指,不管备胎一号出钱还是备胎二号出钱,只要有一个出钱我都能买到,哈哈哈这就是按位或。
按位异或^的用法就是相同则0,不同则1,如111 ^ 001 结果就是110,可以理解为:抄作业,你抄我的我两答案都一样,OMG的雷同卷,判0分,我们一起g了,所以相同为0,不同为1。
按位取反比较简单,~111 结果就是000。
3.4>>巩固知识
理清了它们的概念我们就来做一下题目巩固一下知识:输入一个数,计算该数转换为二进制后有多少个1。
#include<stdio.h>
//输入一个数,计算该数转换为二进制后有多少个1
int main()
{
int a=0;
int count=0;
scanf("%d",&a);
while(a)
{
a=a & (a-1);
count++;
}
printf("%d\n",count);
return 0;
}
这里来解析一下代码(注意运算都是用该数的补码运算):假设我们的a是13它的原码反码补码相同为0000 0000 0000 0000 0000 0000 0000 1101,a-1为0000 0000 0000 0000 0000 0000 0000 1100,此处省略前面的0,来对比1101和1100,这两个逻辑与结果就是1100,在循环,1100和1100-1即1011逻辑与又得到1000,这样每次逻辑与完都去掉最右边的一个1,简直妙哉,最终a为0退出循环,打印结果。
这时就有人说了,例子都是正数,能不能来个负数,好的安排!
这里可以看到结果为32个1,为什么呢?不急我们先来看看-1的原码反码补码:
-1的原码为:1000 0000 0000 0000 0000 0000 0000 0001
-1的反码为:0111 1111 1111 1111 1111 1111 1111 1110
-1的补码为:1111 1111 1111 1111 1111 1111 1111 1111
注意:补码取反加一也能得到原码
使用补码进行计算,-1的结果为:1111 1111 1111 1111 1111 1111 1111 1110逻辑与完就是0111 1111 1111 1111 1111 1111 1111 1111,以此类推我们能得到32次运算,是不是很神奇!
4>>结语
今天带来的是递归和操作符部分的深入讲解,函数递归在未来学算法估计会经常用到,原码反码补码对于未来学单片机和嵌入式的同学也很有帮助,另外:把自己所学的知识分享给大家,可以说是非常的舒服,感觉心灵受到了浇灌。小编要学习的地方还有很多,请大家多多指教,谢谢大家!