[java] 자바 재귀 피보나치 시퀀스

이 간단한 코드를 설명하십시오 :

public int fibonacci(int n)  {
    if(n == 0)
        return 0;
    else if(n == 1)
      return 1;
   else
      return fibonacci(n - 1) + fibonacci(n - 2);
}

마지막 줄과 혼동됩니다. 특히 예를 들어 n = 5 인 경우 fibonacci (4) + fibonacci (3) 등이 호출되지만이 알고리즘이 인덱스 5의 값을 계산하는 방법을 이해하지 못하기 때문에 방법. 자세하게 설명 해주세요!



답변

피보나치 수열에서 각 항목은 이전 두 항목의 합계입니다. 따라서 재귀 알고리즘을 작성했습니다.

그래서,

fibonacci(5) = fibonacci(4) + fibonacci(3)

fibonacci(3) = fibonacci(2) + fibonacci(1)

fibonacci(4) = fibonacci(3) + fibonacci(2)

fibonacci(2) = fibonacci(1) + fibonacci(0)

이제는 이미 알고 fibonacci(1)==1 and fibonacci(0) == 0있습니다. 따라서 나중에 다른 값을 계산할 수 있습니다.

지금,

fibonacci(2) = 1+0 = 1
fibonacci(3) = 1+1 = 2
fibonacci(4) = 2+1 = 3
fibonacci(5) = 3+2 = 5

그리고 피보나치 수열에서 0,1,1,2,3,5,8,13,21....우리는 5th element피보나치 수열이을 반환 한다는 것을 알 수 있습니다 5.

재귀 자습서는 여기를 참조하십시오 .


답변

코드에는 두 가지 문제가 있습니다.

  1. 결과는 정수 채우기 마이너스 비트 이후 첫 48 피보나치 수만 처리 할 수있는 int에 저장되며 결과는 잘못됩니다.
  2. 그러나 피보나치 (50)를 실행할 수 없습니다.
    코드
    fibonacci(n - 1) + fibonacci(n - 2)
    가 매우 잘못되었습니다.
    문제는 피보나치가 50 번이 아니라 훨씬 더 많다는 것입니다.
    처음에는 피보나치 (49) + 피보나치 (48),
    다음 피보나치 (48) + 피보나치 (47) 및 피보나치 (47) + 피보나치 (46)
    라고합니다. 피보나치 (n)가 될 때마다 복잡성이 지수입니다.
    여기에 이미지 설명을 입력하십시오

비 재귀 코드에 대한 접근 방식 :

 double fibbonaci(int n){
    double prev=0d, next=1d, result=0d;
    for (int i = 0; i < n; i++) {
        result=prev+next;
        prev=next;
        next=result;
    }
    return result;
}


답변

의사 코드에서 n = 5 인 경우 다음이 발생합니다.

피보나치 (4) + 피보나치 (3)

이것은 다음과 같이 분류됩니다.

(피보나치 (3) + 피보나치 (2)) + (피보나치 (2) + 피보나치 (1))

이것은 다음과 같이 분류됩니다.

(((피보나치 (2) + 피보나치 (1)) + ((피보나치 (1) + 피보나치 (0))) + ((((피보나치 (1) + 피보나치 (0)) + 1))

이것은 다음과 같이 분류됩니다.

((((피보나치 (1) + 피보나치 (0)) + 1) + ((1 + 0)) + ((1 + 0) + 1))

이것은 다음과 같이 분류됩니다.

((((1 + 0) + 1) + ((1 + 0)) + ((1 + 0) + 1))

결과 : 5

피보나치 수열이 1 1 2 3 5 8 … 이면 5 번째 요소는 5입니다. 동일한 방법론을 사용하여 다른 반복을 알아낼 수 있습니다.


답변

재귀는 때때로 파악하기 어려울 수 있습니다. 적은 수의 종이로 그것을 평가하십시오.

fib(4)
-> fib(3) + fib(2)
-> fib(2) + fib(1) + fib(1) + fib(0)
-> fib(1) + fib(0) + fib(1) + fib(1) + fib(0)
-> 1 + 0 + 1 + 1 + 0
-> 3

Java가 실제로 이것을 어떻게 평가하는지 잘 모르겠지만 결과는 같습니다.


답변

다음과 같이 기능을 단순화 할 수도 있습니다.

public int fibonacci(int n)  {
    if (n < 2) return n;

    return fibonacci(n - 1) + fibonacci(n - 2);
}


답변

                                F(n)
                                /    \
                            F(n-1)   F(n-2)
                            /   \     /      \
                        F(n-2) F(n-3) F(n-3)  F(n-4)
                       /    \
                     F(n-3) F(n-4)

중요한 점은이 알고리즘은 이전 계산 된 숫자의 결과를 저장하지 않기 때문에 지수입니다. 예를 들어 F (n-3)은 3 번 호출됩니다.

자세한 내용은 dasgupta chapter 0.2의 알고리즘을 참조하십시오.


답변

대부분의 답은 좋고 피보나치의 재귀가 어떻게 작동하는지 설명합니다.

다음은 재귀를 포함하는 세 가지 기술에 대한 분석입니다.

  1. 루프
  2. 재귀
  3. 메모

다음은 세 가지를 모두 테스트하는 코드입니다.

public class Fibonnaci {
    // Output = 0 1 1 2 3 5 8 13

    static int fibMemo[];

    public static void main(String args[]) {
        int num = 20;

        System.out.println("By For Loop");
        Long startTimeForLoop = System.nanoTime();
        // returns the fib series
        int fibSeries[] = fib(num);
        for (int i = 0; i < fibSeries.length; i++) {
            System.out.print(" " + fibSeries[i] + " ");
        }
        Long stopTimeForLoop = System.nanoTime();
        System.out.println("");
        System.out.println("For Loop Time:" + (stopTimeForLoop - startTimeForLoop));


        System.out.println("By Using Recursion");
        Long startTimeRecursion = System.nanoTime();
        // uses recursion
        int fibSeriesRec[] = fibByRec(num);

        for (int i = 0; i < fibSeriesRec.length; i++) {
            System.out.print(" " + fibSeriesRec[i] + " ");
        }
        Long stopTimeRecursion = System.nanoTime();
        System.out.println("");
        System.out.println("Recursion Time:" + (stopTimeRecursion -startTimeRecursion));



        System.out.println("By Using Memoization Technique");
        Long startTimeMemo = System.nanoTime();
        // uses memoization
        fibMemo = new int[num];
        fibByRecMemo(num-1);
        for (int i = 0; i < fibMemo.length; i++) {
            System.out.print(" " + fibMemo[i] + " ");
        }
        Long stopTimeMemo = System.nanoTime();
        System.out.println("");
        System.out.println("Memoization Time:" + (stopTimeMemo - startTimeMemo));

    }


    //fib by memoization

    public static int fibByRecMemo(int num){

        if(num == 0){
            fibMemo[0] = 0;
            return 0;
        }

        if(num ==1 || num ==2){
          fibMemo[num] = 1;
          return 1;
        }

        if(fibMemo[num] == 0){
            fibMemo[num] = fibByRecMemo(num-1) + fibByRecMemo(num -2);
            return fibMemo[num];
        }else{
            return fibMemo[num];
        }

    }


    public static int[] fibByRec(int num) {
        int fib[] = new int[num];

        for (int i = 0; i < num; i++) {
            fib[i] = fibRec(i);
        }

        return fib;
    }

    public static int fibRec(int num) {
        if (num == 0) {
            return 0;
        } else if (num == 1 || num == 2) {
            return 1;
        } else {
            return fibRec(num - 1) + fibRec(num - 2);
        }
    }

    public static int[] fib(int num) {
        int fibSum[] = new int[num];
        for (int i = 0; i < num; i++) {
            if (i == 0) {
                fibSum[i] = i;
                continue;
            }

            if (i == 1 || i == 2) {
                fibSum[i] = 1;
                continue;
            }

            fibSum[i] = fibSum[i - 1] + fibSum[i - 2];

        }
        return fibSum;
    }

}

결과는 다음과 같습니다.

By For Loop
 0  1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987  1597  2584  4181
For Loop Time:347688
By Using Recursion
 0  1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987  1597  2584  4181
Recursion Time:767004
By Using Memoization Technique
 0  1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987  1597  2584  4181
Memoization Time:327031

따라서 우리는 메모가 가장 현명 하고 루프 일치와 밀접하게 일치 하는 것을 볼 수 있습니다 .

그러나 재귀가 가장 오래 걸리므로 실제 생활에서 피해야 할 수도 있습니다. 또한 재귀를 사용하는 경우 솔루션을 최적화해야합니다.