求集合的幂集

Posted

技术标签:

【中文标题】求集合的幂集【英文标题】:Finding Power set of a Set 【发布时间】:2013-08-27 13:03:08 【问题描述】:

[家庭作业]

我们必须使用 Java 或 C++ 找到给定集合的幂集。该集合将以任意大小的数组的形式被接受,我需要显示该集合的幂集的元素。请注意,唯一要使用的概念是数组、循环和函数(递归和迭代)。

我需要有人指出我可以应用的逻辑的正确方向。 请帮忙。

PS : 集合 A 的幂集是集合 A 的所有子集的集合 例如。 A = a, b, c A 的幂集 = ,a,b,c,a,b,b,c,a,c,a,b,c


编辑:

非常感谢“wy”和“MrSmith42”!我已经使用他们给出的逻辑编写了我的程序。现在我正在尝试优化它。请注意,我是 Java 新手,由于它的新颖性,我觉得它有点不舒服。

这是我的代码:

import java.util.Scanner;

public class PowerSet 

    //Function to increment binary string...

    static String incr_bin (String binary)
        char bin[] = new char[100];
        int size_bin, i;
        size_bin = binary.length();
        bin = binary.toCharArray(); 
        bin[size_bin-1]++;
        for(i=size_bin-1; i>=0; i--)
            if (i != 0)
                if(bin[i] > '1')
                    bin[i]='0';
                    bin[i-1]++;
                
            
        
        if (bin[0]>'1')
            for(i=0;i<size_bin;i++)
                bin[i]='0';
            
        
        binary = new String (bin);
        return binary;
    



    public static void main(String[] args) 

        //Declarations

        Scanner in = new Scanner (System.in);
        int a[] = new int [100];
        int size_a, i, count=0;

        String binary;

        //Input

        System.out.println("Enter the number of elements in A : ");
        size_a = in.nextInt();
        char bin[] = new char [size_a];
        System.out.println("Enter the elements in A : ");
        for(i=0; i<size_a; i++)
            a[i] = in.nextInt();
            bin[i] = '0';
        
        binary = new String(bin);

        //Calculating and Setting up subsets
        System.out.println("MEMBERS OF POWER SET :");
        do
            System.out.print("\n.");
            count = 0;
            binary = incr_bin(binary);
            bin = binary.toCharArray();
            for(i=0; i<size_a; i++)
                if (bin[i] == '0') count++;
                if (bin[i] == '1') System.out.print(a[i] + "  ");
            
            System.out.println("");
        while(count!=size_a);      
    

【问题讨论】:

学习编码的唯一方法是尝试编码。请尝试返回具体问题。 我知道如何编码,我只是不知道如何处理这么多数组并同时操作它们。 @whoAmI 你读过这个问题吗? 我需要有人指出我可以应用的逻辑的正确方向我在这个问题中没有看到代码请求 @BackSlash 学习编码包括知道要走什么路(或至少要问什么)。在这个问题变得更具体之前,我认为不应该回答这个问题。 @whoAmI :我已经编辑了我的问题。我需要逻辑,而不是代码。如果可以,请提供帮助。 【参考方案1】:

您可以将幂集的每个元素映射到一个二进制数,其位数与您的集的大小一样多。

例如

     A =  a, b, c 
     binary number  => resulting subset
     000            =>        // no 'a',  no 'b', no 'c'
     001            =>     c
     010            =>   b  
     011            =>   b,c
     100            => a    
     101            => a,  c
     110            => a,b  
     111            => a,b,c

【讨论】:

非常感谢!这就是我一直在寻找的东西!【参考方案2】:

输出幂集,算法设计手册“14.5 生成子集”中有3种方法,我都试过了,只有数组,循环和函数。但是不会有代码。以下是关于它们的简短段落:

1.字典顺序 – 字典顺序表示排序顺序,是 通常是生成组合对象的最自然方式。这 1, 2, 3 的八个子集按字典顺序是 , 1, 1, 2、1、2、3、1、3、2、2、3 和 3。但令人惊讶的是 难以按字典顺序生成子集。 除非你有 一个令人信服的理由,不要打扰。

2.格雷码 - 一个特别有趣和有用的子集序列是最小更改顺序,其中相邻子集相差 插入或删除一个元素。这样的排序,称为 格雷码。以格雷码顺序生成子集可以非常快, 因为有一个很好的递归结构。构造格雷码 n − 1 个元素的 Gn−1 反转 Gn−1 的 > 第二个副本并将 n 添加到 此副本中的每个子集。然后将它们连接在一起以创建 Gn此外,由于子集之间只有一个元素发生变化,因此详尽无遗 基于格雷码的搜索算法非常有效。

3.二进制计数最简单的方法解决子集生成问题是基于观察到任何子集 S' 定义为 该 S 的项目在 S' 中。我们可以用二进制字符串表示 S' n 位,其中第 i 位是 1iffS 的第 i 个元素在 S' 中。这 定义长度为 2n 的二进制字符串之间的双射 n,以及 n 个项目的 2n 个子集。对于 n = 3,二进制计数 按以下顺序生成子集:、3、2、2,3、1、 1,3、1,2、1,2,3。这种二进制表示是关键 解决所有子集生成问题。生成所有子集 顺序,只需从 0 数到 2n-1。对于每个整数, 依次屏蔽掉每个位并精确组成一个子集 1位对应的项目。生成下一个或上一个 子集,将整数递增或递减一。对子集进行排序 正是掩蔽过程,而排名构造一个二进制 与 S 中的项目对应的 1 的数字,然后将其转换为 二进制数转为整数。

如果你想要一个简单的,只需要二进制计数就足够了,它可以是循环实现,如回溯或特定的。如果你已经做过并且想要更多的挑战,你可以编码一个格雷码。你可以在其wiki页面here了解如何生成格雷码。

【讨论】:

精彩的解释。非常感谢!【参考方案3】:

这是java中的实现。这使用了上面使用位解释的逻辑。

/**
 * Prints all subsets of a list
 * @param list
 */
public static void printSubsets(List<Integer> list) 
    int max = (int)Math.pow(2, list.size());

    for (int i = 0; i < max; i++) 
        // Convert int to bitset
        BitSet bs = getConvertedBitSet(i, list.size());

        // Use bitset to print the subset
        printSubset(bs, list);
    


/**
 * Helper function for @link org.vikastaneja.companies.Expedia#printSubsets(java.util.List)<br/>
 * This function prints the subsets for the bits that are set in bitset
 * @param bs
 * @param list
 */
private static void printSubset(BitSet bs, List<Integer> list) 
    if (list == null) 
        throw new NullPointerException("Set is empty");
    

    System.out.print(" ");
    for (int i = 0; i < list.size();i++) 
        if (bs.get(i)) 
            System.out.print(list.get(i) + " ");
        
    

    System.out.print("");

    System.out.println();


/**
 * Helper function for @link org.vikastaneja.companies.Expedia#printSubsets(java.util.List)<br/>
 * This function converts an integer to the bitset
 * @param value
 * @param size
 * @return
 */
private static BitSet getConvertedBitSet(int value, int size) 
    BitSet bits = new BitSet(size);
    bits.set(0, size - 1, false);
    int index = 0;
    while (value != 0) 
        if (value % 2 != 0) 
            bits.set(index);
        
        ++index;
        value = value >>> 1;
    
    return bits;

【讨论】:

【参考方案4】:

使用递增/递减的二进制计数很好,直到你的通用集的元素比你最大的整数类型的位数多。但是,继承规则很简单。给定子集 S_k 表示为位向量,您生成 S_k+1 如下:

for i in 0..len(s):
  if s[i]:
    s[i] = 0
  else:
    s[i] = 1
    break

从 [000] 开始,很容易看出这会生成 [100],[010],[110],[001],...[111]。要生成所有这些,请将上述内容包装在一个循环中并跟踪子集的基数,在将位设置为 1 或 0 时加或减 1。最后一个子集将具有基数 n。

【讨论】:

以上是关于求集合的幂集的主要内容,如果未能解决你的问题,请参考以下文章

一组python的幂集和笛卡尔积

11.幂集计算[回溯递归]<一>

两种求幂集的方法

点集拓扑

集合论基础

集合论(基础+二元关系+函数)