问题引入
给定一组数字或符号,产生所有可能的集合(包括空集合)。 例如1 2 3,则可能的集合为:{}(空集)、{1}、{1,2}、{1,2,3}、{1,3}、{2}、{2,3}、{3}。如何实现呢?
问题分析
1.若不考虑顺序,借助二进位数字加法计算过程较为方便,假设每个位置都对应一个数字,出现1的位置所对应的数字的组合就是一个集合,例如:
000 {} 无数字
001 {3} 对应数字3
010 {2} 对应数字2
011 {2,3} 对应数字2 3
100 {1} 对应数字1
101 {1,3} 对应数字1 3
110 {1,2} 对应数字1 2
111 {1,2,3} 对应数字1 2 3
如何产生二进位数?
借助数组实现。先令数组内容全为0,找第一个1,在还没找到之前将走访过的内容变为0。将第一个找到的0则变为 1,重复进行知道数组中所以元素都为1,例如:
000 ---> 100 ---> 010 ---> 110 ---> 001--->101--->011--->111
2.如果考虑顺序,例如若有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,而倒数第二个元素是e,例如:{a,b,c,d,e,n},则下一个集合就是{a b c d e+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}。
代码实现1——> 不考虑顺序
1.代码实现
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
int main(){
char digit[MAXSIZE];
int i, j;
int n;
printf("输入集合个数:");
scanf("%d", &n);
for(i = 0; i < n; i++) 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
digit[i] = '1';
// 找第一个1,并记录对应位置
for(i = 0; i < n && digit[i] == '0'; i++);
printf("\n{%d", i+1);
for(j = i + 1; j < n; j++){
if(digit[j] == '1')
printf(",%d", j + 1);
}
printf("}");
}
printf("\n");
return 0;
}
2.运行结果
代码实现2——> 考虑顺序
1.代码实现
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
int main() {
int set[MAXSIZE];
int i, n, position = 0;
printf("输入集合个数:");
scanf("%d", &n);
printf("\n{}");
set[position] = 1;
while(1) {
printf("\n{%d", set[0]); // 印第一个数
for(i = 1; i <= position; i++) printf(",%d", set[i]);
printf("}");
if(set[position] < n) { // 递增集合个数
set[position+1] = set[position] + 1; position++;
}else if(position != 0) { // 如果不是第一个位置
position--; // 倒退
set[position]++; // 下一个集合尾数
}
else // 已倒退至第一个位置
break;
}
printf("\n");
return 0;
}
2.运行结果