集合的子集输出(位运算方式)

问题:怎样找出某个集合的所有子集,怎样找出某个集合指定元素个数的所有子集?

 

思路:对集合中所有元素进行标记,0表示未选中,1表示选中。假如有一个集合有3个元素为 {1,2,3}, 则 000 表示一个都不选, 001表示选中数组中第一个元素1,010表示选中数组中第2个元素2,011表示选中数组中第1,2个元素即是1,2...。 这样一来,集合{1,2,3}的所有子集(忽略空集)可以表示为 001 -> 111 这样的编码。这样,我们就知道集合的所有子集的个数,即是 2^3=8个。所以,如果我们需要输出所有的子集,只需要将每个子集用 001这样的二进制编码表示,然后按照此编码输出选中的元素即可。十进制1->7恰可表示为二进制001->111这样的编码,这样求集合的所有子集就很简单了,所有的子集就是: 0->(2^元素数-1) 表示为二进制编码 所对应的集合元素的选择! 

 

实现:

package com.hdwang;

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

/**
 * Created by hdwang on 2016-12-29.
 * 集合中输出所有子集(空集除外),或者输出指定元素个数的子集
 * 思路:对每个元素进行标记(选择1 不选0),穷举子集,穷举中可进行筛选
 */
public class Combine2 {

    /**
     * 集合
     */
    private int data[] = {1, 2, 3, 4, 5, 6, 7, 8};

    Combine2(int size){
        //初始化集合
        this.data = new int[size];
        for(int i=0;i<size;i++){
            this.data[i] = i+1;
        }
        System.out.println("集合是:"+ Arrays.toString(this.data));
    }

    /**
     * 组合子集
     */
    List<String> subColListCH = new ArrayList<String>();

    /**
     * 输出集合的所有子集(空集忽略)
     */
    public void generateAllSubCol(){
        //256表示8个元素的输出情况
        for(int i = 1; i < 256; i++)   // 2^8 = 256
        {
            System.out.print(i+ " : ");
            int mark = 1;
            for(int j = 0; j < 8; j++)
            {
                int index = mark & i;  //mark与i后 得到i的每一位
                if(0 != index)         // 该位置是1,状态是选中,则输出对应元素
                {
                    System.out.print(data[j]+ " ");
                }
                mark <<= 1;  //mark在内层循环中,每次的值为1,2,4,8,16,32,64,128
            }
            System.out.println();
        }
    }

    /**
     * 输出指定元素个数的子集
     * @param subSize 子集大小
     */
    public void generateSubCol(int subSize){
        System.out.println("子集大小是:"+subSize);

        int elCount = data.length; //元素个数
        int allSubColCount = (int)Math.pow(2,elCount); //子集个数(空集不算)

        for(int i=1;i<allSubColCount;i++){ //i表示了一个子集的输出规则
            int mark = 1; //用于取出i的每一位
            List<Integer> subCol = new ArrayList(); //存储子集元素

            for(int j=0; j<elCount; j++){
                int index = mark & i; //取出i的第1位,第2位。。。
                if(0 != index){
                    subCol.add(data[j]);
                }
                mark <<= 1; //mark左移1位,用于获取i高一位的数字
            }

            if(subCol.size() == subSize){ //子集元素个数符合要求
                subColListCH.add(listToString(subCol, ','));
            }
        }

        System.out.println("\n打印组合集合:size is "+this.subColListCH.size());
        for(int i=0;i< this.subColListCH.size();i++) {
            String line = subColListCH.get(i);
            System.out.println(line);
        }
    }

    /**
     * list转换字符串
     * @param list list
     * @param separator 分隔符
     * @return 字符串
     */
    public String listToString(List list, char separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)).append(separator);
        }
        return sb.toString().substring(0,sb.toString().length()-1);
    }
}

 

函数调用

Combine2 combine2 = new Combine2(3);
combine2.generateSubCol(2);

 

输出结果

集合是:[1, 2, 3]
子集大小是:2

打印组合集合:size is 3
1,2
1,3
2,3





posted @ 2016-12-29 21:56  追极  阅读(2196)  评论(0编辑  收藏  举报