Algorithm 什么';生成n-集的所有k-子集的最有效算法是什么?

Algorithm 什么';生成n-集的所有k-子集的最有效算法是什么?,algorithm,reference,subset,combinatorics,Algorithm,Reference,Subset,Combinatorics,我们得到了一组n个元素,我们想要生成这个集合中的所有k-子集。例如,如果S={1,2,3}和k=2,那么答案将是{1,2},{1,3},{2,3}(顺序不重要) 一个n-集(定义:-)有{n-choose k}k-子集,即O(n^k)(尽管这不是紧的)。显然,解决这个问题的任何算法都必须在时间ω({n选择k})内运行 目前已知的解决这个问题的最快算法是什么?{n choose k}的下界真的可以实现吗(这样我们就有了一个基本上最优的算法)?这可以使用递归规则来计算: kSubsets(S, k)

我们得到了一组n个元素,我们想要生成这个集合中的所有k-子集。例如,如果S={1,2,3}和k=2,那么答案将是{1,2},{1,3},{2,3}(顺序不重要)

一个n-集(定义:-)有{n-choose k}k-子集,即O(n^k)(尽管这不是紧的)。显然,解决这个问题的任何算法都必须在时间ω({n选择k})内运行


目前已知的解决这个问题的最快算法是什么?{n choose k}的下界真的可以实现吗(这样我们就有了一个基本上最优的算法)?

这可以使用递归规则来计算:

kSubsets(S, k) :
  k=0 or k>len(S):  {}
  else:  { for each i-th item in S: {Si} + kSubsets({Si+1,...,Sn}, k-1 }
例如:

kSubsets({1,2,3}, 2) =  {
                         {1}+kSubsets({2,3}, 1)}, 
                         {2}+kSubsets({3}, 1)}, 
                         {3}+kSubsets({}, 1)
                        } =
     = {
        {1}+{{2}+{kSubsets({3},0), {3}+kSubsets({}, 0)}}},
        {2}+{{3}+kSubsets({},0)},
        {3}+{}
       } =
     = {
        {1}+{{2}+{{}, {3}}},
        {2}+{{3}},
        {}
       } =
     = {
        {1}+{{2}, {3}},
        {2, 3}
       } =
     = {
        {1, 2}, {1, 3},
        {2, 3}
       } =
     = { {1,2}, {1,3}, {2,3} }

请注意,T+p意味着将T的项目添加到p中的每个项目(p中的每个项目都是一个集合)。

有一些众所周知的位魔术,可以用于生成所有子集(以长字符串的二进制表示形式编码):


优点是,这段代码速度非常快,缺点是它不能处理超过64个对象。

Nice。我喜欢这种方法。然而,我要求的是已知的最有效的算法(你必须提供分析并证明它优于其他算法)。您的过程的运行时间似乎是递归
T(k,n)=O(n-k)*T(k-1,n)
(具有明显的拐角情况)的解决方案。此外,可以使用动态规划保存每个计算子集的k子集列表,但这将使用与答案大小相同的空间。运行时间是解决方案的大小,这是所有ksubset中的项数,也就是O(k*C(n,k))是的,我找到了一个运行时间相似的。我想知道下限C(n,k)是否可以实现。如果一个人可以对长度为n的所有二进制序列进行一次非常聪明的遍历,并且恰好是k个序列(几乎只访问这样的序列),那么这就可以工作了。但这远不是显而易见的。。。我问这个问题的原因是因为我想知道目前最佳算法的运行时间与下限C(n,k)之间的差距有多大。(我对你的答案投了高票;但我不接受;让我们看看是否有人提出了一个好的参考/算法。)哇,没想到!美好的有趣的是,如果您必须对小
k
和小
n
进行大量计算,那么这实际上可能很有用。(我会详细讨论的——我承认我不明白它是怎么工作的/为什么工作的。)非常感谢。请每个社区都应该诚实地回答问题,而不浪费任何人的时间。如果您在一周左右的时间后没有得到满意的答案,您可能会标记请求迁移。
long getNextSubset(long subset){
   long smallest = subset& -subset;       
   long ripple = subset + smallest;    
   long ones = subset ^ ripple;       
   ones = (ones >> 2)/smallest; 
   subset= ripple | ones;    
   return subset;
}

void printAllSubsets(int n, int k){
    long MAX=1L<<n;
    long subset=(1L<<k)-1L;
    while((MAX&subset)==0){
         System.out.println(Long.toString(subset, 2));
         subset=getNextSubset(subset);
    }
}
[00]11
[0]101
[0]110
1001
1010
1100