怎样找出集合中所有子集,怎样找出集合中指定元素的所有子集?

集合中的组合算法

Java 没有自带的求一个集合的所有子集的方法,我们可以通过集合的子集规律来求。

思路:
对集合中所有元素进行标记,0表示未选中,1表示选中。

示例:
集合{1,2,3,4},长度为4,则 0000表示一个都不选,0001表示选数集合中第一个元素 {1}0010表示选中集合中第二个元素 {2},0011表示选中第一,第二元素 {1,2}
以此类推,集合{1,2,3,4}的所有集合,包括空集,可以表示为0000-1111这样的二进制位码。
我们可以看出集合的所有子集的个数,是2^3=8个。

由此,可以推理,如果我们需要输出所有的子集,只需要将每个子集用0001这样的二进制编码表示,然后按照此二进制码输出选中的元素即可,十进制0-15,恰巧可以表示为二进制0000-1111,这样求集合的所有子集就比较简单了,所有的子集就是:0 -(2^元素数-1)表示为二进制编码所对应的集合元素的选择。

在这里插入图片描述
于是,根据上面的规律,代码可以这样写,先取集合的长度,求出2^该集合的长度是多少,比如上面的16,然后从0遍历到16-1。
遍历的时候,对0、1、2…每一个数据进行位运算,逐一判断其对应的位数,也就是二进制的表示方式,是1表示选中,0表示未选中。

实现:

package com.dodoke.test5;

import java.util.ArrayList;
import java.util.List;

public class Test5 {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		// 初始化集合
		for (int i = 0; i < 4; i++) {
			list.add(i + 1);
		}
		System.out.println(list.toString());

		List<List<Integer>> all = compare1(list);
		
		System.out.println("+++++++++++++所有子集(begin)++++++++++++++");
		for (List<Integer> a : all) {
			System.out.println(a.toString());
		}
		System.out.println("+++++++++++++所有子集(end)++++++++++++++");
		

		int subSize = 3;

		System.out.println("+++++++++++++指定子集:"+subSize+"(begin)++++++++++++++");
		List<List<Integer>> subCol = compareCol(list,subSize);

		for (List<Integer> a : subCol) {
			System.out.println(a.toString());
		}
		System.out.println("+++++++++++++指定子集:"+subSize+"(end)++++++++++++++");
	}

	private static List<List<Integer>> compareCol(List<Integer> list, int subSize) {
		List<List<Integer>> allCol = new ArrayList<>();
		// 0到2^集合长度-1
		for (int i = 0; i < (int) Math.pow(2, list.size()); i++) {

			List<Integer> subList = new ArrayList<>();
			// 重置mark值
			int mark = 1;
			// 该循环用于对mark移位
			for (int j = 0; j < list.size(); j++) {
				// 该位置是1,状态是选中,则将对于元素放到子集合中
				if ((mark & i) == mark) {
					subList.add(list.get(j));
				}
				mark <<= 1;
			}
			
			if(subList.size() == subSize) {
				allCol.add(subList);
			}
		}
		return allCol;
	}

	/**
	 * 右移索引,获取每一位
	 * 
	 * @param list
	 * @return
	 */
	private static List<List<Integer>> compare(List<Integer> list) {
		List<List<Integer>> all = new ArrayList<>();
		// 0到2^集合长度-1
		for (int i = 0; i < (int) Math.pow(2, list.size()); i++) {

			List<Integer> subList = new ArrayList<>();
			// 临时保存i,接下来,右移mark,得到最后一位,是否为1
			int mark = i;
			// 该循环用于对mark移位
			for (int j = 0; j < list.size(); j++) {
				if ((mark & 1) == 1) {
					subList.add(list.get(j));
				}
				mark >>= 1;
			}
			all.add(subList);
		}
		return all;
	}

	/**
	 * 方法2:索引不动,移动mark,即左移
	 * 
	 * @param list
	 * @return
	 */
	private static List<List<Integer>> compare1(List<Integer> list) {
		List<List<Integer>> all = new ArrayList<>();
		// 0到2^集合长度-1
		for (int i = 0; i < (int) Math.pow(2, list.size()); i++) {

			List<Integer> subList = new ArrayList<>();
			// 重置mark值
			int mark = 1;
			// 该循环用于对mark移位
			for (int j = 0; j < list.size(); j++) {
				// 该位置是1,状态是选中,则将对于元素放到子集合中
				if ((mark & i) == mark) {
					subList.add(list.get(j));
				}
				mark <<= 1;
			}
			all.add(subList);
		}
		return all;
	}
}

参考资料:https://blog.csdn.net/yongh701/article/details/53583486

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值