Artigos anteriores
1 Introdução - Conceitos básicos da estrutura de dados
2 Introdução - Algoritmo
3 Lista de sequência linear linear e conceitos de lista vinculada e sua implementação de código
4 Ordem de pesquisa + Metade + Índice + Hash
5 Inserção Sort-Hill Sort-Selection Sort-Bubble Sort -Quick Sort-Cardinal Sort-External Sort-Merge Sort
Artigo Diretório
- 1 Definição de recursão
- 2 Solução recursiva e não recursiva da sequência de Fibonacci
- 3 Soluções recursivas e não recursivas para detecção de string de palíndromo
- 4 Divida e conquiste a recursão
- 5 Exemplo de aplicação
1 Definição de recursão
- Uma sub-rotina (ou função) chama a si mesma direta ou indiretamente por meio de uma série de instruções de chamada, que é chamada de recursão.
- A recursão é um método básico de descrição e solução de problemas.
Chamada recursiva direta
void A()
{
...
A();
...
}
Recursão de chamada indireta
void B()
{
...
C();
...
}
void C()
{
...
B();
...
}
2 Solução recursiva e não recursiva da sequência de Fibonacci
A recursão de cauda pode ser convertida em escrita não recursiva
A recursão da cauda significa que a recursão só ocorre quando o retorno
Solução recursiva
int f(int n)
{
if(n<=1)
return n;//结束条件
else
return(f(n-1)+f(n-2));//递归方程
}
Solução não recursiva
int f(int n)
{
int pre,now,next,j;
if(n<=1)return(n);
else
{
pre=0;now=1;
for(j=2;j<=n;j++)
{
next=pre+now;
pre=now;
now=next
}
return(next);
}
}
3 Soluções recursivas e não recursivas para detecção de string de palíndromo
Se uma string é lida da esquerda para a direita e lida da direita para a esquerda é exatamente a mesma (não diferencia maiúsculas de minúsculas), então esta string é chamada de palíndromo. Por exemplo, "meio-dia", "madame", etc. são todas strings de palíndromo .
Solução recursiva
bool palindrome(string &s,unsigned h,unsigned t)
{
if (h>=t) return 1;
if(tolower(s[h])==tolower(s[t]))
return palindrome(s,h+1,t-1);
else
return 0;
}
Solução não recursiva
bool palindrome(string &s)
{
int h=0,t=strlen(s)-1;
while(h<=t)
{
if(s[h]!=s[t])return 0;
h++;t--;
}
return 1;
}
4 Divida e conquiste a recursão
4.1 Divida e conquiste o pensamento recursivo
- Resolva esses k subproblemas separadamente. Se o tamanho do subproblema ainda não for pequeno o suficiente, divida-o em k subproblemas e proceda recursivamente até que o problema seja pequeno o suficiente para encontrar sua solução facilmente.
- Combine a solução do problema de pequena escala encontrada na solução de um problema de grande escala e, gradualmente, encontre a solução do problema original de baixo para cima.
4.2 Condições aplicáveis da lei dividir para conquistar
- O tamanho do problema pode ser facilmente resolvido reduzindo-o até certo ponto;
- O problema pode ser decomposto em vários problemas idênticos de menor escala, ou seja, o problema tem a propriedade de subestrutura ótima ( premissa )
- As soluções dos subproblemas decompostos pelo problema podem ser combinadas na solução do problema; ( se você tiver os dois primeiros, mas não o terceiro, você pode considerar o uso de algoritmo guloso e programação dinâmica )
- Os subproblemas decompostos pelo problema são independentes uns dos outros, ou seja, os subproblemas não contêm subproblemas comuns. ( Este recurso projeta a eficiência do método de dividir e conquistar )
4.3 As etapas básicas de dividir e conquistar
Preste atenção às notas
{
if ( | P | <= n0) adhoc(P); //解决小规模的问题
divide P into smaller subinstances P1,P2,...,Pk;//分解问题
for (i=1,i<=k,i++)
yi=divide-and-conquer(Pi); //递归的解各子问题
return merge(y1,...,yk); //将各子问题的解合并为原问题的解
}
4.4 Três maneiras de resolver o cálculo da complexidade recursiva
4.4.1 Método de substituição
Pré-requisito (ignorar os detalhes e adicioná-los se forem considerados importantes posteriormente)
T (n) consiste em duas partes, uma éSoma do tempo de cálculo para cada pequena parte + Tempo de decomposição e tempo de reconciliação f (n)
A ideia principal
- Adivinhe a forma da solução.
- Use a indução matemática para encontrar a constante que torna a solução realmente eficaz
4.4.2 Expansão direta de método iterativo
4.4.3 Método principal
5 Exemplo de aplicação
Supondo que haja n dados a [n], para imprimir todas as permutações desses n dados, considere o método recursivo PrintPermutation.
-
O elemento na primeira posição pode ser qualquer um desses n elementos. Você pode usar swap para trocar a primeira posição por outras posições para obter a diferença no primeiro elemento de posição, e o resto da chamada recursiva imprime todos. A função de organização PrintPermutation é concluído. No entanto, deve-se notar que eles devem ser trocados de volta para facilitar o manuseio correto posteriormente.
-
Dentro da função recursiva, o elemento na primeira posição atual (a segunda posição) será trocado com os elementos de posição n-2 restantes; o elemento na primeira posição atual (a terceira posição) será trocado com o n-Exchange restante de 3 elementos de posição; ...; O elemento na última enésima posição significa que as n-1 posições anteriores foram processadas e podem ser impressas. Portanto, a condição de impressão recursiva é a posição k = n, esta também é uma saída recursiva
a [] armazena os dados k representa a primeira posição de troca, geralmente 1, n é o número de dados.
void PrintPermutation(int a[], int k, int n){
if (k == n){
for (int i = 1; i < n + 1; ++i){
cout << a[i] << " ";
}
cout << endl;
return;
}
else{
for (int i = k; i < n+1; ++i){
Swap(a[k], a[i]);
PrintPermutation(a, k + 1, n);
Swap(a[k], a[i]);
}
}
}
int main()
{
int *a, len;
cout << "len:" << endl;
cin >> len;
a = new int[len+1];
if (!a)return -1;
for (int i = 1; i < len + 1; ++i)
a[i] = i;
PrintPermutation(a, 1, len);
}
Se houver omissões e erros, indique-os.