我正在尝试创建一个能够通过行向量并输出n的可能组合的函数,选择k 而不递归。
例如:3选择[a,b,c]输出[a,b; A,C; B,C]
我发现了这个:How to loop through all the combinations of e.g. 48 choose 5,它显示了如何为固定的n选择k做这个:https://codereview.stackexchange.com/questions/7001/generating-all-combinations-of-an-array显示了如何获得所有可能的组合。使用后面的代码,我设法在matlab中创建一个非常简单和低效的函数,它返回结果:
function [ combi ] = NCK(x,k)
%x - row vector of inputs
%k - number of elements in the combinations
combi = [];
letLen = 2^length(x);
for i = 0:letLen-1
temp=[0];
a=1;
for j=0:length(x)-1
if (bitand(i,2^j))
temp(k) = x(j+1);
a=a+1;
end
end
if (nnz(temp) == k)
combi=[combi; derp];
end
end
combi = sortrows(combi);
end
这适用于非常小的向量,但我需要能够使用长度至少为50的向量。我已经找到了许多如何以递归方式执行此操作的示例,但是有没有一种有效的方法可以在没有递归的情况下执行此操作,并且仍然能够执行可变大小的向量和ks?
答案 0 :(得分:2)
这是一个简单的函数,它会对k
个和n-k
个零进行排列,并返回nchoosek
的下一个组合。它完全独立于n
和k
的值,直接从输入数组中获取值。
function [nextc] = nextComb(oldc)
nextc = [];
o = find(oldc, 1); %// find the first one
z = find(~oldc(o+1:end), 1) + o; %// find the first zero *after* the first one
if length(z) > 0
nextc = oldc;
nextc(1:z-1) = 0;
nextc(z) = 1; %// make the first zero a one
nextc(1:nnz(oldc(1:z-2))) = 1; %// move previous ones to the beginning
else
nextc = zeros(size(oldc));
nextc(1:nnz(oldc)) = 1; %// start over
end
end
(请注意,仅当您希望组合从最后一个组合环绕到第一个组合时,才需要else
子句。)
如果您使用例如:
调用此函数A = [1 1 1 1 1 0 1 0 0 1 1]
nextCombination = nextComb(A)
输出将是:
A =
1 1 1 1 1 0 1 0 0 1 1
nextCombination =
1 1 1 1 0 1 1 0 0 1 1
然后,您可以将其用作字母表中的掩码(或您想要组合的任何元素)。
C = ['a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k']
C(find(nextCombination))
ans = abcdegjk
此排序中的第一个组合是
1 1 1 1 1 1 1 1 0 0 0
,最后一个是
0 0 0 1 1 1 1 1 1 1 1
以编程方式生成第一个组合,
n = 11; k = 8;
nextCombination = zeros(1,n);
nextCombination(1:k) = 1;
现在您可以遍历这些组合(或者您愿意等待的许多组合):
for c = 2:nchoosek(n,k) %// start from 2; we already have 1
nextCombination = nextComb(A);
%// do something with the combination...
end
上面的示例:
nextCombination = [1 1 0];
C(find(nextCombination))
for c = 2:nchoosek(3,2)
nextCombination = nextComb(nextCombination);
C(find(nextCombination))
end
ans = ab
ans = ac
ans = bc
注意:我已经更新了代码;我忘了包含该行来将所有在交换数字之前发生的1移动到数组的开头。当前代码(除了上面更正)还在ideone here上。 4 choose 2
的输出为:
allCombs =
1 2
1 3
2 3
1 4
2 4
3 4