【发布时间】:2018-07-11 13:47:13
【问题描述】:
我基本上需要 C 中以下 Python itertools 命令的等效结果:
a = itertools.permutations(range(4),2))
目前我的流程涉及首先从 10 个元素中“选择”5 个元素,然后为这 5 个元素生成排列,如图所示 here
这种方法的问题在于输出的顺序。我需要它是(a),而我得到的是(b),如下所示。
a = itertools.permutations(range(4),2)
for i in a:
print(i)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 2)
(1, 3)
(2, 0)
(2, 1)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
b = itertools.combinations(range(4),2)
for i in b:
c = itertools.permutations(i)
for j in c:
print(j)
(0, 1)
(1, 0)
(0, 2)
(2, 0)
(0, 3)
(3, 0)
(1, 2)
(2, 1)
(1, 3)
(3, 1)
(2, 3)
(3, 2)
我正在使用的另一种方法如下
void perm(int n, int k)
{
bool valid = true;
int h = 0, i = 0, j = 0, limit = 1;
int id = 0;
int perm[10] = { 0,0,0,0,0,0,0,0,0,0 };
for (i = 0; i < k; i++)
limit *= n;
for (i = 0; i < limit; i++)
{
id = i;
valid = true;
for (j = 0; j < k; j++)
{
perms[j] = id % n;
id /= n;
for (h = j - 1; h >= 0; h--)
if (perms[j] == perms[h])
{
valid = false; break;
}
if (!valid) break;
}
if (valid)
{
for (h = k - 1; h > 0; h--)
printf("%d,", perms[h]);
printf("%d\n", perms[h]);
count++;
}
}
}
内存是我的限制,所以我不能无限期地存储排列。性能需要比上面的算法好,当n是50,k是10时,我最终会遍历更多无效组合(60+%)
我知道Heap's algorithm 用于在适当的位置生成排列,但它再次生成整个数组而不是我需要的 k of n。
问题。
- 有没有比迭代 n^k 次更好的方法?
- 我可以创建一个惰性迭代器,在给定当前排列的情况下移动到下一个排列吗?
EDIT 这不是 std::next_permutation 实现的副本,因为它将置换整个输入范围。 我已经明确提到我需要 n 个排列中的 k 个。即,如果我的范围是 10,我希望所有长度(k)的排列都说 5,当长度或排列与输入范围的长度相同时,std::next_permutation 起作用
更新 这是一个丑陋的递归 NextPerm 解决方案,它比我的旧解决方案快 4 倍,并且提供增量 nextPerm,就像 Python 惰性迭代器一样。
int nextPerm(int perm[], int k, int n)
{
bool invalid = true;
int subject,i;
if (k == 1)
{
if (perm[0] == n - 1)
return 0;
else { perm[0]=perm[0]+1; return 1; }
}
subject = perm[k - 1]+1;
while (invalid)
{
if (subject == n)
{
subject = 0;
if (!nextPerm(perm, k - 1, n))
return 0;
}
for (i = 0; i < k-1; i++)
{
if (perm[i] != subject)
invalid = false;
else
{
invalid = true;subject++; break;
}
}
}
perm[k - 1] = subject;
return 1;
}
int main()
{
int a, k =3 ,n = 10;
int perm2[3] = { 0,1,2}; //starting permutation
unsigned long long count = 0;
int depth = 0;
do
{
for (a = 0; a < k - 1; a++)
printf("%d,", perm2[a]);
printf("%d\n", perm2[k - 1]);
count++;
}
while (nextPerm(perm2,k,n));
printf("\n%llu", count);
getchar();
return 0;
}
【问题讨论】:
-
@anatolyg 我需要从 n 个排列中选择 k 个,该链接只排列一个完整的范围
-
除了使用
std::next_permutation的代码,this algorithm 是您正在寻找的。该算法是对以下问题的回答:Generating N choose K Permutations in C++。关键是在每次排列后将元素从k+1反转为n,以避免重复排列。 -
@Emil no,它的工作原理是选择 k 然后排列那些 k,排列的顺序与我想要的输出不同。查看选择 k 和 permute 输出的行为差异以及我想要的输出。还特别需要在C中
-
我明白你在说什么。这实际上让我想起了堆的算法。
-
@Emil 是的,在我的问题中也有联系
标签: c permutation itertools heaps-algorithm