2015-03-05 17 views
5

Ho creato una funzione memoized della versione ricorsiva di Fibonacci. Lo uso come esempio per altri tipi di funzioni che utilizzerebbero la memoizzazione. mia implementazione è male perché se includo in una libreria, che significa che la variabile global è ancora visto ..Memoizing funzione fibonacci in php

Questo è l'originale ricorsiva funzione di Fibonacci:

function fibonacci($n) { 
    if($n > 1) { 
    return fibonacci($n-1) + fibonacci($n-2); 
    } 
    return $n; 
} 

e ho modificato per un versione memoized:

$memo = array(); 
function fibonacciMemo($n) { 
    global $memo; 
    if(array_key_exists($n, $memo)) { 
    return $memo[$n]; 
    } 
    else { 
    if($n > 1) { 
     $result = fibonacciMemo($n-1) + fibonacciMemo($n-2); 
     $memo[$n] = $result; 
     return $result; 
    } 
    return $n; 
    } 
} 

ho volutamente non ha utilizzato il metodo iterativo nell'attuazione Fibonacci. C'è qualche modo migliore per memorizzare la funzione Fibonacci in PHP? Puoi suggerirmi miglioramenti migliori? Ho visto func_get_args() e call_user_func_array come un altro modo, ma non riesco a capire cosa è meglio?

Quindi la mia domanda principale è: Come posso memorizzare correttamente la funzione Fibonacci in PHP? o Qual è il modo migliore per memorizzare la funzione Fibonacci in PHP?

+0

passando '$ memo 'come parametro di' fibonacciMemo'? anche se è molto meno elegante :( –

+0

beh, penso che sia anche possibile, ma quello che sto cercando è la migliore implementazione finora per questa funzione .. :) – catzilla

+0

Dai un'occhiata a [memoized] (https: // github .com/ihor/Nspl # memoizedfunction) funzione da [Nspl] (https: // github.com/ihor/Nspl) –

risposta

5

Beh, Edd Mann mostra un ottimo modo per implementare una funzione memoize in php in His post

Ecco il codice di esempio (in realtà tratto da post di Edd Mann):

$memoize = function($func) 
{ 
    return function() use ($func) 
    { 
     static $cache = []; 

     $args = func_get_args(); 

     $key = md5(serialize($args)); 

     if (! isset($cache[$key])) { 
      $cache[$key] = call_user_func_array($func, $args); 
     } 

     return $cache[$key]; 
    }; 
}; 

$fibonacci = $memoize(function($n) use (&$fibonacci) 
{ 
    return ($n < 2) ? $n : $fibonacci($n - 1) + $fibonacci($n - 2); 
}); 

Si noti che il La definizione global è stata sostituita grazie alla funzione clousure e al supporto delle funzioni di prima classe di PHP.

Altro soluzione:

È possibile creare un class contenente come membri statici: fibonnacciMemo e $memo. Si noti che non è più necessario utilizzare $memo come variabile globale, quindi non darà alcun conflitto con altri spazi dei nomi. Ecco l'esempio:

class Fib{ 
    //$memo and fibonacciMemo are static members 
    static $memo = array(); 
    static function fibonacciMemo($n) { 
     if(array_key_exists($n, static::$memo)) { 
     return static::$memo[$n]; 
     } 
     else { 
     if($n > 1) { 
      $result = static::fibonacciMemo($n-1) + static::fibonacciMemo($n-2); 
      static::$memo[$n] = $result; 
      return $result; 
     } 
     return $n; 
     } 
    } 
} 

//Using the same method by Edd Mann to benchmark 
//the results 

$start = microtime(true); 
Fib::fibonacciMemo(10); 
echo sprintf("%f\n", microtime(true) - $start); 
//outputs 0.000249 

$start = microtime(true); 
Fib::fibonacciMemo(10); 
echo sprintf("%f\n", microtime(true) - $start); 
//outputs 0.000016 (now with memoized fibonacci) 

//Cleaning $memo 
Fib::$memo = array(); 
$start = microtime(true); 
Fib::fibonacciMemo(10); 
echo sprintf("%f\n", microtime(true) - $start); 
//outputs 0.000203 (after 'cleaning' $memo) 

Usando questo, si evita l'uso di global e anche il problema della pulizia della cache . Anche se, $memo non è thread risparmi e le chiavi memorizzate non sono valori hash. In ogni modo, è possibile utilizzare tutti i programmi di utilità php Memoize come memoize-php

+0

Sì, ho visto anche questo post, è molto informativo e dettagliato .. ma il modo in cui chiama la funzione è diverso: '$ fibonacci (10)' ... questo fa un cambiamento significativo o una differenza rispetto alla solita funzione chiamata 'fibonacci (10)'? E credo che questo non è davvero Memoizzazione ma la cache in generale e supportata anche da uno dei commenti nel post che hai condiviso: anche sul wiki: Anche se correlato alla cache, Memoizzazione si riferisce a un caso specifico di questo ottimizzazione, distinguendolo dalle forme di memorizzazione nella cache come il buffering o la sostituzione delle pagine. – catzilla

+0

Non c'è differenza tra '$ fibonacci (10)' e 'fibonacci (10)', il primo è un oggetto che il suo valore è una funzione anonima (non una dichiarazione di funzione come la seconda). Ho visto quel commento sul post, e il problema è con la memoria: * non c'è modo di svuotare la cache * e * ha consumato molta memoria *. Sebbene non sia né [buffering] (http://en.wikipedia.org/wiki/Data_buffer) né [sostituzione della pagina] (http://en.wikipedia.org/wiki/Page_replacement_algorithm). –

+0

Grazie per le informazioni, la tua seconda soluzione funziona bene per me .. Sono solo scomodo usando i metodi di classi statiche per il problema di Fibonacci ... Ma penso che l'uso della proprietà statica riduca notevolmente il tempo di calcolo per le chiamate precedenti per quello .. E per il prima soluzione, penso che proverò a testare e indagare su quello .. Penso che la tua risposta meriti il ​​voto .. Grazie comunque .. :) – catzilla

2

penso ... questo dovrebbe ad ad Memoize un Fibonacci:

function fib($n, &$computed = array(0,1)) { 
    if (!array_key_exists($n,$computed)) { 
     $computed[$n] = fib($n-1, $computed) + fib($n-2, $computed); 
    } 
    return $computed[$n]; 
} 

qualche prova

$arr = array(0,1); 
$start = microtime(true); 
fib(10,$arr); 
echo sprintf("%f\n", microtime(true) - $start); 
//0.000068 

$start = microtime(true); 
fib(10,$arr); 
echo sprintf("%f\n", microtime(true) - $start); 
//0.000005 

//Cleaning $arr 
$arr = array(0,1); 
$start = microtime(true); 
fib(10,$arr); 
echo sprintf("%f\n", microtime(true) - $start); 
//0.000039 
+0

Ciao .. sì, questo metodo funziona anche .. e ha anche dei buoni punti .. ma il problema con questo è che è necessario includere il parametro '$ arr 'in ogni dichiarazione della funzione' fib() '.. è meglio che' $ arr' debba essere nascosto durante l'uso della funzione 'fib() '.. – catzilla

+0

non proprio, se si guarda la firma della funzione la matrice è dichiarata lì, se non si passa la matrice alla funzione viene reinizializzata in ogni chiamata, quindi, è nascosta, ma, se si prevede di usa la funzione più di una volta, beh, puoi dichiarare il tuo array a Usalo, puoi persino, serializzarlo, memorizzarlo e ricaricarlo più tardi, usando la stessa funzione senza modifiche ... –

+0

Ciao, ho provato questo metodo e sì, ha funzionato benissimo ... forse ho frainteso il modo in cui $ viene utilizzato il parametro calcolato, ma ha funzionato benissimo! finora, questa è la funzione di Fibonacci memoizzata più semplice che ho incontrato ..! Proverò a confrontare questa funzione con altre implementazioni di Fibonacci e confrontare i risultati ... grazie per la tua risposta! – catzilla