如何从可变数量的可变长度数组中找到由1个元素组成的所有排列?

时间:2010-02-03 02:43:54

标签: algorithm permutation

我有一个数组U的数组D,其长度各不相同。我需要能够返回数组索引的所有排列,这些排列将选择由每个集合中的1个元素组成的不同排列。我还要求将此算法表示为仅记住最后一个排列的对象,并使用get_next方法返回下一个排列。

例如,U = [array_of_size_n1, array_of_size_n2, array_of_size_n3]会有n1*n2*n3个排列,每个 3 元素都很长。

修改:套数也有所不同。

4 个答案:

答案 0 :(得分:2)

如果你正在使用python,这是标准库的一部分:itertools.product。但假设你不是,这是伪代码版本。

// Create an initialised array of indexes.
int[] index0(arrays) {
    // We require all arrays to be non-empty.
    for a in arrays {
        assert len(a) != 0;
    }
    return new int[len(arrays)];
}

// Increment the indices. Returns false when the indices wrap round to the start.
bool next_index(indices, arrays) {
    for (i = len(indices) - 1; i >= 0; --i) {
        indices[i] += 1
        if indices[i] < len(arrays[i]) {
            return true;
        }
        indices[i] = 0;
    }
    return false;
}

你可以像这样使用它(假设你的数组都不是空的)。此示例打印出数组中每个元素的组合。

indices = index0(arrays); 
{
    for (i = 0; i < len(arrays); ++i) {
        print arrays[i][indices[i]];
    }
    print
} while next_index(indices);

答案 1 :(得分:1)

你可以在每个阵列中为你的个人位置保留一个计数器。在你的get_next方法中,将计数器增加一个,然后按数组的长度进行修改。然后,每当前一个计数器翻转为0时,只需增加下一个计数器;

if (pos3 == array_of_size_n3 -1)
{
   if (pos2 == size_of_array_2 -1)
   {
       pos1 = (pos1 + 1) % size_of_array_1

   }
   pos2 = (pos2 + 1) % size_of_array_2
}
pos3 = (pos3 + 1) % size_of_array_3

print array1[pos1], array2[pos2], array3[pos3]

编辑:如果数组的数量不同,请将位置变量保存在数组中。实际上,无论如何这可能会更好。这样你可以像引用数组本身一样引用pos变量。

答案 2 :(得分:0)

那么......这个不是直截了当的呢?

你想要一个迭代器。您希望它迭代最后一个数组。当它到达该数组的末尾时,在第二个数组中递增其当前位置,然后返回到最后一个数组的开头。

psuedocode使用C#s yield return语法:

foreach n1 in a1
    foreach n2 in a2
        foreach n3 in a3
            yield return (n1, n2, n3)

编辑:如果集的数量不同,您可以使用某种形式的递归:

function next(list)
    firstArray = list.first
    iterator = iterator(list.rest)
    if !iterator
        foreach i in firstArray
            yield return i
    else
        foreach i in firstArray
            while (iterator.hasNext)
                yield return (i, iterator.next)

考虑传入长度为1的列表时的行为,然后考虑长度为2的列表的行为,并确保它确实可以正常工作。

答案 3 :(得分:0)

为了解决Anon所说的问题,你不要只是循环它们。您在类中维护状态,以便了解每个数组的最后一个索引。逻辑是相同的,但您不会在连续循环中运行。伪代码逻辑将是:

get_next()
{
  oldn3 = this.n3;
  oldn2 = this.n2;
  oldn1 = this.n1;

  if(this.n3 == this.a3.Count)
     this.n3 = 0;
  else
     this.n3++;

  if(oldn3 > this.n3)
    if(this.n2 == this.a2.Count)
      this.n2 = 0;
    else
      this.n2++;

  if(oldn2 > this.n2)
    if(this.n1 == this.a1.Count)
      this.n1 = 0;
    else
      this.n1++;

  if(oldn1 > this.n1)
    return NO_MORE_PERMS;

  return [n1,n2,n3];  
}

getCurrent()
{
  return [n1,n2,n3];
}