求集合的子集合问题

问题描述:假如给你一个固定的集合{"abc"},如果要求这个集合的所有子集合,怎么办?数学功底好的人也许一下子知道答案了---总数是2^n,对答案就是这个(如果包括空集的话)。数学定义是这样的:

定义1:含有n个元素的集合A称为n元集。它的含有m个(mn)元素的子集称作它的m元子集

一般来说,对于n元集A,它的m0mn)元子集有个,所以不同的子集总数有

=2n  

 所以n元集共有2n个子集。 至于推理过程就不在详细介绍了,有兴趣的同学可以自己思考一下。

既然我们知道了结果,但是这不是根本目的,我还想要将求解的过程模拟出来,怎么办?只有靠程序实现这个模拟过程了。

对于这个过程有这样的几种解法:

1 我们可以从小到大的求解这个问题,所有的集合中可以分为4类(举上面的例子“abc”),元素个数为0个,1个,2个,3个。且不看元素的内容,了解一下求解过程就知道了。首先当元素数为0时,不用说就知道了,而元素个数为1个的时候是怎么求出来的呢?是将分别从所剩下的元素中抽取一个元素然后和元素个数为0的集合相或就求得了,后面的求法是一样的。过程不再熬述了。这种方法可以使用C++的vector< set<char> > 这样的组合数据结构来存放所有的集合。

2 这种方法的思路是从头到尾的去遍历这个序列("abc"),当每遇到一个字符的时候,比如遇到'a'的时候,我们有两种选择,取或者不取,不管你取或者不取,都不影响下一个字符'b'的选择,这样只要我们把所有的可能的选择情况都罗列出来,结果(最后选择的字符)自然就出来了。

3 这种思路其实和思路2是差不多等同的,只是它是思路的一种抽象的表达。当我们知道结果的时候也许对0,1 敏感的人已经或多或少有思路3了,对!就是你想的那个样子。(还是举这个简单的例子“abc”)这3个元素一种有8中组合方式,而3bit位的组合方式不也是8种吗?从000~111,是吧,它已经把所有的组合方式罗列出来了,我们何必再去做这样的重复工作呢?为0表示不取,为1表示取?所有可能不就尽收眼底了?

说了这么久,直接给代码了(思路很简单,所以代码就不给解释了)

思路2的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int count;
void getSubSet(char* arr,char* result,int i_current,int j_current,int r){
    if(i_current == r) {
        printf("%s\n",result);    
        count++;
        return;
    }
    result[j_current++]=arr[i_current];
    getSubSet(arr,result,i_current+1,j_current,r);
    result[--j_current]='\0';
    getSubSet(arr,result,i_current+1,j_current,r);
}

int main(){
    char arr[]={'a','b','c','d','e'};
    char* result;
    result = (char*)malloc(sizeof(arr));
    memset(result,0,sizeof(arr));
    getSubSet(arr,result,0,0,4);
    printf("the total num is %d\n",count);
}

思路3的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc,char** argv){    
    char arr[]={"fxpmeng"};
    int len = strlen(arr);
    char* result,*p;
    int i,j,count;
    count = 0;
    result = (char*)malloc(sizeof(arr));
    for(i = 0;i <=(1 << len)-1;i++){
        int tmp = i;    
        memset(result,0,sizeof(arr));    
        j = 0;
        p = result;
        while(tmp!=0){
            if(tmp & 0x1){
                *p++ = arr[j];    
            }
            j++;
            tmp = tmp >> 1;
        }
        printf("%s\n",result);
        count++;
    }
    printf("the total num is %d\n",count);
}

 

 

转载于:https://www.cnblogs.com/fxplove/articles/2513749.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值