11. Recursión e iteración de funciones.

1. ¿Qué es la recursividad?

La recursividad es un método para resolver problemas, y la recursividad es cuando la función se llama a sí misma.
ejemplo:

int main() {
    
    
	printf("调用函数main");
	main();
	return 0;
}

El código anterior es solo para demostrar la forma de recursividad, no para resolver el problema:
cuando se llama a la función principal en la función principal, el código eventualmente cae en una recursividad muerta, llamando a la función principal infinitamente, lo que eventualmente conduce a un desbordamiento de la pila (desbordamiento )

El resultado de salida está bloqueado y la pila de errores se desborda.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Pensamiento recursivo:

Convierta un problema grande y complejo en un subproblema que sea similar al problema original pero de menor escala para resolver. Hasta que el problema grande se divida, la recursividad finaliza. Esa es la idea de reducir las cosas grandes a cosas pequeñas .


2. Restricciones a la recursividad

Hay dos condiciones necesarias para la recursividad en formato escrito:

1. Existen restricciones a la recursividad. Cuando se cumple esta restricción, la recursividad ya no continuará y se detendrá.
2. Después de cada llamada recursiva, se acerca cada vez más a este límite.

Aquí hay algunos ejemplos de preguntas recursivas para darle una idea.


3. Ejemplo recursivo

3.1 Encuentra el factorial de n

计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。
n的阶乘的公式:n! = n ∗ (n − 1)!

1.如果n等于0,则直接返回1,因为0的阶乘定义为1
2.否则,将n与(n-1)的阶乘结果相乘,并返回这个乘积
3.直至fact(n)中的n被减至0,跳出递归

Insertar descripción de la imagen aquí

//求n的阶乘
//计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。
int fact(int n) {
    
    
	if (n = 0) {
    
    //如果n等于0,则直接返回1,因为0的阶乘定义为1。
		return 1;
	}
	else//否则,将n与(n-1)的阶乘结果相乘,并返回这个乘积
	{
    
    
	
	//这里就是把一个大的数拆成了一个小的数乘上一个递归函数
	//直至fact(n)中的n被减至0,跳出递归
		return n * fact(n - 1);
	}
	return 0;
}

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

Insertar descripción de la imagen aquí

3.2 Imprimir cada dígito de un número entero secuencialmente

输⼊⼀个整数n,打印这个按照顺序打印整数的每⼀位
输⼊:1234 输出:1 2 3 4
输⼊:520  输出:5 2 0

n % 10 toma el último dígito
n/10 elimina el último dígito

void Print_Frist(int n) {
    
    
	if (n > 9) {
    
    
	//这里先递归再去打印最后一位
		Print_Frist(n / 10);
	}
	//打印最后一位
	printf("%d ", n % 10);
}

int main() {
    
    
	int n;
	scanf("%d", &n);
	Print_Frist(n);
	return 0;
}

Idea equivocada:

void Print_Frist(int n) {
    
    
	if (n > 9) {
    
    
		//如果这里把n除以10,那么此次函数中的打印最后一位就会出问题
		n = n / 10;
		Print_Frist(n);
	}
	//打印最后一位,这里会出问题
	printf("%d ", n % 10);
}

razón:

Por ejemplo, ingrese 1234. Si n = n / 10 en la declaración if,
entonces use n como parámetro de la función Print_Frist(n) (de hecho, no hay ningún problema aquí); sin embargo, esta vez la función printf("%d ", n % 10); El n in también cambiará en consecuencia. Originalmente era 4 y se convirtió en 3 después de n = n / 10.
Cuando la función se llama de forma recursiva, la función aún no ha finalizado por completo, es decir, cuando Print_Frist( n) se llama, el siguiente printf("%d ", n % 10) aún no se ha ejecutado.
Todo lo que necesitamos es cambiar los parámetros en la función de llamada de bucle/10, y n en esta función permanece sin cambios.


4. Recursión e iteración

Permítanme enfatizar que en las siguientes preguntas, n en int Fibonacci(int n) en la función numérica de Fibonacci es solo un parámetro en la función, comenzando desde 0; y el parámetro es 0, que es el primer término, y así sucesivamente. (Entonces será +1 al imprimir el resultado) F(0) = 0 //Primer elemento F(1) = 1 //Segundo elemento

4.1 Encuentre el enésimo número de Fibonacci (no se recomienda la recursividad)

斐波那契数列是一个经典的数列,在数学上以如下递归关系定义:
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)
换句话说,斐波那契数列的前两项是0和1,之后的每一项都是前两项的和。
//递归方法
int count = 0;//调用函数次数
int Fibonacci(int n) {
    
    
	if (n <= 1) {
    
    
		count++;
		return n;
	}
	else{
    
    
		count++;
		return Fibonacci(n-1) + Fibonacci(n-2);
	}
}

int main() {
    
    
	int n;
	scanf("%d", &n);
    printf("第%d斐波那契数 = %d\n", n + 1, Fibonacci(n));
	printf("共调用了函数 %d 次\n",count);
	return 0;
}

Insertar descripción de la imagen aquí

Inapropiado.
Este cálculo puede obtener resultados correctos, pero esta función se ha llamado casi 40 millones de veces.
Cada vez que se llama a una función en lenguaje C, se debe asignar un espacio de memoria en el área de la pila para guardar los valores. de varias variables locales durante la llamada a la función. , este espacio se llama pila de tiempo de ejecución o marco de pila de funciones.
En el paso anterior de retorno del número de Fibonacci Fibonacci (n - 1) + Fibonacci (n - 2), la función se llama recursivamente nuevamente en el valor de retorno. La función aún no ha finalizado y el espacio no se ha liberado, por lo que es necesario para abrir recursivamente otro El nuevo espacio de memoria abre un nuevo espacio de marco de pila para cada recursión. El espacio del marco de pila se liberará capa por capa hasta que comience a regresar.

4.2 Encuentre el enésimo número de Fibonacci (recomendación iterativa)

La iteración es un método para realizar una operación o proceso repetidamente. En programación, la iteración se utiliza normalmente para procesar cada elemento de una colección (como una lista, una matriz, etc.) o para ejecutar repetidamente un bloque de código hasta que se cumpla una condición específica. (Como sugiere el nombre, es una iteración de actualización, que reemplaza la variable con otra variable nueva.

//迭代
int count = 0;
int Fibonacci(int n) {
    
    
    if (n <= 1) {
    
    
        count++;
        return n;
    }
    int a = 0;  // 第 0 项
    int b = 1;  // 第 1 项
    int fib = 0;  // 第 n 项

    for (int i = 2; i <= n; i++) {
    
    
        fib = a + b;
        //相当于都往后走了一位,因为这三个数是连续的
        a = b;
        b = fib;
        count++;
    }
    return fib;
}

int main() {
    
    
	int n;
	scanf("%d", &n);
	printf("第%d个斐波那契数 = %d\n",n+1, Fibonacci(n));
	printf("共执行了 %d 次\n",count);
	return 0;
}

Insertar descripción de la imagen aquí

El código anterior utiliza una eficiencia de iteración que es mucho mayor que la eficiencia de recursividad.

4.3 Resumen

Aunque la recursividad es una muy buena idea, no se puede entrar en la recursividad a ciegas. Cualquier método tiene sus propias ventajas y desventajas, por lo que los problemas específicos deben analizarse en detalle. Hay muchas soluciones a un problema y se prefiere la eficiencia. uno.

Supongo que te gusta

Origin blog.csdn.net/qq_45657848/article/details/132096859
Recomendado
Clasificación