C语⾔简单函数递归介绍和题⽬应⽤
简单函数递归
递归的两个必要条件
存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。
每次递归调⽤后越来越接近这个条件
编写⼀个函数,要求不创建变量,计算字符串的长度
在上⼀篇 实现strcpy和strlen函数 对此题已有详细介绍。
求n的阶乘
对于n的阶乘, 当N<=1,N的阶乘是1,当N>2时,!n=n*fac( n-1)(其中fac为阶乘函数)
int fac(n)
{
if(n<=1)
return1;
if(n>1)
return n*fac(n-1);
}
这个函数中的限制条件,n<=1,
n-1使得每次递归后越来与接近这个条件,让函数进⼊最内部,也就时当n n<=1
求第n个斐波那契数
当n<=2时,值为1,n>2时fib=(n-1)+(n-2)
int fib(n)
{
if(n<=2)
{
return0;
}
else
return fib(n-1)+fib(n-2)
这个函数中的限制条件,n<=2,
n-1和n-2每次递归后越来与接近这个条件,让函数进⼊最内部,然后逐层返回。
但是该递归函数出现⼤量的重复,传⼊的n越⼤,计算的重率程度呈指数级增长。所以使⽤循环的⽅法可以极⼤的提⾼效率
int fib(int n)
{
int a = 1, b = 1;
int c = 1;//当n⼩于2时直接返回1
while (n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int a = 0;
printf("%u", fib(a));
getchar();
system("pause");
return0;
在这⾥通过定义三个变量,将c的值存储要求的斐波那契数,然后利⽤a和b更新来分别进⾏每次求下⼀个斐波那契数的求值。以%u的形式输出为了是数字正确,避免最⾼位是1是成为负数。
编写⼀个函数实现n^k,使⽤递归实现
int func(int n, int k)
{
c语言搜题软件推荐if (k <= 1)//限定递归终⽌条件
{
return n; //返回n开始逐层返回
}
return n*func(n, k - 1);
}
int main()
{
int n = 5;
int k = 4
;
printf("%u", func(n,k));
system("pause");
return 0;
//编写⼀个函数实现n^k,使⽤递归实现
}
写⼀个递归函数DigitSum(n),输⼊⼀个⾮负整数,返回组成它的数字之和,例如,调⽤DigitSum(1729),则应该返回1+7+2+9,它的和是19
int DigitSum(unsigned int n)
{
if (n <= 9)
{
return n; //在n之只有⼀位的时候直接返回
}
return n % 10 + DigitSum(n / 10);//表⽰将每次的取模相加
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d", DigitSum(num));
system("pause");
return0;
}
同理,对函数进⾏稍微更改,实现打印函数的每⼀位。
void Digitprint(unsigned int n)
{
if (n <= 9)
{
printf("%d ", n);
}
else
{
DigitSum(n / 10);
printf("%d ", n % 10);
}
}
int main()
{
int num = 1234;
Digitprint(num);
system("pause");
return0;
}
1. 编写⼀个函数reverse_string(char * string)(递归实现)
实现:将参数字符串中的字符反向排列。
要求:不能使⽤C函数库中的字符串操作函数,若要实现strlen函数,只能⽤⼀⾏代码实现。不能在函数中创建静态变量思路
看到逆转字符串的题⽬,想到的是
求出字符串的长度,通过指针加法到⾸部对应的末尾字符进⾏交换,然后对称虽⼩范围,直到两个指针相等或者越界。
但是题⽬要求不能使⽤库函数,且函数规定的参数只有⼀个。所以我们可以⽤递归实现my_strlen函数,题⽬要求只能⽤⼀⾏代码,⼜要⽤到assert断⾔函数,如何实现?
使⽤逗号操作符将assert函数添加
使⽤三⽬操作符省略if判断语句
使⽤递归将长度累加
实现strlen函数后,对于reverse函数⽽⾔,要想将逆序实现,似乎必须要创建⼀个变量来对每次的⾸元素相加来得到末尾元素。但是函数中的元素创建是局部变量,每次调⽤都需要重新初始化,如何在不⽤static修饰的情况下进⾏每次的末尾元素寻?
以第⼀次交换为例: 此时值在交换时,我们定义char 类型的变量tmp 来进⾏对⾸元素的保存,然对末尾元素赋值\0☞调⽤reverse函数后,再将存储的tmp赋值给末尾元素。
输出结果
int my_strlen(const char * str )
{
return (((assert (str )),(*str ? (1 + my_strlen(str + 1) ):0)));}
void reverse_string(char * string)
{
assert(string);
if (*string!='\0')
{
char *end= string + (my_strlen(string) - 1);//将末尾⾮零元素存放⾄指针end
char tmp = *string;//开始交换
*string =*end ; //将末尾的⾮\0元素赋值给tmp
*end = '\0';//此时将该处置'\0',便于第⼀阶段递归计算末尾元素
reverse_string(string + 1);
*end = tmp;//此时开始返回,将保存对应交换元素的tmp 赋给它。
}
}
int main()
{
char arr[] = "abcdefghi";
printf("%d\n",my_strlen(arr));
reverse_string(arr);
printf("%s", arr);
system("pause");
return 0;
}
对于刚接触到递归的盆友,都想要对递归过程进⾏全程跟踪,对于简单的递归函数等接触时,最好在纸上画出函数调⽤和返回的流程图,便于理解和记忆,从递归终⽌条件的情况和递归的限制条件⼊⼿。这⾥⼀篇针对于汉诺塔的趣⽂分享。
对递归的理解的要点主要在于放弃!放弃你对于理解和跟踪递归全程的企图,只理解递归两层之间的交接,以及递归终结的条件。想象你来到某个热带丛林,意外发现了⼗层之⾼的汉诺塔。正当你苦苦思索如何搬动它时,林中出来⼀个⼟著,⽑遂⾃荐要帮你搬塔。他名叫⼆傻,戴着⼀个草帽,草帽上有⼀个2字,号称会把⼀到⼆号盘搬到任意柱。你灵机⼀动,问道:“你该不会有个兄弟叫三傻吧?”“对对,⽼爷你咋知道的?他会搬⼀到三号盘。“”那你去把他叫来,我不需要你了。“于是三傻来了,他也带着个草帽,上⾯有个3字。你说:”三傻,你帮我把头三个盘⼦移到c柱吧。“三傻沉吟了⼀会,⾛进
树林,你听见他⼤叫:”⼆傻,出来帮我把头两个盘⼦搬到C!“由于天⽓炎热你开始打瞌睡。朦胧中你没看见⼆傻是怎么⼯作的,⼆傻⼲完以后,⾛⼊林中⼤叫⼀声:“⽼三,我⼲完了!”三傻出来,把三号盘从A搬到B,然后⼜去叫⼆傻:“⽼⼆,帮我把头两个盘⼦搬回A!”余下的我就不多说了,总之三傻其实只搬三号盘,其他叫⼆傻出来⼲。最后⼀步是三傻把三号盘搬到C,然后呼叫⼆傻来把头两个盘⼦搬回C事情完了之后你把三傻叫来,对他说:“其实你不知道怎么具体⼀步⼀步把三个盘⼦搬到C,是吧?”三傻不解地说:“我不是把任务⼲完了?”你说:“可你其实叫你兄弟⼆傻⼲了⼤部分⼯作呀?”三傻说:“我外包给他和你屁相⼲?”你问到:“⼆傻是不是也外包给了谁?“三傻笑了:“这跟我有屁相⼲?”你苦苦思索了⼀夜,第⼆天,你⾛⼊林中⼤叫:“⼗傻,你在哪?”⼀个头上带着10号草帽的⼈,⼗傻,应声⽽出:“⽼爷,你有什么事?”“我要你帮把1到10号盘⼦搬到C柱““好的,⽼爷。“⼗傻转⾝就向林内⾛。“慢着,你该不是回去叫你兄弟九傻吧““⽼爷你怎么知道的?““所以你使唤他把头九个盘⼦搬过来搬过去,你只要搬⼏次⼗号盘就好了,对吗?““对呀!““你知不知道他是怎么⼲的?““这和我有屁相⼲?“你叹了⼀⼝⽓,决定放弃。⼗傻开始⼲活。树林⾥充满了此起彼伏的叫声:“九傻,来⼀下!“ “⽼⼋,到你了!““五傻!。。。“”三傻!。。。“”⼤傻!“你注意到⼤傻从不叫⼈,但是⼤傻的⼯作也最简单,他只是把⼀号盘搬来搬去。若⼲年后,⼯作结束了。⼗傻来到你⾯前。你问⼗傻:“是谁教给你们这么⼲活的?“⼗傻说:“我爸爸。他给我留了这张纸条。”他从⼝袋⾥掏出⼀张⼩纸条,上⾯写着:“照你帽⼦的号码搬盘⼦到⽬标柱。如果有盘⼦压住你,叫你上⾯⼀位哥哥把他搬⾛。如果有盘⼦占住你要去的柱⼦,叫你哥哥把它搬到不碍事的地⽅。等你的盘⼦搬到了⽬标,叫你哥哥把该压在你
上⾯的盘⼦搬回到你上头。“你不解地问:“那⼤傻没有哥哥怎么办?“⼗傻笑了:“他只管⼀号盘,所以永远不会碰到那两个‘如果’,也没有盘⼦该压在⼀号上啊。”但这时他忽然变了颜⾊,好像泄漏了巨⼤的机密。他惊慌地看了你⼀眼,飞快地逃⼊树林。第⼆天,你到树林⾥去搜寻这⼗兄弟。他们已经不知去向。你到了⼀个⼩屋,只容⼀个⼈居住,但是屋⾥有⼗顶草帽,写着⼀到⼗号的号码。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论