2015-03-05 29 views
5

tôi đã tạo ra một hàm memoized của phiên bản đệ quy của fibonacci. Tôi sử dụng điều này làm ví dụ cho các loại chức năng khác có thể sử dụng tính năng ghi nhớ. thực hiện của tôi là xấu vì nếu tôi đưa nó vào trong thư viện, đó có nghĩa là biến global vẫn thấy ..Memoizing chức năng fibonacci trong php

Đây là đệ quy ban chức năng fibonacci:

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

và tôi sửa đổi nó vào một phiên bản được ghi nhớ:

$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; 
    } 
} 

Tôi cố tình không sử dụng phương pháp lặp lại khi triển khai mã fibonacci. Có cách nào tốt hơn để ghi nhớ hàm fibonacci trong php? Bạn có thể đề xuất tôi cải tiến tốt hơn không? Tôi đã nhìn thấy func_get_args()call_user_func_array như một cách khác nhưng tôi dường như không thể biết những gì là tốt hơn?

Vì vậy, câu hỏi chính của tôi là: Làm thế nào tôi có thể memoize chức năng fibonacci trong php đúng cách? hoặc cách tốt nhất trong memoizing chức năng fibonacci trong php là gì?

+0

qua '$ ghi nhớ 'như một tham số của' fibonacciMemo'? mặc dù là ít hơn nhiều thanh lịch :( –

+0

tốt, tôi nghĩ rằng đó là tốt quá, nhưng những gì tôi đang tìm kiếm là việc thực hiện tốt nhất cho đến nay cho chức năng này .. :) – catzilla

+0

Hãy nhìn vào [memoized] (https: // github Hàm .com/ihor/Nspl # memoizedfunction) từ [Nspl] (https: // github.com/ihor/Nspl) –

Trả lời

5

Vâng, Edd Mann cho thấy một cách tuyệt vời để thực hiện một chức năng memoize trong php trong His post

Đây là đoạn mã ví dụ (trên thực tế được lấy từ bài 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); 
}); 

Chú ý rằng global định nghĩa nó được thay thế nhờ chức năng clousure và hỗ trợ chức năng lớp học đầu tiên của PHP.

giải pháp khác:

Bạn có thể tạo một class chứa các thành viên như tĩnh: fibonnacciMemo$memo. Lưu ý rằng bạn không còn phải sử dụng $memo làm biến toàn cục, vì vậy nó sẽ không gây ra xung đột với các không gian tên khác. Dưới đây là ví dụ:

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) 

Sử dụng này, bạn tránh được việc sử dụng các global và cũng là vấn đề của làm sạch bộ nhớ cache. Mặc dù điều, $memo không phải là chủ đề tiết kiệm và các phím được lưu trữ không giá trị băm. Anyways, bạn có thể sử dụng tất cả các Utilites php memoize như memoize-php

+0

Vâng, tôi cũng thấy bài viết này, nó rất thông tin và chi tiết .. nhưng cách gọi hàm của nó là khác nhau: '$ fibonacci (10)' ... thực hiện điều này tạo nên sự thay đổi đáng kể hoặc sự khác biệt so với hàm gọi thông thường 'fibonacci (10)'? Và tôi tin một điều này thực sự không phải là memoization nhưng bộ nhớ đệm nói chung và cũng được hỗ trợ bởi một trong các chú thích trong bài bạn chia sẻ: cũng trên wiki: Mặc dù có liên quan đến bộ nhớ đệm, memoization đề cập đến một trường hợp cụ thể này tối ưu hóa, phân biệt nó với các hình thức lưu bộ nhớ đệm như đệm hoặc thay thế trang. – catzilla

+0

Không có sự khác biệt giữa '$ fibonacci (10)' và 'fibonacci (10)', cái đầu tiên là một đối tượng giá trị của nó là một hàm ẩn danh (không phải là khai báo hàm như hàm thứ hai). Tôi thấy rằng bình luận trên bài viết, và vấn đề là với bộ nhớ: * không có cách nào để xóa bộ nhớ cache * và * ăn nhiều bộ nhớ *. Mặc dù nó không phải là [đệm] (http://en.wikipedia.org/wiki/Data_buffer) cũng không phải [thay thế trang] (http://en.wikipedia.org/wiki/Page_replacement_algorithm). –

+0

Cảm ơn các thông tin, giải pháp thứ hai của bạn hoạt động tốt cho tôi .. Tôi chỉ bất tiện bằng cách sử dụng các phương pháp lớp tĩnh cho vấn đề fibonacci .. Nhưng tôi nghĩ rằng sử dụng tài sản tĩnh làm giảm đáng kể thời gian calcutation cho các cuộc gọi trước đó. giải pháp đầu tiên, tôi nghĩ rằng tôi sẽ cố gắng để kiểm tra và điều tra trên đó .. Tôi nghĩ rằng câu trả lời của bạn xứng đáng bỏ phiếu .. Cảm ơn anyways .. :) – catzilla

2

tôi nghĩ rằng ... này nên để cho memoize một 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]; 
} 

một số thử nghiệm

$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

Hi .. yes phương pháp này hoạt động quá .. và nó cũng có điểm tốt .. Nhưng vấn đề với điều này là bạn cần đưa tham số '$ arr' vào mọi khai báo của hàm' fib() '.. tốt nhất là' $ arr' sẽ bị ẩn trong khi sử dụng hàm 'fib() '.. – catzilla

+0

không thực sự, nếu bạn nhìn vào chữ ký chức năng mảng được khai báo ở đó, nếu bạn không vượt qua mảng để chức năng nó được reinitialized trong mọi cuộc gọi, vì vậy, nó được ẩn, nhưng, nếu bạn có kế hoạch sử dụng hàm nhiều lần, tốt, bạn có thể khai báo mảng của bạn d sử dụng nó, bạn thậm chí có thể, serialize nó, lưu trữ nó và tải lại nó sau này, sử dụng chức năng tương tự mà không sửa đổi ... –

+0

Xin chào, tôi đã thử phương pháp này và có, nó làm việc tuyệt vời .. có lẽ tôi hiểu lầm cách '$ tham số tính toán được sử dụng nhưng nó hoạt động rất tốt! cho đến nay, đây là hàm Fibonacci được ghi nhớ đơn giản nhất mà tôi gặp phải ..! Tôi sẽ cố gắng điểm chuẩn chức năng này chống lại việc thực hiện khác của fibonacci và so sánh kết quả ... cảm ơn câu trả lời của bạn! – catzilla