求子集的三种方式的总结

Posted torettorui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求子集的三种方式的总结相关的知识,希望对你有一定的参考价值。

求自己总共有三种方式:

增量构造

位向量

二进制

首先假设集合A中有n个元素,而且是非重集,一个下标唯一对应一个元素,那么求A的子集就变成了求0~n-1的子集。这个思想对于所有的三种方式都是通用的。

 

第一种增量构造法的思想是,每一次都从0~n-1中挑出一个元素来,每挑一次,就是一个集合。然后再挑元素进入这个集合,但是这次挑选元素的时候,必须比之前的那个元素大。

下面是代码实现:

//假设后一个非可重集合P,里面的元素各不相同,现在要从中挑选出它的所有子集来
//这个问题可以转换成挑选出P数组的下标的所有子集。即若P中有n个元素,那么就挑选出0~n-1之间的所有子集来
//以上的分析适合于所有的子集生成算法
//增量构造法的本质是这样的,每次从0~n-1 中挑选出一个元素来,每挑选一次,就是一个子集。然后再给这个已经挑选出来的子集中挑选元素,这次挑选出来的元素
//必须比之前的元素要大
#include<cstdio>
using namespace std;

const int maxn = 100 + 10;
int ans[maxn];
int n;

void print_sub_set(int cur)
{
    for(int i = 0; i < cur; i++)
    {
        printf("%d ",ans[i]);
    }
    printf("
");
    int s = cur ? ans[cur - 1] + 1 : 0;
    for(int i = s;i < n; i++)
    {
        ans[cur] = i;
        print_sub_set(cur +1);
    }
}

int main()
{
    n = 3;
    print_sub_set(0);
    return 0;
}

第二种方式是位向量法,如上一种方式所述,问题已经被转换成求0~n-1的子集,这时再转换一次,转换为求一个长度位n位的向量B[i],当b[i]为1时,代表i在这个集合中。在实现的时候,采用了递归的思想,每次都决定每一位的归属。

下面是代码实现:

//在上一篇说过,问题转换成了枚举0~n-1之间的所有的子集
//在位向量法中,还需要再次去转换,即将问题转换为构造一个有n位的向量,当b[i]为1的时候,表示i-1在此集合中,即元素A[i - 1]在集合中
#include<cstdio>
using namespace std;
const int maxn = 100 + 10;
int B[maxn];
int n;

void print_subset(int cur)
{
    if(cur == n)
    {
        for(int i = 0;i < n;i++)
        {
            if(B[i])
                printf("%d ",i);
        }
        printf("
");
    }
    else
        for(int i = 0; i <= 1; i++)
    {
        B[cur] = i;
        print_subset(cur + 1);
    }

}

int main()
{
    n = 3;
    print_subset(0);
    return 0;
}

最后是二进制法,二进制法的本质和位向量法是一致的,只不过位向量法中的向量B[],变成了一个整数转换为二进制时有n位的整数,这样就可以从0枚举到1<<n - 1,然后再去依次判断各个位的情况

下面附上代码:需要注意的一点就是如何判断各位的情况,就是x&1<<i       

//二进制法的本质和位向量法是一致的,都是构造一组向量
//但是二进制法使用的是位运算的方式
#include<cstdio>
using namespace std;

int n;
//const int ALL_BITS = 1<<n - 1;

void print_subset(int x)
{
    for(int i = 0; i < n;i++)
    {
        if(x & (1 << i))
        {
            printf("%d ",i);
        }
    }
    printf("
");
}

int main()
{
    n = 3;
    for(int i = 0;i < 1<<n;i++)
    {
        print_subset(i);
    }
    return 0;

}

经过比较这三种方式的效率,增量构造的效率最高,二进制次之,位向量最慢

当输入达到26的时候,增量构造法11s,二进制15s,位向量20s

但是编程的复杂度而言二进制最简单,增量构造和位向量一致

&符号代表所有的位一起与。

 

以上是关于求子集的三种方式的总结的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse中Runnable JAR file的三种打包方式有啥区别?求大神帮助。。。

多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP

求字符串长度的三种方式

pandas子集选取的三种方法:[].loc[].iloc[]

数组的三种声明方式总结多维数组的遍历Arrays类的常用方法总结

枚举所有子集的三种算法详解-《算法入门经典》