如何降低循环速度

时间:2010-06-24 12:26:43

标签: php for-loop

我面临一个大问题。我需要生成精确的7个数字组合,并且我使用7个forloops编写了一个代码,并且它的工作正常,数量非常少。请检查附件,这样你就会非常清楚我需要什么。 请提供PHP结果。

<?php
// I need the combinations for this commented numbers   
// 1, 7, 13, 19, 25, 31, 2, 8, 14, 20, 26, 32, 3, 9, 15, 
// 21, 27, 33, 4, 10, 16, 22, 28, 34, 5, 11, 17, 23, 29,
// 35, 6, 12, 18, 24, 30, 36
$string=array(1,7,13,19,25,31,2,8,14,20,26,32,3,9,15,21,27,33,4,10,16,22,28,34);
$len=count($string);
$c=0;
ob_start();
for ($e = 0; $e < $len - 6; $e++)
{
   for ($f = $e+1; $f < $len - 5; $f++)
   {
       for ($g = $f+1; $g < $len - 4; $g++)
       {
           for ($h = $g+1; $h < $len - 3; $h++)
           { 
               for ($i = $h+1; $i < $len - 2; $i++)
               {
                   for ($j = $i + 1; $j < $len - 1; $j++)
                   {
                        for ($k = $j + 1; $k < $len; $k++)
                        {
                             $c++;
                             $output[] = $string[$e] . "," . 
                                         $string[$f] . "," . 
                                         $string[$g] . "," .  
                                         $string[$h] . "," . 
                                         $string[$i] . "," . 
                                         $string[$j] . "," . 
                                         $string[$k];
                             ob_flush();
                        }
                        ob_flush();
                   }
                   ob_flush();
               }
               ob_flush();
           }
           ob_flush();
   }
   ob_flush();
}
ob_flush();
}
echo count($output);
?>

我需要输出相同,如下所述。 输出:

passed numbers $string=array(1, 7, 13, 19, 25, 31, 2, 8, 14) and the out put is below
count of combinations = 36
Array
(
    [0] => 1,7,13,19,25,31,2
    [1] => 1,7,13,19,25,31,8
    [2] => 1,7,13,19,25,31,14
    [3] => 1,7,13,19,25,2,8
    [4] => 1,7,13,19,25,2,14
    [5] => 1,7,13,19,25,8,14
    [6] => 1,7,13,19,31,2,8
    [7] => 1,7,13,19,31,2,14
    [8] => 1,7,13,19,31,8,14
    [9] => 1,7,13,19,2,8,14
    [10] => 1,7,13,25,31,2,8
    [11] => 1,7,13,25,31,2,14
    [12] => 1,7,13,25,31,8,14
    [13] => 1,7,13,25,2,8,14
    [14] => 1,7,13,31,2,8,14
    [15] => 1,7,19,25,31,2,8
    [16] => 1,7,19,25,31,2,14
    [17] => 1,7,19,25,31,8,14
    [18] => 1,7,19,25,2,8,14
    [19] => 1,7,19,31,2,8,14
    [20] => 1,7,25,31,2,8,14
    [21] => 1,13,19,25,31,2,8
    [22] => 1,13,19,25,31,2,14
    [23] => 1,13,19,25,31,8,14
    [24] => 1,13,19,25,2,8,14
    [25] => 1,13,19,31,2,8,14
    [26] => 1,13,25,31,2,8,14
    [27] => 1,19,25,31,2,8,14
    [28] => 7,13,19,25,31,2,8
    [29] => 7,13,19,25,31,2,14
    [30] => 7,13,19,25,31,8,14
    [31] => 7,13,19,25,2,8,14
    [32] => 7,13,19,31,2,8,14
    [33] => 7,13,25,31,2,8,14
    [34] => 7,19,25,31,2,8,14
    [35] => 13,19,25,31,2,8,14
)

5 个答案:

答案 0 :(得分:8)

function factorial($factVal) {
    $factorial = 1;
    while ($factVal > 1) {
        $factorial *= $factVal--;
    }
    return $factorial ;
}

function permutations($numObjs,$numInSet) {
    return round(factorial($numObjs) / factorial($numObjs - $numInSet));
}

function combinations($numObjs,$numInSet) {
    return round(factorial($numObjs) / factorial($numObjs - $numInSet)) / factorial($numInSet);
}


$string=array(1,7,13,19,25,31,2,8,14,20,26,32,3,9,15,21,27,33,4,10,16,22,28,34); 
echo 'Number of Combinations = '.combinations(count($string),7).'<br />';
echo 'Number of Permutations = '.permutations(count($string),7).'<br />';

答案 1 :(得分:0)

尽管我无法向您提供完整的代码,但我可以告诉您,即使是更高的组合,我也已经完成了此操作,您需要使用 RECURSIVE FUNCTIONS 而不是使用嵌套循环。< / p>

递归函数使您可以灵活地超越7。

NLV

答案 2 :(得分:0)

如果你真的想要这些组合,你可以做这样的事情......

  • 注1:这只会为您提供有序的结果,而不会给您排列。
  • 注意2:如果您只需要计数,请使用Mark的答案。
  • 注3:根本没有测试,因此可能存在一些偏移错误等。

这里是:

function combinations($set,$length) {
  $combinations = array();

  for($i = 0, $n = count($set); $i <= ($n - $length); $i++) {
    $combination = array();
    $combination[] = $set[$i];

    if($length > 1) {
      $combination = array_merge(
        $combination,
        combinations(array_slice($set,1+$i), $length-1)
      );
    }

    $combinations[] = $combination;
  }

  return $combinations;
}

$allCombinations = combinations($allYourNumbers, 7);

编辑将参数的顺序更改为array_slice

答案 3 :(得分:0)

我不确定我是否理解你的问题,但我认为你想要在数组中生成所有可以从“从左到右”获得的数字组合,即如果我们采用排序的数组(让我们说从1到50)并且第一个数字已经是4,那么所有后面的数字应该大于4,如果第二个数字是12,所有后面的数字应该大于12,依此类推。

所以事实是这样的数字组合的数量是如此之大,无论你使用什么算法 - 在某个数组大小,它都是不易处理的,即真正生成所有数字需要太长时间,因为它们太多了。

如果您从m个号码中取出n个号码,则binomial(n,m)有多种可能性(binomial(n,m)是二项式系数nm)。

因此,特别是对于您的情况binomial(n,7)很有意思。然而,二项式系数是一个非常快速增长的函数。即如果你把参数放大一点,结果会大得多。

binomial(9,7) = 36
binomial(10,7) = 120
binomial(11,7) = 330
binomial(12,7) = 792
...
binomial(15,7) = 6435
binomial(20,7) = 77520
binomial(30,7) = 2035800

你看,对于30个数字,已经存在很多可能性,并且需要时间来枚举所有这些可能性。所以,你的算法可能有多聪明,在数组大小的某个点上它只能因为大量的可能性而放弃。

我在C中写了一个小程序:

#define PRINTITEMS 0

#include <stdio.h>
#include <stdlib.h>

typedef struct _comb{
  int x1;
  int x2;
  int x3;
  int x4;
  int x5;
  int x6;
  int x7;
} comb;

void generateAll7Possibilities(int* a,int n, comb* target){
  int i1, i2, i3, i4, i5, i6, i7;
  int c = 0;
  for (i1=0; i1<n-6; i1++){
    for (i2=i1+1; i2<n-5; i2++){
      for (i3=i2+1; i3<n-4; i3++){
        for (i4=i3+1; i4<n-3; i4++){
          for (i5=i4+1; i5<n-2; i5++){
            for (i6=i5+1; i6<n-1; i6++){
              for (i7=i6+1; i7<n; i7++){
            target[c].x1=a[i1];
            target[c].x2=a[i2];
            target[c].x3=a[i3];
            target[c].x4=a[i4];
            target[c].x5=a[i5];
            target[c].x6=a[i6];
            target[c].x7=a[i7];
            if (PRINTITEMS){
              printf("%d %d %d %d %d %d %d\n", target[c].x1, target[c].x2, target[c].x3, target[c].x4, target[c].x5, target[c].x6, target[c].x7);
            }
              }
            }
          }
        }
      }
    }
  }
}


int main(){
  printf("This is enumerator\n");
  int array[36];
  int i;
  for (i=0; i<36; ++i){
    array[i]=i;
    printf("%d\n",array[i]);
  }
  printf("Starting generation");
  comb* target= malloc(sizeof(comb)*8347680);
  generateAll7Possibilities(array,36,target);
  printf("Generation finished");
}

如果打印值,上述程序运行正常。但是,一旦开始打印值,就没有机会完成。

所以我建议你尝试删除输出并生成所有可能的组合。

答案 4 :(得分:0)

这是一种替代方法(不是在PHP中),它允许确定组合集中任意组合的组合。

在组合集中,存在有限数量的不同组合。这意味着可以为每个组合分配序列号,并且可以将序列号转换为组合集。关键部分是以下例程.... get_array_offset()。

int get_array_offset (x, y) {
    int  offset = 0;
    while (1) {
        choices = choose (x, y);   // x choose y
        if (sequence <= choices)
            break;
        sequence -= choices;
        x--;
        offset++;
    }
    return offset;
}

让我们假设我们正在处理一个24选择7组合,并且我们所有的值都存储在数组中

valueArray[24] = { ....};

对于给定的序列号,要找到组合中的第一项是......

sequence = ...;                     // sequence number in combination set
index = 0;
offset = get_array_offset (24 - 1 - index, 7 - 1);
index += offset;
/* valueArray[index] <--- first item in the combination */

offset = get_array_offset (24 - 2 - index, 7 - 2);
index += offset;
/* valueArray[index] <--- second item in the combination */

offset = get_array_offset (24 - 3 - index, 7 - 3);
index += offset;
/* valueArray[index] <--- third item in the combination */

... And so forth (fits nicely into a loop) ...

我已经实施了这样的算法已经有一段时间了。要点就在那里,但我可能会有一个错误的错误。类似的逻辑可以适用于排列问题。

希望这有帮助。