2009-09-08 2 views
1

먼저 : 위키 백과의 문제 이름은 "집합의 정렬 된 파티션"입니다.PHP : 캐싱 순서화 정수 알고리즘

나는 가능한 파티션을 계산하는 알고리즘을 가지고 있습니다. 속도를 높이기 위해 캐시를 사용합니다.

function partition($intervalSize, $pieces) { 
    // special case of integer partitions: ordered integer partitions 
    // in Wikipedia it is: ordered partition of a set 
    global $partition_cache; 
    // CACHE START 
    $cacheId = $intervalSize.'-'.$pieces; 
    if (isset($partition_cache[$cacheId])) { return $partition_cache[$cacheId]; } 
    // CACHE END 
    if ($pieces == 1) { return 1; } 
    else { 
     $sum = 0; 
     for ($i = 1; $i < $intervalSize; $i++) { 
      $sum += partition(($intervalSize-$i), ($pieces-1)); 
     } 
     $partition_cache[$cacheId] = $sum; // insert into cache 
     return $sum; 
    } 
} 
$result = partition(8, 4); 

또한 이러한 가능한 파티션 목록을 보여주는 또 다른 알고리즘이 있습니다. 그러나 아직 캐시를 사용하지 않으며 그래서 아주 느린 :

function showPartitions($prefix, $start, $finish, $numLeft) { 
    global $partitions; 
    if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben 
     $gruppen = split('\|', $prefix); 
     $partitions[] = $gruppen; 
    } 
    else { 
     if (strlen($prefix) > 0) { // nicht | an Anfang setzen sondern nur zwischen Gruppen 
      $prefix .= '|'; 
     } 
     for ($i = $start + 1; $i <= $finish; $i++) { 
      $prefix .= chr($i+64); 
      showPartitions($prefix, $i, $finish, $numLeft - 1); 
     } 
    } 
} 
$result = showPartitions('', 0, 8, 4); 

그래서 나는 두 가지 질문이 있습니다 1) 두 번째 알고리즘 캐시를 구현할 수를 너무? 그렇다면이 일을 도와 주시겠습니까? 2) 두 번째 알고리즘의 결과를 문자열 대신 구조화 된 배열에 쓸 수 있습니까?

도와 주시면 감사하겠습니다. 대단히 감사드립니다!

추신 : 두 가지 기능, Simonn과 Dan Dyer에게 감사드립니다.

답변

1
  1. 아니요, 실제로 동일한 계산을 두 번 수행하지 않으므로 캐시가 도움이 될 것이라고 생각하지 않습니다. showPartitions() 호출마다 다른 매개 변수가 있으며 다른 결과가 생성됩니다.
  2. 물론 가능합니다. 기본적으로 정수를 가리키는 중첩 배열의 다른 레벨을 사용하여 파이프 문자로 구분 된 문자열을 대체합니다. (대신에 "A | B | C"당신은 array(array(1), array(2), array(3))을해야합니다.)

같은 showPartitions()을 변경해보십시오 : $ 접두사, 호출에 대해 빈 문자열을 호출하는 대신

if ($numLeft == 0 && $start == $finish) { // wenn eine Partition fertig ist dann in Array schreiben 
    $partitions[] = $prefix; 
} 
else { 
    $prefix[] = array(); 
    for ($i = $start + 1; $i <= $finish; $i++) { 
     $prefix[count($prefix) - 1][] = $i; 
     showPartitions($prefix, $i, $finish, $numLeft - 1); 
    } 
} 

및 그것은 빈 배열 :

showPartitions(array(), 0, 8, 4); 
+0

고맙습니다. – caw

1

오프 주제 : 나는 조금 더 빨리 첫 번째 기능을 다시 작성했습니다.

function partition($intervalSize, $pieces) { 
    // special case of integer partitions: ordered integer partitions 
    // in Wikipedia it is: ordered partition of a set 

    // CACHE START 
    static $partition_cache = array(); 
    if (isset($partition_cache[$intervalSize][$pieces])) { 
     return $partition_cache[$intervalSize][$pieces]; 
    } 
    // CACHE END 

    if ($pieces === 1) { 
     return 1; 
    } 
    if ($intervalSize === 1) { 
     return 0; 
    } 

    $sum = 0; 
    $subPieces = $pieces - 1; 
    $i = $intervalSize; 
    while (--$i) { 
      $sum += partition($i, $subPieces); 
    } 
    $partition_cache[$intervalSize][$pieces] = $sum; // insert into cache 
    return $sum; 
} 
+0

고맙습니다, OIS! :) 귀하의 기능은 "조금 더 빠릅니다". 테스트를 마친 후에도 이전 기능보다 43 배 빠릅니다! 나는 이것을 믿을 수 없다. 어떻게 한거야? 동안보다 빠르다? 배열 선언 앞에 "정적"이라고 쓰여진 이유는 무엇입니까? – caw

+0

함수 자체에서 배열 선언 대신 전역 변수를 사용하면 이전 함수보다 2 배 빠릅니다. 따라서 좋은 성능은 주로이 어레이에 달려 있습니다. 왜 이런거야? – caw

+0

@ marco92w : static은 모든 함수 (또는 클래스의 클래스 인스턴스)에 대해 "저장 됨"을 의미합니다. = array() 초기화를 제거하지 않고 전역 변수를 전역 변수로 변경하면 각 재귀가 발생할 때마다 빈 배열로 변수를 덮어 쓰기 때문에 기본적으로 캐시 기능이 제거됩니다.캐시 변수에 액세스 할 수있게하려면이 함수를 클래스의 정적 메소드 부분으로 만들고 캐시는 클래스의 정적 변수로 만들어야합니다. – OIS