Duvida sobre recursividade

Boa noite…
Qual a vantagem de usar a recursividade no java?
Eu to tentando aprender mas eu acho os metodos nao recursivos mais faceis de usar…

Olá amigo, a recursividade é um pouco complexa inicialmente,mas com tempo e pratica vai aparecendo certa situações que é necessária, a vantagem depende do algoritmo que está sendo desenvolvido, quando você está fazendo estrutura de dados(fila, pilha, lista encadeada e etc) na maioria dos casos utilizar a recursividade para deixar o código mais enxuto , legível e evitar muitos laço de repetição.

Independente da linguagem, recursividade pode ser útil em diversos cenários.
Acredito que sua maior vantagem é o fato de que o empilhamento das chamadas de métodos é gerenciado pelo sistema operacional (ou pela máquina virtual no caso do Java) poupando assim o programador de implementar uma estrutura de pilha.

Vou te dar um desafio simples:
Escreva um algoritmo que liste todos os arquivos de todas as pastas e subpastas de uma unidade de disco de seu computador.
Tente implementar uma versão sem recursividade e outra com recursividade.

1 curtida

Passei um tempo estudando algoritmos recursivos e percebi que são mais fáceis de implementar do que os iterativos.
Os recursivos são mais difíceis de visualizar e as vezes mais difíceis de entender oque o algoritmo faz, mas percebi que muitos deles seguem um certo padrão:

Number método(Parâmetros) {
  // bloco de calculo de condição de saída
  // bloco de condição de saída
  // bloco de calculo de bloco de repetição
  // bloco de repetição
}

Exemplo Fibonacci:

int Fibonacci(int numero) {
  // bloco de calculo de condição de saída
  // nada

  // bloco de condição de saída
  if (numero == 0) return 0;
  if (numero == 1) return 1;

  // bloco de calculo de bloco de repetição
  // nada

  // bloco de repetição
  return Fibonacci(numero - 1) + Fibonacci(numero - 2);
}

Exemplo do algoritmo listar arquivos do @staroski :

void listarArquivos(Pasta pasta, Lista arquivos) {
  // bloco de calculo de condição de saída
  // nada

  // bloco de condição de saída
  // nada

  // bloco de calculo de bloco de repetição
  Lista pastas;
  for (item : pasta) {
    if (item é arquivo) {
      arquivos.add(item);
    } else if (item é pasta) {
      pastas.add(item);
    }
  }

  //  bloco de repetição
  for (item : pastas) {
    listarArquivos(item, arquivos);
  }
}

ou

void listarArquivos(Item item, Lista arquivos) {
  // bloco de calculo de condição de saída
  // nada

  // bloco de condição de saída
  if (item é arquivo) {
    arquivos.add(item);
    return;
  } // else item é pasta

  // bloco de calculo de bloco de repetição
  // nada

  //  bloco de repetição
  for (i : item) {
    listarArquivos(i, arquivos);
  }
}

Compreendi a diferença…entretanto to achando muito dificil aprender…ja vi varios videos… mas nao aprendi de fato.
Tem algum site que ensine a fundo este assunto?

No início é confuso, mas a recursividade é basicamente um método que chama a si mesmo.
Ele trabalha de forma semelhante ao while, onde é necessário saber em que ponto o laço é quebrado.

No geral, é observar o comportamento e praticar.

Veja um exemplo, onde a codificação se comporta como se tive-se um while.

import java.util.Scanner;

public class Teste {

    public static void main(String[] args) {
        new Teste().escrevaAlgo(new Scanner(System.in));

    }

    private void escrevaAlgo(Scanner scan) {
        System.out.println(scan.hashCode()+" Informe algo:");
        String entrada = scan.nextLine();
        switch (entrada.toLowerCase()) {
            case "sair":
                System.out.println("Saindo da aplicação");
                break;
            default:
                System.out.println("Entrada informada: " + entrada+"\n");
                escrevaAlgo(scan);//como não digitou sair, o método chamou a si mesmo
        }
        System.out.println("Té+");//o comportamento aqui será "acumulado"
        scan.close();
    }
}

Então, recursividade é bem legal, mas deve ser usada com cuidado pois consome muito recurso e possui construções diferentes, ou seja depende da finalidade.

Na construção acima, eu não retornei nada, apenas chamei o método, este é um comportamento básico.
Seria possível chamar este método indiretamente, mas ai já é outra situação.

Resumo, praticar.

faça uma funçao recursiva que calcula a quantidade de caracteres em uma string.

Fiz da seguinte forma e funcionou:
public static int contarCaracteres(String str){
if ( str.length()==0)
{
return 0;
}
if (str.length()==1){
return 1;
}
str = str.substring(1, str.length());
return 1 + contarCaracteres(str);
}

Agora é praticar, lembrando que a recursividade deve ser usada com cuidado.

Fazer uma funçao recursiva que calcule o valor da serie S descrita a seguir para um valor n>0 a ser fornecido como parametro para a mesma: S= 1 + 1/2! + 1/3! + … 1/n!

Aqui fiz da seguinte forma… eu coloquei uma funca dentro de outra funçao… Eu ja tinha uma funçao que calculava o fatorial
public static int calcular(int num){
if (num == 0){
return 1;
} else {
return num * calcular(num-1);
}
}

public static double serie(int num){
if (num==0){
return 0;
}
if (num==1){
return 1;
}
return 1/ (calcular(num)) + serie(num-1);
}

Esta certo?