递归经典题目(汉诺塔问题,青蛙跳台阶问题)

        在写这两道题之前,我们再大致看看函数的一些比较重要的知识点

    函数的知识点

一.函数

1.函数的分类

        函数分为库函数和自定义函数。

        (1)库函数是c语言所提供的函数,再使用前需要引用头文件#include 。

         常用的库函数有:IO函数

                                      字符串操作函数

                                      字符操作函数

                                      内存操作函数

                                      时间/日期函数

                                      数学函数

                                      其他库函数

        (2)自定义函数是程序员所要实现的函数,这个是很重要的。

二.函数的参数

1.实际参数(实参)

        真实传给函数的参数,叫实参。
        实参可以是:常量、变量、表达式、函数等。
        无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

2.形式参数(形参)

        形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
我们可以认为: 形参实例化之后其实相当于实参的一份临时拷贝

三.函数的调用

1 传值调用

函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。

2 传址调用

传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。

四.链式访问

把一个函数的返回值作为另外一个函数的参数。
举个例子:
int main()
{
    printf("%d", printf("%d", printf("%d", 43)));
    return 0;
}

这个先打印最里面printf的43,然后第二个printf接收到的是前面有2个字符,因此打印2,最后第一个printf接收到的是前面有1个字符,因此打印1。最后结果为4321。

五.函数声明和定义

1 函数声明:

(1) 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数
声明决定不了。
(2) 函数的声明一般出现在函数的使用之前。要满足 先声明后使用
(3) 函数的声明一般要放在头文件中的。

2 函数定义:

函数的定义是指函数的具体实现,交待函数的功能实现。

六. 函数递归

1. 递归
递归是一个过程或函数在其定义或说明中有直接或间接 调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求 解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小

2. 递归的两个必要条件

存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。

        递归经典题目

1.汉诺塔

递归经典题目(汉诺塔问题,青蛙跳台阶问题)_第1张图片

 

n=1:A->C                                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        1

n=2:A->B A->C B->C                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​      3

n=3:A->C A->B C->B A->C B->A B->C A->C         7

n:                                                                             2^n-1

假设有三根柱子A,B,C,A柱上有n个盘子,要想把A最下面的盘子拿到C柱上,(1)需要把A上(n-1)个盘子借助C柱全部挪到B柱上,(2)然后将A柱最下面的盘子放到C柱,(3)最后再将B柱上的盘子借助A柱放到C柱上。

#include 

void move(char pos1, char pos2)//实现移动
{
	printf("%c->%c ", pos1, pos2);//会接收到不同的参数pos1和pos2
}

//n代表盘子的总数,pos1为起始位置,pos2为中转位置,pos3为目的位置
void Hanoi(int n, char pos1, char pos2, char pos3)
{
	//如果只有一个盘子,就直接将这个盘子从A挪到C
	if (n == 1)
	{
		move(pos1, pos3);//接收到的pos1和pos3每次都不一定相同,会随之而变化
	}
	else
	{
		Hanoi(n - 1, pos1, pos3, pos2);//将一个盘子从A借助C挪到B
		move(pos1, pos3);//将最下面的盘子从A挪到C
		Hanoi(n - 1, pos2, pos1, pos3);//将n-1个盘子从B借助A挪到C
	}
}

int main()
{
	int n = 0;//n是要挪的盘子总数
	scanf("%d", &n);
	Hanoi(n, 'A', 'B', 'C');//A,B,C相当于三个柱子
	return 0;
}

2.青蛙跳台阶问题

        这个问题与斐波那契数列很像

斐波那契数列是1  1  2  3  5  8  13  21  34  55

青蛙跳台阶是    1  2  3  5  8  13  21  34  55  89

斐波那契数列是从第3项起,前两项之和等于这一项。

而青蛙跳台阶只是少了最开始的一项,即少了个1,因此只有再斐波那契数列的基础上稍微改动即可。 

使用递归

int Fib(int n)
{
	if (n > 0 && n <= 2)
	{
		return n;
	}
	else
	{
		return Fib(n - 1) + Fib(n - 2);
	}
}

int main()
{
	int n = 0;
	int ret = 0;
	scanf("%d", &n);
	ret = Fib(n);
	printf("ret=%d\n", ret);
	return 0;
}

使用迭代

int Fib(n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 1)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}

int main()
{
	int n = 0;
	int ret = 0;
	scanf("%d", &n);
	ret = Fib(n);
	printf("%d", ret);
	return 0;
}

你可能感兴趣的:(c语言,递归算法)