1

[家庭作业]

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

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

PS:集合A的幂集是集合A的所有子集的集合。A = { a, b, c} A 的幂集 = {{},{a},{b},{c},{a,b},{b,c},{a,c},{a ,公元前}}


编辑:

非常感谢“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);      
    }
}
4

4 回答 4

9

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

例如

     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}
于 2013-08-27T13:26:45.090 回答
5

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

1.字典顺序——字典顺序是指排序的顺序,通常是生成组合对象的最自然的方式。{1, 2, 3} 的八个子集按字典顺序分别为 {} , {1}, {1, 2}, {1, 2, 3}, {1, 3}, {2}, {2, 3 } 和 {3}。但是要按字典顺序生成子集是非常困难的。除非您有令人信服的理由这样做,否则不要打扰。

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

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

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

于 2013-08-27T13:50:48.050 回答
0

这是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;
}
于 2014-07-24T07:36:57.050 回答
0

使用递增/递减的二进制计数很好,直到你的通用集的元素比你最大的整数类型的位数多。但是,继承规则很简单。给定子集 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。

于 2020-05-28T19:23:46.450 回答