给定一组数字或符号,产生所有可能的集合(包括空集合),例如给定1 2 3,则可能的集合为:{}、{1}、{1,2}、{1,2,3}、{1,3}、{2}、{2,3}、{3}。
以下分别为无字典顺序和有字典顺序两种算法分析及代码实现,仅供参考。
如果不考虑字典顺序,则有个简单的方法可以产生所有的集合,思考二进位数字加法,并注意1出现的位置,如果每个位置都对应一个数字,则由1所对应的数字所产生的就是一个集合,例如:
000 |
{} |
001 |
{3} |
010 |
{2} |
011 |
{2,3} |
100 |
{1} |
101 |
{1,3} |
110 |
{1,2} |
111 |
{1,2,3} |
了解这个方法之后,剩下的就是如何产生二进位数?有许多方法可以使用,您可以使用unsigned型别加上&位元运算来产生,这边则是使用阵列搜 寻,首先阵列内容全为0,找第一个1,在还没找到之前将走访过的内容变为0,而第一个找到的0则变为 1,如此重复直到所有的阵列元素都变为1为止,例如:
000 => 100 => 010 => 110 => 001 => 101 => 011 =>111
#define MAXSIZE 20
//主程序(无字典顺序),用数组模拟二进制数,可以不断+1,很巧妙 char digit[MAXSIZE]; int i, j; int n; printf("集合内总元素个数:"); n = 5; for(i = 0; i < n; i++)//初始化数组中的前n个元素,下标从0开始 digit[i] = '0'; printf("\n{}"); // 空集合 while(1) { // 找第一个0,并将找到前所经过的元素变为0 for(i = 0; i < n && digit[i] == '1'; digit[i] = '0', i++); if(i == n) //找不到0,大循环结束,跳出 break; else //将第一个找到的0变为1,结果使二进制数+1 digit[i] = '1'; // 找第一个1,并记录对应位置 for(i = 0; i < n && digit[i] == '0'; i++);//第i下标的数不符合继续循环下去的条件,即==1,此时i已经完成自增(设第二个数字为1,则 i==1) printf("\n{%d", i+1);//打印这个数字,这里是下标,为第i+1个数(打印结果:2) for(j = i + 1; j < n; j++)//从下标i+1开始发现(从下标2开始遍历,而下标1对应的数字已经打印) if(digit[j] == '1') printf(",%d", j + 1);//(下标j对应的数字为j+1) printf("}");//for循环结束,打印} } printf("\n");
如果要产生字典顺序,例如若有4个元素,则:
{} => {1} => {1,2} => {1,2,3} => {1,2,3,4} =>{1,2,4} =>{1,3} => {1,3,4} =>{1,4} =>
{2} => {2,3} => {2,3,4} =>{2,4} =>
{3} => {3,4} =>
{4}
简单的说,如果有n个元素要产生可能的集合,当依序产生集合时,如果最后一个元素是n,而倒数第二个元素是m的话,例如:
{a b c d m n}
则下一个集合就是{a b c d m+1},再依序加入后续的元素。
例如有四个元素,而当产生{1 2 3 4}集合时,则下一个集合就是{1 2 3+1},也就是{1 2 4},由于最后一个元素还是4,所以下一个集合就是{1 2+1},也就是{1 3},接下来再加入后续元素4,也就是{1 3 4},由于又遇到元素4,所以下一个集合是{1 3+1},也就是{1 4}。
#define MAXSIZE 20
//主程序(有字典顺序) int set[MAXSIZE]; int i, n, position = 0; printf("集合内总元素个数:"); n = 5; printf("%d",n); printf("\n{}"); set[position] = 1; while(1) { printf("\n{%d", set[0]); // 打印第一个数,除空集外,都是有这个元素的 for(i = 1; i <= position; i++) // 打印其它数,position为0的时候,自然不会打印 printf(",%d", set[i]); printf("}"); if(set[position] < n) { // 递增,这里是元素的值 <n,成立则加一元素,且值为最后元素值+1 set[position+1] = set[position] + 1;// 给下一个数组元素赋值 position++; // 有效长度+1 } else if(position != 0) { // 如果不是第一个位置 position--; // 倒退 set[position]++; // 倒数第二个元素+1 } else // 已倒退至第一个位置,且元素值为n的时候 break; // 跳出循环 } printf("\n");