質問

書い機能を探 三角数字 の自然に書くので再帰的に:

function triangle (x)
   if x == 0 then return 0 end
   return x+triangle(x-1)
end

もう計算の100,000三角数字で失敗しスタックオーバーフローです!この理想的な機能 memoize, のりかもしれないけど、私は解決するmemoizeず機能していただくためです。

役に立ちましたか?

解決

私はベットのようなことは可変数の引数リストのユーザ:

local function varg_tostring(...)
    local s = select(1, ...)
    for n = 2, select('#', ...) do
        s = s..","..select(n,...)
    end
    return s
end

local function memoize(f)
    local cache = {}
    return function (...)
        local al = varg_tostring(...)
        if cache[al] then
            return cache[al]
        else
            local y = f(...)
            cache[al] = y
            return y
        end
    end
end

きょうもなんとかなるmetatablesに__tostring()この引数リストが変換され、tostring().Ohの可能性が広がる。

他のヒント

Mathematicaにより特にスリックいmemoizationに依拠し、そのハッシュ機能電話利用と同じ構文:

triangle[0] = 0;
triangle[x_] := triangle[x] = x + triangle[x-1]

それだけです。この作品で、ルールパターンマッチング機能通話などでは常により特定の定義の前にはより一般的な定義で設定します。

もちろん、どが指摘されており、この例はデフォルト液 triangle[x_] := x*(x+1)/2.フィボナッチ数列の典型的な例としては、どのように追加memoizationを与える激しい高速:

fib[0] = 1;
fib[1] = 1;
fib[n_] := fib[n] = fib[n-1] + fib[n-2]

このようなものは、デフォルトと同等もmessier: http://mathworld.wolfram.com/FibonacciNumber.html

私は国立大学志望の浪人生での人に案内しては不適memoization恐れがありますので"だけを使用loop"。のmemoizationする繰り返し関数呼び出しはO(1)時間。それにも多くO(n)いきものを振り返るシナリオのmemoized実施してより良いパフォーマンスを見る上ではフォルト実施中!

ま求められていますの違うオリジナルの問題)

これは今までになかった場合:

三角(n=n*(n-1)/2

また、仮式なかったようなすっき液memoisationだ貧しいアプローチです。まるで書く単純なループます。見 この答え のための充実した時間。

クライアントまで、フルのC#3.0-のための再帰的機能、いつものように:

public static class Helpers
{
    public static Func<A, R> Memoize<A, R>(this Func<A, Func<A,R>,  R> f)
    {
        var map = new Dictionary<A, R>();
        Func<A, R> self = null;
        self = (a) =>
        {
            R value;
            if (map.TryGetValue(a, out value))
                return value;
            value = f(a, self);
            map.Add(a, value);
            return value;
        };
        return self;
    }        
}

それを作成できmemoized色関数のようになります:

var memoized_fib = Helpers.Memoize<int, int>((n,fib) => n > 1 ? fib(n - 1) + fib(n - 2) : n);
Console.WriteLine(memoized_fib(40));

にスカラ(未審査):

def memoize[A, B](f: (A)=>B) = {
  var cache = Map[A, B]()

  { x: A =>
    if (cache contains x) cache(x) else {
      val back = f(x)
      cache += (x -> back)

      back
    }
  }
}

この作品のための機能arity1がcurryingす。により微妙な問題は memoize(f) != memoize(f) 他の機能 f.一sneakyグの修正方法は、このようなものになっていくかもの

val correctMem = memoize(memoize _)

ないと思いることをコンパイルするものではあ示のアイデアです。

更新:サていると指摘memoizationを最適化を再帰.確かに、んとこの前、私は一般的に働言語(C#)が一般化memoizationな些細なラの整備が欠かせません。のポストを下する結晶粒の塩です。

と思い ルカが最適なソリューション この問題がmemoizationは一般的に解決問題のスタックオーバーフロー.

スタックオーバーフロー通常より再帰っ以深にも取付けることができます。言語もサポート"尾再帰"再利用のコンテキストの現在の通話を作るのではなく新しいコンテキストを再帰的ます。がたくさんの主流言語/プラットフォームをサポートしない。C#のない固有の支援のためのテール-再帰ります。64-bitバージョン。ネジッターを適用することが可能で、最適化、ILレベルのすべては無駄な対応させる必要がある場合には32-bitプラットフォーム.

の場合の言語をサポートしていないテール再帰、ベストオプションを回避するスタックがあふれるいずれかへの変換による明示的なループ(少ない優雅な時に必要に応じて、アカデミック-ジャパニーズ)も非反復アルゴリズムなどのルを提供します。

function memoize (f)
   local cache = {}
   return function (x)
             if cache[x] then
                return cache[x]
             else
                local y = f(x)
                cache[x] = y
                return y
             end
          end
end

triangle = memoize(triangle);

このため、スタックオーバーフロー、三角ようにするシード.

こちら製品に変換せずにその引数の文字列です。の点に注意することができな取り扱い空の引数。が、解決できない別の価値 nil 文字列から "nil", うことになるだろう。

local function m(f)
  local t = { }
  local function mf(x, ...) -- memoized f
    assert(x ~= nil, 'nil passed to memoized function')
    if select('#', ...) > 0 then
      t[x] = t[x] or m(function(...) return f(x, ...) end)
      return t[x](...)
    else
      t[x] = t[x] or f(x)
      assert(t[x] ~= nil, 'memoized function returns nil')
      return t[x]
    end
  end
  return mf
end

私はインスパイアされたこの質問に行(い)フレキシブルmemoize機能Lua.

https://github.com/kikito/memoize.lua

主なメリット:

  • 数の可変数を受け入れる引数
  • を使用しませんのtostring;その代わりに、開催してキャッシュセットをツリー構造を使用し、パラメータを渡します。
  • 作品は、イブレア城、イブレアの機能を返す 複数の値.

貼り付け、コードはこちらを参考:

local globalCache = {}

local function getFromCache(cache, args)
  local node = cache
  for i=1, #args do
    if not node.children then return {} end
    node = node.children[args[i]]
    if not node then return {} end
  end
  return node.results
end

local function insertInCache(cache, args, results)
  local arg
  local node = cache
  for i=1, #args do
    arg = args[i]
    node.children = node.children or {}
    node.children[arg] = node.children[arg] or {}
    node = node.children[arg]
  end
  node.results = results
end


-- public function

local function memoize(f)
  globalCache[f] = { results = {} }
  return function (...)
    local results = getFromCache( globalCache[f], {...} )

    if #results == 0 then
      results = { f(...) }
      insertInCache(globalCache[f], {...}, results)
    end

    return unpack(results)
  end
end

return memoize

こちらは汎用C#3.0実装ができるように

public static class Memoization
{
    public static Func<T, TResult> Memoize<T, TResult>(this Func<T, TResult> function)
    {
        var cache = new Dictionary<T, TResult>();
        var nullCache = default(TResult);
        var isNullCacheSet = false;
        return  parameter =>
                {
                    TResult value;

                    if (parameter == null && isNullCacheSet)
                    {
                        return nullCache;
                    }

                    if (parameter == null)
                    {
                        nullCache = function(parameter);
                        isNullCacheSet = true;
                        return nullCache;
                    }

                    if (cache.TryGetValue(parameter, out value))
                    {
                        return value;
                    }

                    value = function(parameter);
                    cache.Add(parameter, value);
                    return value;
                };
    }
}

(引用から フランスのブログ記事)

静脈内に掲載memoization異なる言語で、そういった対応を@にonebyone.livejournal.com 非言語変化するC++の一例です。

まず、memoizer単arg機能

template <class Result, class Arg, class ResultStore = std::map<Arg, Result> >
class memoizer1{
public:
    template <class F>
    const Result& operator()(F f, const Arg& a){
        typename ResultStore::const_iterator it = memo_.find(a);
        if(it == memo_.end()) {
            it = memo_.insert(make_pair(a, f(a))).first;
        }
        return it->second;
    }
private:
    ResultStore memo_;
};

かのインスタンスを生成しmemoizer、飼料でご機能と引数です。だが加わらないようにしてください同じメモ間の異なる二つの機能が共有することができ間の実装が異なる場合も同じ機能)。

次に、ドライバー functon、実装されます。みのドライバーの機能する必要がある公 int fib(int);//ドライバー int fib_(int);//実施

int fib_(int n){
    ++total_ops;
    if(n == 0 || n == 1) 
        return 1;
    else
        return fib(n-1) + fib(n-2);
}

モリンスデレイに位置し、memoize

int fib(int n) {
    static memoizer1<int,int> memo;
    return memo(fib_, n);
}

パーマリンクを示す出力 月codepad.org.呼び出しの数を測定し検証正.(挿入ユニットの試験はこちら---)

これだけmemoizesの入力機能一般化のための複数argsは変化を引数として残運動のリーダー.

Perlリmemoizationや取得します。のMemoizeモジュールは、perlの中核であり、信頼性の高い柔軟性と使いやすい.

この例からもmanpage:

# This is the documentation for Memoize 1.01
use Memoize;
memoize('slow_function');
slow_function(arguments);    # Is faster than it was before

きの追加や削除、カスタマイズmemoizationの機能 実行時間! ご提供できるコールバックのためのカスタム記念品計算である。

Memoize.pmものための施設との記念品のキャッシュ持続うにする必要はありませんの再充填ソッドを呼び出すたびにプログラム!

このドキュメンテーション http://perldoc.perl.org/5.8.8/Memoize.html

このブログ 汎用的なスカラ液に、4引数になります。

のアイデアを取得することも可能でmemoize機能の二つの入力パラメータ:

function memoize2 (f)
   local cache = {}
   return function (x, y)
             if cache[x..','..y] then
                return cache[x..','..y]
             else
                local z = f(x,y)
                cache[x..','..y] = z
                return z
             end
          end
end

このパラメータの順にするものであり、多様化するキャッシュアルゴリズムパラメータの順になるで語られることもありますが、こmemoizedの確率を高く、キャッシュヒットしたかが分別による前に、パラメータのチェックします。

ものでもありますので注意して機能できな収memoized.書いた memoize2 た場合、再帰的 ユークリッドアルゴリズム 見つける最大公約数がより高速化を実現。

function gcd (a, b) 
   if b == 0 then return a end
   return gcd(b, a%b)
end

としても gcd なに上手く対応memoization.の計算ではまとまっているものキャッシュアルゴリズムです。どんどん高まっており、大きな数字で終了しかなります。その後、キャッシュが非常に大きい。このアルゴリズムはその速させることができる。

再帰必要ない。N番目の三角数はn(n-1)/2、...

public int triangle(final int n){
   return n * (n - 1) / 2;
}

ないでくださいrecurseます。のいずれかをご利用x*(x+1)/2の数式または単に繰り返し処理を実行し、価値観やmemoizeとしてとても苦手なのでお願いします。

int[] memo = new int[n+1];
int sum = 0;
for(int i = 0; i <= n; ++i)
{
  sum+=i;
  memo[i] = sum;
}
return memo[n];
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top