[Registro de aprendizagem de estrutura de dados 7] - pilha e recursão (na verdade, mais análise e recursão)

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=0nF 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=0de 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

Insira a descrição da imagem aqui

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:

  1. n = 1

    1º Conjunto 1 A ----> C

  2. n = 2

    O primeiro conjunto 1 A ----> B

    2º Conjunto 2 A ----> C

    3º Conjunto 1 B ----> C

  3. 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 é:

  1. Todas as placas acima de A a B
  2. A placa inferior vai de A a C
  3. 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:

  1. Passe todos os parâmetros reais, endereço de retorno e outras informações para a função chamada para salvar.
  2. Alocar área de armazenamento para as variáveis ​​locais da função chamada
  3. 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:

  1. Salve o resultado do cálculo da função chamada
  2. Libere a área de dados da função chamada
  3. 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!

Acho que você gosta

Origin blog.csdn.net/u011017694/article/details/109428873
Recomendado
Clasificación