2016-04-16 9 views
4

私はテストしている2つのフィボナッチメソッドを持っています。どちらも線形でなければなりません。私はメモやHashMapのルックアップが私が思ったよりも遅いことを理解していません。ダイナミックプログラミングの実装が不良か、HashMapが遅いですか?

私は、DPを追加することで再帰関数を大きくするべきではないことを理解していますが、静的なので一度だけ計算する必要があります(スコープから外れることはありません)。最初の実行後、HashMapから回答を取得します。

私はO(log n)フィボナッチ関数とベンチマークを実装するための準備としてこれをやっていますが、これを見て少し迂回しました。 (反復的なアプローチへの追加のメモも、それを遅くする)。

私に教えてください、私は現時点ではかなり愚かだと感じています。

反復アプローチ:

public static int linearIterativeFib(int x) { 
    if (x <= 2) { 
     return 1; 
    } else { 
     int prev = 0; 
     int result = 1; 
     for (int i = 2; i <= x; i++) { 
      int temp = result; 
      result += prev; 
      prev = temp; 
     } 
     return result; 
    }  
} 

再帰的アプローチ:

static Map<Integer, Integer> memo = new HashMap<Integer, Integer>(); 

public static int linearRecursiveFib(int x) { 
    if (x <= 2) { 
     return 1; 
    } else if (memo.containsKey(x)) { 
     return memo.get(x); 
    } else { 
     int result = linearRecursiveFib(x - 1) 
       + linearRecursiveFib(x - 2); 
     memo.put(x, result); 
     return result; 
    } 
} 

とユニットテスト:

@Test 
public void testSpeed() { 
    int input = 35; 
    long start = System.currentTimeMillis(); 
    for (int i = 0; i < 10000000; i++) { 
     fib.linearIterativeFib(input); 
    } 
    System.out.println("Iterative approach took " 
      + (System.currentTimeMillis() - start) + "ms"); 

    start = System.currentTimeMillis(); 
    for (int i = 0; i < 10000000; i++) { 
     fib.linearRecursiveFib(input); 
    } 
    System.out.println("Recursive approach took " 
      + (System.currentTimeMillis() - start) + "ms"); 
} 

戻り値:

Iterative approach took 6ms 
Recursive approach took 132ms 
+0

再帰にスタックの内容をプッシュしてポップすることが原因であると推測しています。 –

+0

大幅なパフォーマンスの差がある可能性がありますが、JITランタイムのベンチマークでは慎重な対応が必要です。あなたのベンチマークを再構築し、まだ十分なパフォーマンスの差がある場合は、新しい質問を編集または投稿してください。 – chrylis

+0

私は、 '' 'HashMap'''の代わりに' '' int [] '' 'を試しましたが、結果は2倍だけ違いました。 –

答えて

0

まず、Javaの再帰は反復よりも遅いです。

containsを実行してからgetするのではなく、単にヌルチェックを取得して実行するのはなぜですか?ハッシュとバケットは2回計算する必要がありますが、パーフォーマンスがどの程度大きいかはわかりません。

オートボクシング。 gnu Troveのようなプリミティブマップを使って外部のlibを使うことは良い考えです。パーフォーマンスがどうなるかわからないが、オブジェクトをもっと少なく割り当てる。

perf測定が健全であるかどうかを確認することもよいでしょう。再帰的なケースでは、最初の、または最初のいくつかの反復の方が残りの部分よりも遅くなりますか?平均値は良い測定値ではないかもしれません。レイテンシのヒストグラムを持つのはいいですね。

+0

Troveを推奨しないでください。より良いオプションがあります:http://java-performance.info/hashmap-overview-jdk-fastutil-goldman-sachs-hppc-koloboke-trove-january-2015/ – leventov

関連する問題