非递归求n个元素的所有子集

题目描述:给出一个n个元素的集合,要求打印出所有的子集;

思路分析:n个元素的子集共有2^n个,其中包括空集。 
(1)假设有3个元素{a, b, c},那么此时有 2^3 个子集,即8个子集。 
(2)因为有8个子集,而且包括空集,注意7对应的二进制形式为111,并且二进制数刚好3位;所以(000 ~ 111)可分别对应一个子集,若该位为1,则表示该元素出现在子集中,若该位为0,则表示该元素不出现在子集中; 

举例:

111表示子集abc; 
110表示子集bc; 
101表示子集ac; 
100表示子集c; 
011表示子集ab 
010表示子集b; 
001表示子集a; 
000则表示空集;

那么问题就变得简单了,程序的思路就变为:

求出子集的个数n---->从0开始到n循环传入一个数---->根据这个数的各个位是否为1来选择是否打印该位元素

程序的核心就变为判断这个数的各个位是否位1,利用位运算很简单就可以实现;

例如: 当传入的数为5时:对应二进制为 101 

用5%2可以得到二进制的最后一位是1,然后将5右移一位(5>>1)得到的是010;循环这个过程就可以判断每一位是否为1;

代码:

void print(int arr[],int length,int n)
{
	for (int i = 0; i < length; i++)     //从0到length循环代表这个集合一共有length个元素,需要依次判断是否需要打印
	{
		if (n % 2)		      //判断n对应的二进制最后一位是否为1
		{
			cout << arr[i]<<' '; 
		}
		n = n >> 1;                  //将n右移一位继续循环这个过程,直到所有的元素都判断结束则退出循环
	}
	cout << endl;
}
void subset(int arr[], int length)
{
	int num = pow(2, length);     //计算子集的个数
	for (int i = 0; i < num; i++)
	{
		print(arr, length,i);  //打印函数,每个i值对应的二进制都代表了一个子集
	}
}
int main()
{
        int ar[] = {1, 2,3,4,5};
        int n = sizeof(ar)/sizeof(ar[0]);
        subset(ar,n);
}





  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,关于你的问题,我可以给出递归算法伪代码: ``` function permutations(list, n) { if (n <= 1) { return [list]; } let result = []; for (let i = 0; i < n; i++) { let subList = list.slice(0); subList.splice(i, 1); let subPermutations = permutations(subList, n - 1); for (let j = 0; j < subPermutations.length; j++) { result.push([list[i]].concat(subPermutations[j])); } } return result; } ``` 通过调用 `permutations(list, n)` 即可获得 `list` 所有长度为 `n` 的排列。 ### 回答2: 要设计递归算法生成n个元素的所有排列对象c,首先可以确定递归的终止条件是当n=1时,排列只有一个元素,即为c。然后考虑如何将问题分解为规模更小的问题。 假设初始时有n个元素{a1, a2, ..., an},为了生成所有排列对象c,可以以第一个元素ai作为固定元素,然后递归地生成剩余n-1个元素的所有排列。递归解的结果可以表示为p(n-1),代表n-1个元素的所有排列。接下来,将ai与p(n-1)中的每一个排列进行组合,得到n个元素的所有排列。 具体步骤如下: 1. 如果n=1,返回{a1}作为排列c。 2. 如果n>1,则对于每一个元素ai,分别以ai作为固定元素,递归地生成剩余n-1个元素的所有排列p(n-1)。 3. 将ai与p(n-1)中的每一个排列进行组合,得到以ai为开头的n个元素的排列对象c(i)。 4. 返回所有c(i)的集合,即为n个元素的所有排列对象c。 通过递归的方式,每一次都将问题分解为规模更小的问题,直到达到终止条件,最终得到全部排列对象c。 需要注意的是,在实现算法时,可以利用循环结构来遍历元素并进行递归调用,同时需要使用适当的数据结构来保存排列结果,并确保在递归过程中不重复生成相同的排列。 ### 回答3: 设计递归算法生成n个元素的所有排列对象c 的步骤如下: 1. 如果n等于1,则排列对象c为单个元素。返回{[1]}。 2. 否则,将第一个元素与剩余的n-1个元素进行交换。这可以通过遍历剩余元素并与第一个元素交换来实现。例如,对于元素数组[1, 2, 3],将第一个元素1与[2,3]中的每个元素进行交换,得到[1]+permutation([2,3])的结果。 3. 对于每个交换后的数组,将当前交换后的元素放在排列对象c中,并递归地生成剩余n-1个元素的排列对象。这可以通过将当前交换后的元素与递归调用permutation()的结果进行连接来实现。例如,在步骤2中,得到[1]+permutation([2,3])的结果后,递归地计算permutation([2,3])。 4. 重复步骤2和3,直到所有元素都参与了交换。最终得到的排列对象c是所有交换的结果的集合。 通过上述步骤,我们可以逐步生成n个元素的所有排列对象c。需要注意的是,在每次递归调用中,所传递的元素数组都是递归前的剩余元素数组。这样可以确保每个元素都有机会成为排列对象c中的第一个元素,并且可以保证没有重复的排列对象c。 需要注意的是,以上算法的时间复杂度为O(n!),其中n为元素个数。这是因为对于每个元素,都需要进行交换和递归操作,而每个操作都是对剩余元素进行的,所以总共有n!个操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值