如何使用Iterator的next()方法生成LinkedSet的幂集并解决空指针异常
问题原因
- 遍历用的节点对象被定义为迭代器全局成员:你将
set节点定义在了迭代器的成员变量位置,第一次调用next()遍历完成后,set已经被移动到了链表头部的前驱(也就是null),第二次调用next()时直接用null值访问prev属性,直接触发空指针。 - bit位判断逻辑错误:
Integer.toBinaryString()返回的是字符数组,元素是字符型的'0'和'1',你直接用bitString[i] == 1做判断,条件永远不成立,每次循环都会走到else分支移动set节点,会快速把set移到null位置。 - 二进制字符串无前导零导致遍历不完整:
Integer.toBinaryString()不会补前导零,比如集合大小N=4,current=2的二进制字符串是10,长度只有2,你遍历只会处理2位,剩下的2位对应的集合元素完全没有遍历,不仅逻辑错误,也会导致节点移动次数不符合预期的问题。
修复方案
- 将遍历用的
set节点改为next()方法的局部变量:每次调用next()生成子集时,都从链表的rear节点重新开始遍历,避免复用上次遍历结束的null节点。 - 修正bit位的判断条件:如果继续使用字符数组方案,要将判断改为
bitString[i] == '1',匹配字符数组的元素类型。 - 改用位运算直接判断每一位(更推荐):不用把current转成二进制字符数组,直接用
(current & (1 << i)) != 0判断第i位是否为1,循环固定执行N次,覆盖所有集合元素,不需要处理前导零问题,逻辑更简洁不易出错。
修复后完整代码示例
private class myPowerIterator implements Iterator<Set<T>> { // 集合元素总数 int N; // 幂集总大小 2^N int M; // 当前生成的子集编号 int current; public myPowerIterator() { N = size; M = 1 << N; // 位运算计算2^N,比Math.pow更高效且不会有浮点精度问题 current = 0; } public boolean hasNext() { return current < M; } public Set<T> next() { if (!hasNext()) { throw new NoSuchElementException(); } LinkedSet<T> result = new LinkedSet<T>(); // 每次生成都从链表尾部节点重新开始遍历 Node currNode = rear; // 固定循环N次,覆盖所有集合元素 for (int i = 0; i < N; i++) { // 判断当前bit位是否为1,为1就把对应元素加入子集 if ((current & (1 << i)) != 0) { result.add(currNode.element); } currNode = currNode.prev; } current++; return result; } public void remove() { throw new UnsupportedOperationException(); } }
内容的提问来源于stack exchange,提问作者thatOnePerson
相关产品推荐
相关产品推荐

