2011-07-02 27 views
1

フィボナッチシリーズのいくつかのインデックスに基づいてスレッドを使用して再帰的に調べる必要があります。次のコードを試しましたが、プログラムは終了しません。私が何かを見逃している場合は、私に知らせてください。Java ExecutorServiceを再帰的フィボナッチシリーズ

コード:固定

import java.math.BigInteger; 
    import java.util.concurrent.*; 

    public class MultiThreadedFib { 

    private ExecutorService executorService; 

    public MultiThreadedFib(final int numberOfThreads) { 
     executorService = Executors.newFixedThreadPool(numberOfThreads); 
    } 

    public BigInteger getFibNumberAtIndex(final int index) 
     throws InterruptedException, ExecutionException { 

     Future<BigInteger> indexMinusOne = executorService.submit(
     new Callable<BigInteger>() { 
      public BigInteger call() 
      throws InterruptedException, ExecutionException { 
      return getNumber(index - 1); 
      } 
     }); 

     Future<BigInteger> indexMinusTwo = executorService.submit(
     new Callable<BigInteger>() { 
      public BigInteger call() 
      throws InterruptedException, ExecutionException { 
      return getNumber(index - 2); 
      } 
     }); 

     return indexMinusOne.get().add(indexMinusTwo.get()); 
    } 

    public BigInteger getNumber(final int index) 
    throws InterruptedException, ExecutionException { 
     if (index == 0 || index == 1) 
     return BigInteger.valueOf(index); 

     return getFibNumberAtIndex(index - 1).add(getFibNumberAtIndex(index - 2)); 
    } 
    } 

その代わりに呼び出しメソッドからはgetNumber(int)を呼び出すドル紙幣のおかげで)

、私は動的プログラミングアルゴリズムを呼び出していますそのインデックスの数値を計算します。

そのためのコードは次のとおりです。

public class DynamicFib implements IFib { 

private Map<Integer, BigInteger> memoize = new HashMap<Integer, BigInteger>(); 

public DynamicFib() { 
    memoize.put(0, BigInteger.ZERO); 
    memoize.put(1, BigInteger.ONE); 
} 

public BigInteger getFibNumberAtIndex(final int index) { 

    if (!memoize.containsKey(index)) 
    memoize.put(index, getFibNumberAtIndex(index - 1).add(getFibNumberAtIndex(index - 2))); 

    return memoize.get(index); 
    } 
} 

答えて

1

この再帰は非常に速く、スタックオーバーフローします。これは、フィボナッチ数が何度も何度も何度も計算しているためです(指数関数的に何回も繰り返します)。

ことを回避するための1つの効果的な方法は、

は、基本的にはすでに計算フィボナッチ数を保持するために、静的な配列を使用して、あなたがものを必要なときに、場合、配列からそれを取るメモ化再帰(動的計画法)を使用することですそれはすでに計算されています。そうでない場合は、それを計算して配列に格納します。この方法では、各数値は1回だけ計算されます。何をやっている

(あなたは、もちろん、配列の代わりに、すなわちハッシュテーブルを他のデータ構造を使用することができます)

+0

これは機能しました!ありがとう! :) – Shankar

+0

しかし、まだ再帰的なマルチスレッドの手順は、再帰的な非マルチスレッドのメモ帳よりずっと長い時間がかかります。 – Shankar

+0

繰り返し回数が指数関数的に増加するため、単純な再帰は決して終了しません(マルチスレッドの場合もあります)。 –

1

は、スレッド/タスクを経由して再帰で簡単な再帰を置き換えることです。

fib(0)およびfib(1)のケースになるまで、各タスクはさらに2つのタスクを送信し、完了するのを待ちます。それが待っている間、まだスレッドを使用しています。スレッドプールが制限されているので、あなたはすぐにsubmitブロックに呼び出して...と、全体の計算がロックアップポイントを取得します。


はそれに加えて、あなたは間違った答えを与えて計算につながるindexMinusTwoのバグを持っています。


しかし、まだ再帰的マルチスレッド化手順の性能を改善するための任意の先端..メモ化再帰非マルチスレッド1よりもはるかに長い時間がかかりますか?でも、あなたがより良い実行フィボナッチのマルチスレッドバージョンを行うことができるようになりますない方法はありません(無制限のスレッドプールを使用することによって)上記の問題を「固定」することを想定し

メモ化を使用するシングルスレッドバージョン。計算は単に並列化には適していません。

+0

説明をありがとうございます。しかし、そのコードのどこにバグがあるのか​​を教えてください。 – Shankar

+0

あなたはそれを修正しました。 –

0

スレッドは、実行する独立したタスクがある場合に最適です。定義によるフィボナッチシリーズには、並行性はありません。各f(n)は、前の2つの値に依存します。したがって、複数のスレッドを使用するよりも高速にf(n)を計算することはできません(非効率なアルゴを持たない場合)

大きな数値に対しては+の演算を並列化できる唯一の方法ですが、 a)複雑であるb)単一のスレッド化された解決策よりも速くすることは困難である。

フィボナッチ数を計算する最も簡単で簡単な方法は、1つのスレッドでループを使用することです。 recusrionを使うか、値を記憶する必要はありません。