@Stack e recursão (na verdade, é mais recursão de análise)
1. Recursão
1. Conceito
O que é recursão é o que aprendemos na matemática do ensino médio, recursão. Claro, se uma fórmula de recorrência é expressa como uma função, podemos chamar essa função 递归函数
. 递归函数
É uma função que chama a si mesma diretamente ou por meio de uma série de instruções, chamada de função recursiva.
Por exemplo, nossa função fatorial:
F act (n) = {1, n = 0 n ⋅ F act (n - 1), n> 0 Fato (n) = \ left \ {\ begin {alinhados} 1, n = 0 \\ n \ cdot Fato (n-1), n> 0 \\ \ end {alinhado} \ à direita.F a c t ( n )={
1 ,n=0n⋅F a c t ( n-1 ) ,n>0
Ou a sequência familiar de Fibonacci:
F ib (n) = {0, n = 0 1, n = 1 F ib (n - 1) ⋅ F ib (n - 2), n> 1 Fib (n) = \ left \ {\ begin {alinhado} 0, n = 0 \\ 1, n = 1 \\ Fib (n-1) \ cdot Fib (n-2), n> 1 \\ \ end {alinhado} \ right.F i b ( n )=⎩⎪⎨⎪⎧0 ,n=01 ,n=1F i b ( n-1 )⋅F i b ( n-2 ) ,n>1
2. Perceba
Podemos pensar o termo constante, é chamado 递归边界
, como o factorial f(n)=1,n=0
de números de Fibonacci ou a seqüência de Fibonacci f(n)=0,n=0
, f(n)=1,n=1
.
Em seguida, escrevemos um código recursivo que implementa a sequência de Fibonacci:
int Fib(int n)
{
if (n == 0) return 0;
else if (n == 1) return 1;
else
{
return Fib(n-1) + Fib(n-2);
}
}
int main()
{
printf("%d", Fib(10));
return 0;
}
Contanto que possamos escrever uma expressão de função recursiva, podemos escrever sua função recursiva. Na minha opinião:O limite recursivo é o mais importante. Se o limite de recursão não for tratado corretamente, a recursão pode continuar para sempre e, em seguida, explodir em morte.
3. Análise recursiva mais difícil - Torre de Hanói
As regras do jogo na Torre de Hanói são: mova o prato A para o prato C, e o prato grande não pode ser colocado no prato pequeno.
Para isso, tentamos mais algumas vezes:
-
n = 1
1º Conjunto 1 A ----> C
-
n = 2
O primeiro conjunto 1 A ----> B
2º Conjunto 2 A ----> C
3º Conjunto 1 B ----> C
-
n = 3
1º Conjunto 1 A ----> C
A segunda rodada No. 2 A ----> B
3º Conjunto 1 C ----> B
4º Conjunto 3 A ----> C
A 5ª rodada No. 1 B ----> A
6º Conjunto 2 B ----> C
7º Disco 1 A ----> C
Se usarmos a abordagem holística, se movermos uma pilha de placas de A para C, podemos considerar as placas no pilar A como dois inteiros, a placa inferior e todas as placas nela. Então nosso processo é:
- Todas as placas acima de A a B
- A placa inferior vai de A a C
- Todas as placas acima de B a C
Então, como movemos a placa superior para B e C? Pense nesta parte da placa como duas partes, a placa de fundo e todas as placas de cima.
Se movermos para B, então C é nossa torre auxiliar (porque o jogo se move de A para C, então B é uma torre auxiliar), então vamos realizar a "operação Torre de Hanói de A para B" na parte superior.
Por outro lado, se você mover de B para C, A é a torre auxiliar, então o que estamos fazendo é "operação de entalhe de solda B para C"
Comece a boneca. Até o final nós só temos uma placa, então obviamente, ele executa "A a C Torre de operação de Hanói" e só tem uma placa, então mova-a para C.
Então, nossa expressão recursiva surge:
Limite de recursão: n=1时 把1号盘子 A→C
Conteúdo recursivo: ① 把n-1号盘子 A→B
② 把n号盘子 A→C
③把n-1号盘子 B→C
Ok, vamos implementar o código:
void hano(int n, char a, char b, char c) // hano(n=有几个碟子,a=主塔,b=辅助塔,c=目标塔)
{
if (n == 1) printf("No.%d %c -> %c\n", 1, a, c);
else
{
hano(n - 1, a, c, b); // 这里是A to B的操作,C是辅助塔
printf("No.%d %c -> %c\n", n, a, c);
hano(n - 1, b, a, c); // 这里是B to C的操作,A是辅助塔
}
}
int main()
{
hano(3, 'A', 'B', 'C'); // 这里是A to C的操作
return 0;
}
2. A relação entre pilha e recursão
Em linguagens de alto nível, se você precisa chamar (este é o verbo) função, então 调用(名词)函数
, e 被调用函数
links para troca de informações entre necessidades por meio de pilha interna.
Antes de executar a função chamada, o sistema completará três coisas:
- Passe todos os parâmetros reais, endereço de retorno e outras informações para a função chamada para salvar.
- Alocar área de armazenamento para as variáveis locais da função chamada
- Transfira o controle para a entrada da função chamada.
Então, antes que a função chamada retorne à função de chamada, temos que completar três coisas:
- Salve o resultado do cálculo da função chamada
- Libere a área de dados da função chamada
- Transfira o controle para a função de chamada de acordo com o endereço de retorno salvo pela função chamada.
Suponha que façamos chamadas aninhadas como recursivamente, então a função chamada primeiro deve retornar por último, portanto, dentro do compilador, esses relacionamentos e informações são salvos para nós por meio da pilha.
Portanto, a transferência de informações entre nossa recursão precisa usar a pilha. Felizmente, o compilador vai gerenciar 递归工作栈
isso para nós, então só precisamos considerar o limite de recursão e o conteúdo da recursão!