【问题标题】:Obtaining power set in mathematical order按数学顺序获取幂集
【发布时间】:2022-11-23 01:50:08
【问题描述】:

{1, 2, 3} 的幂集是:

{{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}

我在 java 中有一个字符串数组,

        String elements={"apple","mango","banana"};
        String set[]=elements.split("[ ,]+");

如何按数学顺序打印此数组的幂集? (我试过位操作方法,它没有按顺序给出解决方案!)

我的位操作方法!没有给出要求的结果!

static void printPowerSet(String[] set) {
        long pset = (long) Math.pow(2, set.length);
        System.out.print("Power Set is \n{");
        for (int i = 0; i < pset; i++) {
            System.out.print("{");
            for (int j = 0; j < set.length; j++) {
                if ((i & (1 << j)) > 0){
                    System.out.print(set[j] + " ");
                    
                }
                if (i == 0 && j==0 )
                    System.out.print(" ");
            }
            System.out.println("}");
        }
        System.out.println(" } \n");
    }

【问题讨论】:

  • 这是一个足够复杂的算法,您不应该将其作为代码的一部分打印 - 返回一组集合并使用单独的方法来打印它们。它会更灵活,更容易调试。
  • 此外,在询问有关 SO 的问题时,您应该确切地告诉我们出了什么问题 - 如果不是想要的结果,这会给出什么结果?
  • 您还应该清楚“数学顺序”的含义。

标签: java powerset


【解决方案1】:

所以看看你提供的列表,我不会称之为“数学顺序”——你的代码产生的结果实际上看起来更像我所期望的。这就是大多数算法自然会产生这样一个幂集的方式。

但是,好吧,说你想要那样。使算法自然地按该顺序生成它将会很痛苦。如果您在创建幂集时打印,则没有办法解决 - 您必须按照算法访问它的顺序打印每个元素。但是,如果您改为返回电源组并且然后打印它,根据需要在两者之间对其进行排序很简单。

在下面的代码中,我(混乱地)实现了我自己的方法来生成排序集,只是因为数组很痛苦。 (实际上,Java 中的一切都是痛苦的。)


public class MyClass {
    public static void main(String args[]) {
      
      List<String> setAsList = Arrays.asList("1", "2", "3");
      List<List<String>> powerSet = powerSetWithPrefix(new ArrayList(), setAsList);
      powerSet.sort( (List<String> l1, List<String> l2) -> l1.size() - l2.size());
      printPowerSet(powerSet);

    }
    static List<List<String>> powerSetWithPrefix(List<String> prefix, List<String> remaining){
        if (remaining.isEmpty()) {
            List<List<String>> ret = new ArrayList();
            ret.add(prefix);
            return ret;
        }
        List<String> tail = remaining.subList(1, remaining.size());
        String head = remaining.get(0);
        List<String> prefixWithout = new ArrayList(prefix);
        List<String> prefixWith = new ArrayList(prefix);
        prefixWith.add(head);
        List<List<String>> powerSet = powerSetWithPrefix(prefixWith, tail);
        powerSet.addAll(powerSetWithPrefix(prefixWithout, tail));
        return powerSet;
    }
    static void printPowerSet(List<List<String>> powerSet){
        System.out.println("Printing powerset:");
        for (List<String> set:  powerSet) {
            System.out.printf("[%s]
", String.join(", ", set));
        }
    }
}

通过将 powerSet 逻辑与打印逻辑分开,可以轻松控制输出格式,而无需费心研究算法。

如果你真的需要某种算法来首先访问较短的列表,你需要编写类似于广度优先搜索的东西,这会笨拙得多。

【讨论】:

    【解决方案2】:

    这是一个有趣的算法,Knuth 认为。 它实际上比听起来容易得多。

    我正在解释顺序。 按基数顺序输出子集(从空集开始)。 在该顺序中,它们根据包含成员的位置({1,2} 在 {2,3} 之前)在词法上相互联系。

    下面的示例显示了一组 4 个对象,因为 3 个对象并不能完全揭示正在发生的事情。

    它适用于一组 boolean 标志以指示成员资格。 在每个步骤中至少在一个 true 标志之后寻找一个 false 标志。 如果找到,则设置 true 并将真标志的数量减一返回到开始。 如果因为设置了所有标志而未找到,我们将输出完整的集合。所以完成。 否则从具有更多成员的第一个子集开始(设置 count+1 标志)。

    class Subsets
    {
        public static boolean advance(boolean[] flags){
            int count=0;
            for(int i=0;i<flags.length;++i){
                if(flags[i]){
                    ++count;
                }else{
                    if(count>0){
                        flags[i]=true;
                        for(int j=0;j<(count-1);++j){
                            flags[j]=true;
                        }
                        for(int j=(count-1);j<i;++j){
                            flags[j]=false;
                        }
                        return true;
                    }
                }
            }
            //Fell off the end.
            if(count==flags.length){
                return false; // All flags set.
            }
            //Rack 'em up for subsets larger than the ones we've finished.
            for(int i=0;i<=count;++i){
                flags[i]=true;
            }
            for(int i=count+1;i<flags.length;++i){
                flags[i]=false;
            }
            return true;
        }
        
        public static void dump(boolean[] flags){
            for(int i=0;i<flags.length;++i){
                System.out.print(flags[i]?'Y':'N');
            }
            System.out.println();
        }
        
        public static void dump(boolean[] flags,String[] items){
            for(int i=0;i<flags.length;++i){
                if(flags[i]){
                    System.out.print(items[i]+" ");
                }
            }
            System.out.println();
        }
        
        public static void main (String[] args) throws java.lang.Exception
        {
            String[] fruit={"Apple","Mango","Banana","Pear"};
            boolean[] flags=new boolean [4];
            do{
                dump(flags);
                //dump(flags,fruit);
            }while(advance(flags));
        }
    }
    

    请参阅:计算机编程艺术,第 4A 卷,组合算法,第 1 部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-31
      • 2017-03-03
      • 1970-01-01
      • 2020-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多