2010-06-11 15 views
1

모든 가능한 크기의 모든 순열을 가져 오는 PHP 함수를 작성하려고합니다. 다양한 크기의다양한 크기의 순열

$my_array = array(1,1,2,3); 

가능한 순열 :

 
1 
1 // * See Note 
2 
3 
1,1 
1,2 
1,3 
// And so forth, for all the sets of size 2 
1,1,2 
1,1,3 
1,2,1 
// And so forth, for all the sets of size 3 
1,1,2,3 
1,1,3,2 
// And so forth, for all the sets of size 4 

참고 : 나는 예를 들어이 시작하는 가장 좋은 방법이 될 것이라고 생각이 중복의 여부를해도 상관하지 않습니다. 이 예제의 목적 상 향후 모든 중복은 생략되었습니다.

내가 PHP에서 지금까지 가지고

function getPermutations($my_array){ 

$permutation_length = 1; 
$keep_going = true;  

while($keep_going){ 
    while($there_are_still_permutations_with_this_length){ 
     // Generate the next permutation and return it into an array 
     // Of course, the actual important part of the code is what I'm having trouble with. 
    } 
    $permutation_length++; 
    if($permutation_length>count($my_array)){ 
     $keep_going = false; 
    } 
    else{ 
     $keep_going = true; 
     } 
} 

return $return_array; 

} 

그렇지 않은 경우, 나는이 결과 배열에 이미 있는지보고, 처음 n 요소를 따기, 배열을 셔플한다 생각하고, 할 수있는 가장 가까운 것은 그것을 추가하고 그 길이에 대해 수학적으로 가능한 순열이 없을 때 중단하십시오. 그러나 그것은 추악하고 자원 비효율적입니다.

모든 의사 코드 알고리즘은 크게 감사하겠습니다.


또한 슈퍼 듀서 (쓸데없는) 보너스 포인트의 경우, 함수로 단 1 개의 순열을 얻는 방법이 있습니까?하지만 다음 순열을 얻기 위해 모든 이전 순열을 다시 계산할 필요가 없도록 만드는 방법이 있습니까?

예를 들어 매개 변수 3을 전달하면 3 개의 순열이 완료되고 이전 3을 다시 실행하지 않고 숫자 4가 생성됩니다. (매개 변수를 전달하는 것은 필요하지 않으며 전역 또는 정적으로 추적 할 수 있습니다).

내가 질문하는 이유는 배열이 커질수록 가능한 조합의 수가 너무 많기 때문입니다. 단지 십여 개의 요소로 이루어진 하나의 작은 데이터 세트가 수조 개의 조합으로 빠르게 성장하고 있으며 수십억 개의 순열을 한 번에 메모리에 담아 PHP를 처리하고 싶지는 않습니다.

답변

2

죄송합니다. PHP 코드는 없지만 알고리즘을 제공 할 수 있습니다.

소량의 메모리로 수행 할 수 있으며 중복 코드는 신경 쓰지 않으므로 코드도 간단합니다.

먼저 가능한 모든 하위 집합을 생성하십시오.

하위 집합을 비트 벡터로 보면 집합과 이진수에 1-1이 대응한다는 것을 알 수 있습니다.

배열에 12 개의 요소가있는 경우 2^12 개의 하위 집합 (빈 집합 포함)이 있습니다.

하위 집합을 생성하려면 0부터 시작하여 2^12에 도달 할 때까지 계속 증가시킵니다. 각 단계에서 번호의 세트 비트를 읽어 어레이에서 적절한 서브 세트를 얻습니다.

일단 하나의 하위 집합을 얻으면 순열을 실행할 수 있습니다.

다음 순열 (배열 인덱스 중 요소 자체가 아님)은 http://www.de-brauwer.be/wiki/wikka.php?wakka=Permutations과 같은 사전 식 순서로 생성 될 수 있으며 최소 메모리로 수행 될 수 있습니다.

다음 두 가지를 조합하여 next_permutation 함수를 제공 할 수 있어야합니다.숫자를 전달하는 대신 이전 순열을 포함하는 12 개 요소의 배열을 전달할 수 있으며, 다음 하위 집합 등으로 이동해야하는지 여부에 대한 정보 (작은 메모리가 다시 있음)를 전달할 수 있습니다.

실제로 최소한의 메모리를 사용하는 매우 빠른 알고리즘을 찾을 수 있어야하고, next_permutation 유형 기능을 제공하고, 중복 코드를 생성하지 않아야합니다. 웹에서 다중 세트 순열/조합 생성을 검색하십시오.

희망이 있습니다. 행운을 빕니다!

1

최고의 기능은 php.net의 셔플 기능에 대한 의견에서 일부 사용자가 제공 한 기능입니다. 여기는 link입니다. 꽤 잘 작동합니다.

희망이 있습니다.

0

이 문제는 모든 순열에 색인을 제공하고 일정한 액세스 시간을 갖는 것으로 보입니다. 내가 일정한 시간 알고리즘을 생각할 수는 없지만 어쩌면이 것을 향상시킬 수 있습니다. 이 알고리즘은 시간 복잡성이 O (n)인데, 여기서 n은 집합의 길이입니다. 공간 복잡성은 O (1)로 축소 될 수 있어야한다.

집합이 1,1,2,3이고 우리가 10 번째 순열을 원한다고 가정합니다. 또한 집합의 각 요소를 0에서 3까지 색인 할 것임을 유의하십시오.이 순서는 단일 요소 순열이 먼저오고 두 요소가 차례로 오는 것을 의미합니다. 우리는 10 번째 순열을 완전히 결정할 수있을 때까지 숫자 10에서 뺄 것입니다.

첫 번째 요소는 단일 요소 순열입니다. 이 중 4 개가 있으므로 10에서 4를 1을 뺀 것으로 볼 수 있습니다. 우리는 6을 남겨두고 있으므로 두 요소 순열을 고려해야합니다. 이 중 12 개가 있으며, 이것을 6에서 3을 빼는 것으로 볼 수 있습니다. 두 번째로 3을 빼면 0이됩니다. 즉, 순열의 인덱스는 2 여야합니다. 3을 두 번 빼기), 0은 나머지이므로 0입니다. 따라서, 우리의 순열은 2,1이되어야합니다.

나누기 및 모듈러스가 도움이됩니다.

우리가 12 번째 순열을 찾고 있다면 2의 나머지가있는 경우를 생각해 볼 수 있습니다. 원하는 동작에 따라 순열 2,2가 유효하지 않을 수 있습니다. 그러나 색인 2와 2 (요소와 혼동하지 말 것)가 동일하다는 것을 쉽게 감지 할 수 있으므로 두 번째 요소는 3으로 부딪쳐 야합니다. 따라서 12 번째 순열은 쉽게 될 수 있습니다. 2,3로 계산됩니다.

가장 큰 혼란은 바로 인덱스와 요소 값이 일치한다는 것입니다. 내 알고리즘 설명이 그렇게 혼란스럽지 않기를 바랍니다. 그것이 그렇다면, 나는 당신의 모범이 아닌 다른 것을 사용하고 말로 바꾸십시오.

0

입력 : 순열 인덱스 k는 S.

설정, 색인

의사 코드 :

L = {S_1} 
for i = 2 to |S| do 
Insert S_i before L_{k % i} 
k <- k/i 
loop 
return L 

이 알고리즘은 중복 쉽게 작동하도록 변경 될 수있다.