-
函数递归
递归的两个条件:
1 将问题转化为其子问题,子问题要与原问题具有相同的解法。限制条件即递归的出口,如果限制条件满足,递归程序就可以退出了
2.递归的出口例如 求n个斐波那契数
int fib(int n)
{
if (n<=2)
{
return 1;
}
else
return fib(n-1)+fib(n-2);
}
int main()
{
int n = 1;
scanf_s("%d", &n);
int result=fib(n);
printf("%d\n", result);
system("pause");
return 0;
}
非递归的方法
int fib(int n)
{
int first = 1;
int second = 1;
int third = 1;
while (n > 2)
{
third = first + second;
first = second;
second = third;
n--;
}
return third;
}
int main()
{
int n = 1;
scanf_s("%d", &n);
int result = fib(n);
printf("%d\n", result);
system("pause");
return 0;
}
- 函数调用
传参时不论是按照值还是指针方式传递,形参拿到的都是实参的一份拷贝。
形参是在函数调用的时候才实例化,才开辟内存空间
如果是按照值的方式传递,形参和实参各自有各自的空间,改变形参不能改变外部的实参
函数调用如果采用传值调用,改变形参不影响实参,因为形参和实参是两个不同的变量
在C语言中,函数的形参一般都是通过参数压栈的方式传递的 - 函数声明和定义
函数必须保证先声明后使用
函数的定义可以放在任意位置,函数的声明必须放在函数的使用之前
函数的声明只是告诉编译器函数返回值类型、函数名字以及函数所需要的参数,函数定义才是说明函数是怎么实现的
练习
1.递归方式实现打印一个整数的每一位
思路//1234->调用123->调用12->调用1
// | | | |
//(1 2 3 4) (1 2 3) (1 2) (1)
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int num = 1234;
print(num);
system("pause");
return 0;
}
2.递归和非递归分别实现求n的阶乘(不考虑溢出的问题)
//递归
int factorial(int n)
{
if (n <= 1)
{
return 1;
}
return n*factorial(n-1);
}
int main()
{
int n = 5;
int result = factorial(n);
printf("%d\n", result);
system("pause");
return 0;
}
非递归
int factorial(int n)
{
int result = 1;
while (n>1)
{
result = result*n;
n--;
}
return result;
}
int main()
{
int n = 5;
int res = factorial(n);
printf("%d\n", res);
system("pause");
return 0;
}
3.strlen的模拟(递归实现) 递归和非递归分别实现strlen
非递归的方法
int my_strlen(char* str)
{
int count = 0;
while ('\0' != *str)
{
count++;
str++;
}
return count;
}
int main()
{
char *str = "abcde";
int result = my_strlen(str);
printf("%d\n", result);
system("pause");
return 0;
}
让我们来看看递归做法
int my_strlen(char* str)
{
if ('\0' == *str)
return 0;
else
return 1 + my_strlen(str + 1);
}
int main()
{
char *str = "abcde";
int result = my_strlen(str);
printf("%d\n", result);
system("pause");
return 0;
}
4.字符串逆序(递归实现) 编写一个函数 reverse_string(char * string)(递归实现)
实现:将参数字符串中的字符反向排列。要求:不能使用C函数库中的字符串操作函数
思路 非递归 1.给两个指针,left放在字符串左侧,right放在最后一个有效字符位置
2. 交换两个指针位置上的字符
3. left指针往后走,right指针往前走,只要两个指针没有相遇,继续2,两个指针相遇后,逆置结束
char reverse_string(char string[])
{
char *left = string;
char *right = string+strlen(string)-1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
return *string;
}
int main()
{
char string[] = "abcdef";
printf("%s\n", string);
reverse_string(string);
printf("%s\n", string);
system("pause");
return 0;
}
再看看递归做法有何不同
void reverse_string(char arr[]) {
int len = strlen(arr); //计算字符串string的长度
char tmp = *arr;//定义一个变量,把字符串第一个元素赋值给变量
*arr = *(arr + len - 1);//把字符串最后一个元素内容赋值给第一个元素
*(arr + len - 1) = '\0';//再把字符串最后一个元素变为'\0'
if (strlen(arr + 1) > 1) {
reverse_string(arr + 1);
}
*(arr + len - 1) = tmp;//f返回时 把每一趟tmp存的值赋给字符串最后一个元素
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s\n", arr);
system("pause");
return 0;
}
5.计算一个数的每位之和(递归实现) 写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19输入:1729,输出:19
思路//1729->dig(172)->dig(17)->dig(1)=1 返回1+7+2+9
// +9 +2 +7
int DigitSum(int num)
{
if (num / 10 == 0)
{
return num;
}
return num % 10 + DigitSum(num / 10);
}
int main()
{
int num = 1;
scanf_s("%d", &num);
int result = DigitSum(num);
printf("%d", result);
system("pause");
return 0;
}
6.编写一个函数实现n的k次方,使用递归实现
//递归 5!->5*4!->4*3!->3*2!->2*1!
int factorial(int n)
{
if (n <= 1)
{
return 1;
}
return n*factorial(n-1);
}
int main()
{
int n = 5;
int result = factorial(n);
printf("%d\n", result);
system("pause");
return 0;
}
再来看一看非递归是怎么实现的
//非递归
int factorial(int n)
{
int result = 1;
while (n>1)
{
result = result*n;
n--;
}
return result;
}
int main()
{
int n = 5;
int res = factorial(n);
printf("%d\n", res);
system("pause");
return 0;
}
7.递归和非递归分别实现求第n个斐波那契数 见例子