C语言学习记录—函数

本章分为:函数的分类、函数的参数、函数的调用、嵌套调用和链式访问、函数的声明和定义、函数递归。

第一节:函数的分类

库函数:老师推荐的库函数学习工具是MSDN。使用库函数必须包含#include对应的头文件。

自定义函数:返回类型+函数名+函数参数

第二节:函数的参数

实参:传递给函数的参数。可以是常量、变量、表达式、函数等。

形参:形参只有在函数被调用时才实例化,并且只在函数内部有效。形参是实参的一份临时拷贝。

第三节:函数的调用

传值调用:因为函数的形参和实参分别占有不同的内存空间,所以修改形参不能影响实参。

传址调用:这种调用方式是将变量的地址传给函数,因此函数修改了变量后会影响实参。

练习

1. 写一个函数可以判断100~200之间的数是不是素数。

两种方法:
第一种:用2~n-1的数去试除,如果这些数有能整除说明不是素数;反之,是素数。
第二种:假设m不是素数,那么它可以写成m=a*b,(a b不能是1或它本身) 并且a或b中一定有一个数小于m的平方根(<= sqrt(m)) 所以被除数j最大只需要到i的平方根。并且在此基础上可以继续优化。除了2以外,所有偶数都不是素数,遍历的时候从101开始,每次+2
#include <math.h>
int is_prime(int n)
{
	int i = 0;//除数
	for (i = 2; i <= sqrt(n); i++)
	{
		if (n % i == 0)
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	int n = 0;//100-200之间的数
	for (n = 101; n < 200; n+=2)
	{
		if (is_prime(n) == 1)
			printf("%d ", n);
	}
	return 0;
}

2. 写一个函数判断一年是不是闰年。

闰年判断规则:
1.能被4整除,且不能被100整除。2.能被400整除。
if的条件就是1或2。
int is_leap_year(int year)
{
	if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
		return 1;
	else
		return 0;
}
int main()
{
	int year = 0;
	for (year = 1000; year <= 2000; year++)
	{
		if (is_leap_year(year) == 1)
			printf("%d ", year);
	}
	return 0;
}

3. 写一个函数,实现一个整形有序数组的二分查找。

实现方法在上一章。如果用函数实现,一定要注意不能再函数内部求数组大小,因为数组名传参,传的是数组的地址。需要将数组元素个数作为参数传过去。
int binary_search(int arr[], int k, int sz)
{
	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = left + (right - left) / 2;//此方法求平均值不会越界
		if (arr[mid] < k)//如果中间元素比要找的元素小,说明范围在右边
			left = mid + 1;//此时左下标left要变成mid+1
		else if (arr[mid] > k)//如果中间元素比要找的元素大,说明范围在左边边
			right = mid - 1;//此时右下标right要变成mid-1
		else
			return mid;
	}
	return -1;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	int ret = binary_search(arr, k, sz);
	if (ret == -1)
		printf("找不到\n");
	else
		printf("找到了,下标是:%d\n", ret);

	return 0;
}

4. 写一个函数,每调用一次这个函数,就会将 num 的值增加1

两种方法:
1. 传址调用:将变量的地址传过去,用指针变量接收,通过解引用操作符让指针指向的值++
2. 传值调用:函数返回n+1即可。注意不可以像指针方法那样使用++,因为这会先返回后++,导致没有增加。
//传址调用
void Add(int* p)
{
	(*p)++;
}
int main()
{
	int num = 0;
	Add(&num);
	printf("%d\n", num);
	Add(&num);
	printf("%d\n", num);
	return 0;
}

//传值调用
int Add2(int n)
{
	return ++n;
}
int main()
{
	int num = 0;
	num = Add2(num);
	printf("%d\n", num);
	num = Add2(num);
	printf("%d\n", num);
	return 0;
}

第四节:嵌套调用和链式访问

嵌套调用:A函数调用B函数,B函数调用C函数;函数之前可以根据需求相互调用。但不能嵌套定义。
链式访问:把一个函数的返回值作为另外一个函数的参数。
#include <stdio.h>
int main()
{
    printf("%d", printf("%d", printf("%d", 43)));
    return 0;
}

第五节:函数的声明和定义

函数的声明:

  • 声明就告诉编译器有一个什么样的函数(名字、参数、返回类型)。但是否存在声明决定不了。
  • 声明要在函数使用之前,先声明后使用。
  • 声明一般要放在头文件中

函数的定义:就是函数功能的具体实现。

第六节:函数递归

函数递归其实分两个动作,先完成所有的递,再全部归。并且是最后一次调用的自己是第一次返回,也就是深度优先。

void print(unsigned int n)
{
	//如果这里没有if这个限制条件,这个递归会无限调用形成栈溢出
	//内存中的栈区存放着局部变量、函数的形参。函数的每一次调用也会在栈区申请空间
	if (n > 9)			//1234	123	 12  1	
	{
		print(n / 10);	//123	12	 1	
	}
	printf("%d ", n % 10);
}

练习1:接受一个整型值(无符号),按照顺序打印它的每一位。

递归分 递和归,先执行完递延,最后一起回归。
1.n = 1234,大于9,继续递归,n变为1234 / 10 = 123。
2.n = 123,大于9,继续递归,n变为123 / 10 = 12。
3.n = 12,大于9,继续递归,n变为12 / 10 = 1。
4.n = 1,不大于9,结束递归,打印n % 10,即打印1。
5.回溯到n = 12,打印12 % 10,即打印2。
6.回溯到n = 123,打印123 % 10,即打印3。
7.回溯到n = 1234,打印1234 % 10,即打印4。
所以,最后打印的结果是1 2 3 4。

一开始学习递归函数时,总是搞不清调用自己以后函数执行到哪了,并且返回的时候也比较迷,通过画图的形式才一步一步搞清楚递归的整个过程。

练习2:编写函数不允许创建临时变量,求字符串的长度

思路:使用递归方式的核心就是拆解问题,将规模减小,直到最简单的情况。这题可以把问题看成查看第一个字符是否是\0,如果不是就+1,并向后移动一位。

去查看第一个字符是不是\0,如果不是下一步。具体如下:

my_strlen("abc")

1+my_strlen("bc")

1+1+my_strlen("c")

1+1+1+my_strlen("")

1+1+1+0

int my_strlen(char* str)
{
	if (*str != 0)
		return 1 + my_strlen(str + 1);//这里不能使用str++,因为先使用后++,每次都把相同的地址传到下一次
	else
		return 0;
}

作业

1. 以下关于函数设计不正确的说法是:( )

A.函数设计应该追求高内聚低耦合
B.要尽可能多的使用全局变量
C.函数参数不易过多
D.设计函数时,尽量做到谁申请的资源就由谁来释放
答案:B
 

2. 以下叙述中不正确的是:( )

A.在不同的函数中可以使用相同名字的变量
B.函数中的形式参数是在栈中保存
C.在一个函数内定义的变量只在本函数范围内有效
D.在一个函数内复合语句中定义的变量在本函数范围内有效(复合语句指函数中的成对括号构成的代码)
答案:D
 

3. 关于C语言函数描述正确的是:( )

A.函数必须有参数和返回值
B.函数的实参只能是变量
C.库函数的使用必须要包含对应的头文件
D.有了库函数就不需要自定函数了
答案:C
 

4. C语言规定,在一个源程序中,main函数的位置( )

A.必须在最开始
B.必须在库函数的后面
C.可以任意
D.必须在最后
答案:C
 

5. 关于实参和形参描述错误的是:( )

A.形参是实参的一份临时拷贝
B.形参是在函数调用的时候才实例化,才开辟内存空间
C.改变形参就是改变实参
D.函数调用如果采用传值调用,改变形参不影响实参
答案:C
 

6. 函数调用exec((vl,v2),(v3,v4),v5,v6); 中,实参的个数是:( )

A.3
B.4
C.5
D.6
答案:B
 

7. 关于函数的声明和定义说法正确的是:( )

A.函数的定义必须放在函数的使用之前
B.函数必须保证先声明后使用
C.函数定义在使用之后,也可以不声明
D.函数的声明就是说明函数是怎么实现的
答案:B

8. 在函数调用时,以下说法正确的是:(    )

A.函数调用后必须带回返回值
B.实际参数和形式参数可以同名
C.函数间的数据传递不可以使用全局变量
D.主调函数和被调函数总是在同一个文件里
答案:B
 

9. 关于函数调用说法不正确的是:(     )

A.函数可以传值调用,传值调用的时候形参是实参的一份临时拷贝
B.函数可以传址调用,传址调用的时候,可以通过形参操作实参
C.函数可以嵌套定义,但是不能嵌套调用
D.函数可以嵌套调用,但是不能嵌套定义
答案:C
 

10. 函数判断素数

实现一个函数is_prime,判断一个数是不是素数。
利用上面实现的is_prime函数,打印100到200之间的素数。
 

#include <math.h>
int is_prime(int n)
{
	int i = 0;//除数
	for (i = 2; i <= sqrt(n); i++)
	{
		if (n % i == 0)
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	int n = 0;//100-200之间的数
	int count = 0;
	for (n = 101; n < 200; n+=2)
	{
		if (is_prime(n) == 1)
		{
			printf("%d ", n);
			count++;
		}
	}
	printf("\n%d\n", count);
	return 0;
}

11. 函数判断闰年

int is_leap_year(int year)
{
	if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
		return 1;
	else
		return 0;
}
int main()
{
	int year = 0;
	for (year = 1000; year <= 2000; year++)
	{
		if (is_leap_year(year) == 1)
			printf("%d ", year);
	}
	return 0;
}

12. 写一个函数,实现一个整形有序数组的二分查找。

int binary_search(int arr[], int k, int sz)
{
	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = left + (right - left) / 2;//此方法求平均值不会越界
		if (arr[mid] < k)//如果中间元素比要找的元素小,说明范围在右边
			left = mid + 1;//此时左下标left要变成mid+1
		else if (arr[mid] > k)//如果中间元素比要找的元素大,说明范围在左边边
			right = mid - 1;//此时右下标right要变成mid-1
		else
			return mid;
	}
	return -1;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	int ret = binary_search(arr, k, sz);
	if (ret == -1)
		printf("找不到\n");
	else
		printf("找到了,下标是:%d\n", ret);

	return 0;
}

13. 写一个函数,每调用一次这个函数,就会将 num 的值增加1。

//传址调用
void Add1(int* p)
{
	(*p)++;
}
int main()
{
	int num = 0;
	Add1(&num);
	printf("%d\n", num);
	Add1(&num);
	printf("%d\n", num);
	return 0;
}

//传值调用
int Add2(int n)
{
	return ++n;
}
int main()
{
	int num = 0;
	num = Add2(num);
	printf("%d\n", num);
	num = Add2(num);
	printf("%d\n", num);
	return 0;
}

14. 函数交换两个整数

void Swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d b=%d\n", a, b);
	Swap(&a, &b);
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

15. 乘法口诀表

实现一个函数,打印乘法口诀表,口诀表的行数和列数自己指定
如:输入9,输出9 * 9口诀表,输出12,输出12 * 12的乘法口诀表。
 

void multi_table(int n)
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= i; j++)
		{
			printf("%-2d*%2d = %-2d  ", i, j, i * j);
		}
		printf("\n");
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	multi_table(n);
	return 0;
}

16. 能把函数处理结果的2个数据返回给主调函数,在下面的方法中不正确的是:(   )

A.return 这2个数
B.形参用数组
C.形参用2个指针
D.用2个全局变量
答案:A
 

17. 根据下面递归函数:调用函数Fun(2),返回值是多少(       )

int Fun(int n)
{
    if (n == 5)
        return 2;
    else
        return 2 * Fun(n + 1);
}
//A.2
//B.4
//C.8
//D.16
//答案:D

18. 关于递归的描述错误的是:(        )

A.存在限制条件,当满足这个限制条件的时候,递归便不再继续
B.每次递归调用之后越来越接近这个限制条件
C.递归可以无限递归下去
D.递归层次太深,会出现栈溢出现象
答案:C
 

19. 打印一个数的每一位

递归方式实现打印一个整数的每一位

void print(int n)
{
	if (n > 9)
		print(n / 10);
	printf("%d ", n % 10);
}
int main()
{
	int n = 1234;
	print(n);
	return 0;
}

20. 求阶乘

递归和非递归分别实现求n的阶乘(不考虑溢出的问题)

递归版本

思路:用递归求阶乘首先找到最简单的情况,即求1的阶乘。1的阶乘就是1。2的阶乘是用2乘以1的阶乘。那么n的阶乘就是n*(n-1)的阶乘

非递归版本

思路:非递归版本求阶乘也是用当前的数乘以上一个数的阶乘。在程序实现上需要考虑1的阶乘情况。这里创建一个阶乘的变量,并初始化为1,这样1*1还是等于1。这样就得到了1的阶乘,并保存起来。利用for循环让数字每次+1,这样每次都是乘以上一个数的阶乘。

//非递归
int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret *= i;
	}
	printf("%d\n", ret);
	return 0;
}

//递归
int fac(int n)
{
	if (n == 1)
		return 1;
	else
		return n * fac(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d\n", fac(n));
	return 0;
}

21. strlen的模拟(递归实现)

递归和非递归分别实现strlen

非递归版本

思路:将字符数组的地址传过去,用指针变量接收。利用循环判断当前位置是否是\0,如果不是那么计数变量+1,并且让指针向后移动一位。直到遇到\0。

递归版本

思路:同样将字符数组传过去,用指针变量接收,判断当前位置是否为\0。如果不是那么返回1,并且继续递归。同时,让指针+1也就是让指针让后移动一位。

//非递归
#include <assert.h>
size_t my_strlen1(const char* str)
{
	assert(str);
	size_t count = 0;
	while (*str!='\0')
	{
		str++;
		count++;
	}
	return count;
}

//递归
size_t my_strlen2(const char* str)
{
	assert(str);
	if (*str != '\0')
		return 1 + my_strlen2(str + 1);
	else
		return 0;
}
int main()
{
	char arr[] = "abcdef";
	size_t ret1 = my_strlen1(arr);
	printf("%zu\n", ret1);

	size_t ret2 = my_strlen2(arr);
	printf("%zu\n", ret2);

	return 0;
}

22. 字符串逆序(递归实现)

编写一个函数 reverse_string(char* string)(递归实现)
实现:将参数字符串中的字符反向排列,不是逆序打印。
要求:不能使用C函数库中的字符串操作函数。
比如 :
char arr[] = "abcdef";
逆序之后数组的内容变成:fedcba

非递归版本
//循环非指针版本
//思路:逆置字符串,循环的方式实现非常简单
//确定左边下标(第一个元素)和右边下标(最后一个元素)。
//交换两个元素,每次左下标+1,有下标-1,直到左右下标相等说明只有一个元素,此时不需要再交换。
#include <string.h>
void reverse_string(char arr[])
{
	int sz = strlen(arr);
	int left = 0;
	int right = sz - 1;

	while (left < right)
	{
		char tmp = arr[left];
		arr[left] = arr[right];
		arr[right] = tmp;
		left++;
		right--;
	}
}

//循环指针版本
//1. 给两个指针,left放在字符串左侧,right放在最后一个有效字符位置
//2. 交换两个指针位置上的字符
//3. left指针往后走,right指针往前走,只要两个指针没有相遇,继续2,两个指针相遇后,逆置结束
void reverse_string(char* arr)
{
	char* left = arr;
	char* right = arr + strlen(arr) - 1;
	while (left <= right)
	{
		char tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}

int main()
{
	char arr[] = "abcdef";
	
	reverse_string(arr);
	printf("%s\n", arr);

	return 0;
}

递归版本

思路:交换第一个和最后一个,再交换第二个和倒数第二个,以此类推
只能逆序元素个数为奇数的数组

//递归版本(只能逆序元素个数为奇数的数组)
void reverse_string(char arr[], int left, int right)
{
	char tmp = arr[left];
	arr[left] = arr[right];
	arr[right] = tmp;

	//如果if条件在这个位置,遇到元素个数为偶数的的数组会有以下情况
	//当逆序到最后两个字符时,虽然字符被交换了,但下标还未 + 1,(调用自己时才 + 1)
	//所以此时的左下边仍然小于右下标,所以又再次调用自己,导致已经被正确交换的两个字符又被交换了。
	//下面函数为正确版本,即使交换也要左下标小于右下标。
	if (left < right)
		reverse_string(arr, left + 1, right - 1);
}

//递归版本(正确版本)
void reverse_string(char arr[], int left, int right)
{
	if (left < right)
	{
		char tmp = arr[left];
		arr[left] = arr[right];
		arr[right] = tmp;
		reverse_string(arr, left + 1, right - 1);
	}
}

int main()
{
	char arr[] = "abcdef";
	int left = 0;
	int right = strlen(arr) - 1;

	reverse_string(arr, left, right);
	printf("%s\n", arr);
	return 0;
}


23. 计算一个数的每位之和(递归实现)

写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
例如,调用DigitSum(1729),则应该返回1 + 7 + 2 + 9,它的和是19
输入:1729,输出:19
思路:这题和顺序打印每一位类似。首先要拆分每一位,在获取每一位之后再相加。

//DigitSum(1234)
//DigitSum(123)+4		等效于DigitSum(1234/10)+ 1234%10
//DigitSum(12)+3+4
//DigitSum(1)+2+3+4

//自己的版本
int DigitSum(int n)
{
	int sum = 0;
	if (n > 9)
		sum += DigitSum(n / 10);
	return sum += n % 10;
}

//GPT版本
int DigitSum(int n)
{
	if (n == 0)
		return 0;
	return n % 10 + DigitSum(n / 10);
}

//老师版本
int DigitSum(unsigned int n)
{
	if (n > 9)
		return DigitSum(n / 10) + n % 10;
	else
		return n;
}

int main()
{
	int n = 1234;
	int ret = DigitSum(n);
	printf("%d\n", ret);
	return 0;
}

24. 递归实现n的k次方

编写一个函数实现n的k次方,使用递归实现。

思路:从指数入手,分3种情况:

k=0,无论n是几,都等于1(此为最简单的情况)
k>0,例如3^3可以理解为3*3^2(即n*n^k-1)
k<0,其实就是k>0时再取倒数

//Pow(n, k) -> n*Pow(n, k-1)
//k=0, 1
//k>0, Pow(n, k)->n* Pow(n, k - 1)
//k<0, 1/(Pow(n, -k))
//n的k次方可以看作,n乘以n的k-1次方,直到k=0
double Pow(int n, int k)
{
	if (k == 0)
		return 1;
	else if (k > 0)
		return n * Pow(n, k - 1);
	else
		//如果k是负数则进入下面代码,假设k是-2,那么-k=-(-2),结果就是2
		//然后进去k>0的部分,最后才返回到 1.0 / Pow(n, -k);
		return 1.0 / Pow(n, -k);
}
int main()
{
	int n = 0;
	int k = 0;
	scanf("%d%d", &n, &k);
	double ret = Pow(n, k);
	printf("%lf\n", ret);
	return 0;
}

25. 计算斐波那契数

递归和非递归分别实现求第n个斐波那契数
例如:
输入:5  输出:5
输入:10, 输出:55
输入:2, 输出:1
1,1,2,3,5,8,13,21,34,55,89
 

//非递归
//自己的方法
int fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 0;
	if (n <= 2)
		return 1;

	n--;
	while (--n)
	{
		c = a + b;
		a = b;
		b = c;
	}
	return c;
}

//老师方法
//思路:第1个数+第2个数=第3个数。第2个数+第3个数=第四个数。
//又因为最开始两个数都是1,所以创建3个变量分别是第1、2个数(初始化为1),和第3个数。
//每次加完之后,把第3个数的值赋给第2个数;第2个数的值赋给第1个数。
int fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 0;
	if (n <= 2)
		return 1;
	
	int i = 0;
	for ( i = 3; i <= n; i++)
	{
		c = a + b;
		a = b;
		b = c;
	}
	return c;
}

//递归版本
//根据上方非递归可以总结出,任何一个数都是往前移动1和2的两个数相加。即n=(n-1)+(n-2)
//最简单的情况是最开始的两个数,都是1。
int fib(n)
{
	if (n <= 2)
		return 1;
	else
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fib(n);
	printf("%d\n", ret);
	return 0;
}

26. 将数组A的内容和数组B的内容进行交换。(数组一样大)

int main()
{
	int arr1[] = { 1,3,5,7,9 };
	int arr2[] = { 2,4,6,8,0 };
	//不可以使用数组名进行交换,因为数组名是地址
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (i = 0; i < sz; i++)
	{
		int tmp = arr1[i];
		arr1[i] = arr2[i];
		arr2[i] = tmp;
	}
 
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
 
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	return 0;
}

27. 冒泡排序

思路:假设有10个数(n=10),那么每个数都要交换到指定位置需要9轮(n-1),因为9个数交换完,最后一个数也在指定位置了。
第一轮交换的次数是9次(n-1)。
每一轮交换的次数比上一次-1,增加几轮少几次。

void bubble(int* arr, int sz)
{
	int i = 0;//i是需要交换多少轮
	for (i = 0; i < sz - 1; i++)
	{
		//j是元素下标,从下标为0的元素(也就是第一个元素)开始逐一比较
		//第1轮:第1个元素需要交换 元素个数-1次,10-1=9
		//第2轮:第2个元素需要交换 元素个数-2次,10-2=8
		//....
		//第9轮:第9个元素需要交换 元素个数-9次,10-9=1
		//结束,总共交换 元素个数-1轮,10-1=9
		int j = 0;//元素下标
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
 
	bubble(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
 
	return 0;
}

28. 小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?

思路1:
假设n=10,fib(n)表示n个台阶的走法。
如果第一步走1个台阶,那么还剩9个台阶,剩余台阶走法是fib(9)
如果第一步走2个台阶,那么还剩8个台阶,剩余台阶走法是fib(8)

思路2:
假设台阶有5级
  n      跳法
  1        1
  2        2
  3        3
  4        5
  5        8
如果青蛙站在第1级台阶,那么剩下的4级台阶总共有5种跳法
如果青蛙站在第2级台阶,那么剩下的3级台阶总共有3种跳法
所以5级台阶的跳法:3级台阶的跳法+4级台阶跳法(3+5=8)
也就是当n<=2时,有几级台阶就只有几种跳法
当n>2时,跳法总共有:(n-1)+(n-2)
每次求n时,都是青蛙站在第1级,或第2级作为起点(动态规划:用上一步的结果,来计算下一步的结果)

int fib(int n)
{
	if (n <= 2)
		return n;
	else 
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
 
	int m = fib(n);
	printf("%d\n", m);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值