6

次のような非常に単純な Java コードは奇妙な出力を示しますが、C と C++ の同じロジック コードは正しい出力を示します。JDK 1.7 と JDK 1.3 (相対 JRE) を試してみましたが、常に奇妙な出力が表示されます。

public class Test {

    public static int sum=0;

    public static int fun(int n) {

        if (n == 1)
            return 1;
        else
            sum += fun(n - 1);  // this statement leads to weird output
        // { // the following block has right output
        //     int tmp = fun(n - 1);
        //     sum += tmp;
        // }

        return sum;
    }

    public static void main(String[] arg) {
        System.out.print(fun(5));
    }
}

出力は 1 ですが、8 になるはずです。相対的な C/C++ コードは次のとおりです。

#include<stdio.h>
int sum=0;
int fun(int n) {

        if (n == 1)
            return 1;
        else
            sum += fun(n - 1);

        return sum;
    }

int main()
{
    printf("%d",fun(5));

    return 0;
}

テスト Java コードの追加:

class A {
    public int sum = 0;

    public int fun(int n) {
        if(n == 1) {
            return 1;
        } else {
            sum += fun(n - 1);
            return sum;
        }
    }
}

public class Test {
    public static void main(String arg[]){
        A a = new A();
        System.out.print(a.fun(5));
    }
}
4

8 に答える 8

6

問題は次の行です。

 sum += fun(n - 1);

変数を更新していますsum

単純に 1 から N までの数値を合計しようとしていると仮定すると、 で計算する計算を行う必要がf(N)ありf(N - 1)ます。それはあなたが参照する必要はありませんsum...そして確かにそれを更新する必要はありません。

(私は答えが何であるかをあなたに言わないように注意しています...なぜなら、あなたがそれを自分で理解すればもっと学ぶからです. )


ところで、アルゴリズムの欠陥についてJava固有のものは何もありません...


実際の問題は、静的変数とインスタンス変数の関係ではないことに注意してください。本当の問題は、このような再帰関数はどちらの種類の変数も使用してはならないということです。この例では、問題を回避できる可能性がありますが、再帰に次のようなものが含まれる場合:f(N) = f(N-1) + f(N-2)異なる呼び出しツリーが互いに干渉していることに気付く可能性があります。

この場合のより正しい解決策は、メソッドを次のように記述することです。

int fun(int n) {
    if (n == 1)
        return 1;
    else
        return n + f(n - 1);
}

先ほど言ったように、sum変数を参照したり更新したりする必要はありません。

于 2012-08-05T03:26:14.287 に答える
3

完全な答えを出すために、楽しみのためにこれを実行します(3)。これが C++ では機能するのに Java では機能しない理由に興味がない人は、私の回答を無視してください。

Javaが行っていることは次のとおりです。

インサイドファン(3)

sum += sum + fn(n-1) // sum is 0

になる

sum = 0 + fun(2) // sum is 0

次に、内部 fun(2)

sum = 0 + fun(1) // sum is 0

次に、内部 fun(1)

return 1 // sum is 0

楽しみの中に戻る(2)

sum = 0 + 1; // sum is 0

になる

sum = 1; // sum will soon become 1

楽しみの中に戻る(3)

sum = 0 + 1; // sum is 1

になる

sum = 1; // sum gets reset to 1

C++ が行っていることは次のとおりです。

インサイドファン(3)

sum += fn(n-1) // sum is 0

になる

sum = sum + fn(2) // sum is 0

次に、内部 fun(2)

sum = sum + fn(1) // sum is 0

次に、内部 fun(1)

return 1 // sum is 0

楽しみの中に戻る(2)

sum = sum + 1 // sum is 0

なる

sum = 0 + 1 => sum = 1 // sum will soon become 1

楽しみの中に戻る(3)

sum = sum + 1 // sum is 1

なる

sum = 1 + 1 // sum will soon become 2

すべきこと:sum C++が関数呼び出しを行う前ではなく後で 評価する理由がわかりません。これが仕様にあるかどうかはわかりません。しかし、どの言語でもこれに依存すべきではないことはわかっています。正しい解決策は次のとおりです。

int fun(int n) {
    if (n == 1)
        return 1;
    else
        return n + f(n - 1);
}
于 2012-08-05T04:29:59.213 に答える
1

これを試して:

public class Test {

   public static int fun(int n) {
      System.out.println("processing n " + n );

      if (n == 1)
        return 1;
       else{
           return n + fun(n - 1);
      }
   }

   public static void main(String[] arg) {
      System.out.print(fun(5));
   }
}
于 2012-08-05T03:38:30.333 に答える
1
public static int fun(int n) {
    if (n == 1)
        return 1;
    else
        return n +  fun(n - 1);
} 

ところで、C コードと同じ方法で実行したい場合は、sum を「int」ではなく「Integer」と定義するだけです。

于 2012-08-05T03:41:31.300 に答える
0

これを試して

   static int getsum(int num){
        int sum = 0;
        if(num == 1){
            return num;

        }else{
             sum  = num+getsum(num-1);  
        }

        return sum ;
    }
于 2012-08-05T04:42:44.563 に答える
0
return n <= 1 ? n : n + fun(n-1);
于 2012-08-05T03:54:45.063 に答える
0

そこでは、ロジックをステップ実行する必要があります。意味がありません。f(5) = 8 という「奇妙な」出力はありますか? (あなたは実際に誤って 2^(n-2) を計算する関数を書いてしまいましたが、それは的外れのようです)

構文が間違っている場所を説明することはできません-それはアルゴリズム自体です。それはあなたが意図したことをしないだけです。目立つはずの大きな赤い旗: 変数 n は、合計するために直接追加されていません! fun(5) を呼び出すと、その 5 は使用されません。f(4) に渡されるだけです。

あなたのロジックはこれだったようです:n-> 1から再帰的にループし、それを合計に追加します。その場合、関数は次のようになります。

void fun(int n){
    if(n == 0)
        return;
    sum += n;
    fun(n-1);
}

またはそのようなもの。しかし、それは非常に...再帰的な方法ではありません。変数がまったくない方がはるかに良いでしょう。非基本ケース: n+fun(n-1) を返します。

また、将来、一部のコードに「奇妙な出力」があると言うときは、おそらく、1) 奇妙な出力と 2) 予想される出力の両方を提供する必要があります。私たちは皆、あなたが何を書きたかったかを推測しているだけです。

于 2012-08-05T03:37:55.960 に答える