输入集合的幂集作为自定义集合

huangapple go评论67阅读模式
英文:

Power set of an input set as custom collection

问题

我一直在阅读《Effective Java》这本书,现在卡在了这段代码上,我无法理解这段代码是如何生成幂集的。

**代码:**
```java
public class PowerSet {

    public static final <E> Collection<Set<E>> of(Set<E> s) {
        List<E> src = new ArrayList<>(s);
        if (src.size() >= 30)
            throw new IllegalArgumentException("Set too big " + s);
        return new AbstractList<Set<E>>() {

            @Override
            public int size() {
                return 1 << src.size();
            }

            @Override
            public boolean contains(Object o) {
                return o instanceof Set && src.containsAll((Set) o);
            }

            @Override
            public Set<E> get(int index) {
                Set<E> result = new HashSet<>();
                for (int i = 0; index != 0; i++, index >>= 1)
                    if ((index & 1) == 1)
                        result.add(src.get(i));
                return result;
            }
        };
    }

    public static void main(String[] args) {
        Collection<Set<String>> result = of(Set.of("a", "b", "c"));
        System.out.println(result);
    }
}

输出:

[[], [a], [b], [a, b], [c], [a, c], [b, c], [a, b, c]]

有人可以解释一下这段代码是如何生成给定集合的幂集吗?


<details>
<summary>英文:</summary>

I have been reading the Effective Java book and I have stuck with this code I am unable to understand how this code is generating power set.

**Code:**

public class PowerSet {

public static final &lt;E&gt; Collection&lt;Set&lt;E&gt;&gt; of(Set&lt;E&gt; s) {
    List&lt;E&gt; src = new ArrayList&lt;&gt;(s);
    if (src.size() &gt;= 30)
        throw new IllegalArgumentException(&quot;Set too big &quot; + s);
    return new AbstractList&lt;Set&lt;E&gt;&gt;() {

        @Override
        public int size() {
            return 1 &lt;&lt; src.size();
        }

        @Override
        public boolean contains(Object o) {
            return o instanceof Set &amp;&amp; src.containsAll((Set) o);
        }

        @Override
        public Set&lt;E&gt; get(int index) {
            Set&lt;E&gt; result = new HashSet&lt;&gt;();
            for (int i = 0; index != 0; i++, index &gt;&gt;= 1)
                if ((index &amp; 1) == 1)
                    result.add(src.get(i));
            return result;
        }
    };
}

public static void main(String[] args) {
    Collection&lt;Set&lt;String&gt;&gt; result = of(Set.of(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;));
    System.out.println(result);
}

}

**Output:**

[[], [a], [b], [a, b], [c], [a, c], [b, c], [a, b, c]]


Can someone explain how this code is generating powerset of a given set.

</details>


# 答案1
**得分**: 1

代码使用索引号的二进制表示作为`s`列表中要包含的元素的映射。

例如,假设一个数字中只有3个位:

```plaintext
索引   | a | b | c
-------------------
0 (000) | 0 | 0 | 0 -> 不选择任何元素
1 (001) | 0 | 0 | 1 -> 仅选择 c
2 (010) | 0 | 1 | 0 -> 仅选择 b
3 (011) | 0 | 1 | 1 -> 选择 a 和 b
4 (100) | 1 | 0 | 0 -> 仅选择 a
...

生成的列表的get方法遵循以下逻辑,根据给定的index输入:

  • index >>= 1 每次循环将所有位右移一位
  • (index & 1) == 1 检查index的最右位是否为1

& 操作符是二进制与运算,所以 2 & 1 等于二进制 010 AND 001,结果为 000(不等于1或001),而 3 & 1 等于二进制 011 AND 001,结果为 001(等于1或001

  • 如果这个条件为真,则将第i个元素添加到列表中
  • index == 0 时终止,即没有更多的位要进行移位/添加的元素了

以 index = 3 为例:

i | index | (index & 1) == 1 | 添加的元素
-----------------------------------------
0 |   011 |             TRUE |   a (第0个元素)
1 |   001 |             TRUE |   b (第1个元素)
2 |   000 |            FALSE |   - 
(当 index == 0 时终止)
英文:

The code uses the binary representation of the index number as a map of which element of s to include.

For instance, assuming only 3 bits in a number:

index   | a | b | c
--------------------
0 (000) | 0 | 0 | 0 -&gt; take nothing
1 (001) | 0 | 0 | 1 -&gt; take only c
2 (010) | 0 | 1 | 0 -&gt; take only b
3 (011) | 0 | 1 | 1 -&gt; take a and b
4 (100) | 1 | 0 | 0 -&gt; take only a
...

The get method of the generated list follows this logic with the index input given:

  • index &gt;&gt;= 1 shifts all bits one position to the right with each loop
  • (index &amp; 1) == 1 checks whether the rightmost bit of index is a 1

The &amp; operator is the binary AND, so 2 & 1 equals binary 010 AND 001, giving 000 (not equal to 1 or 001) and 3 & 1 equals binary 011 AND 001, giving 001 (equal to 1 or 001)

  • If this evaluates to true, the i-th element is added to the list
  • This terminates when index == 0, i.e. there are no more bits to shift / elements to add

Example for index = 3:

i | index | (index &amp; 1) == 1 | element added
---------------------------------------------
0 |   011 |             TRUE |   a (0-th element)
1 |   001 |             TRUE |   b (1-th element)
2 |   000 |            FALSE |   - 
(terminates as index == 0)

huangapple
  • 本文由 发表于 2020年7月24日 19:31:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/63072693.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定