nextSetBit() 是遍历 BitSet 中所有置位最高效方式,时间复杂度 O(k),k 为值为 1 的位数;length() 返回最高置位索引加 1,非总容量,故不可用于循环控制。

用 nextSetBit() 遍历 BitSet 中所有值为 1 的位,是 Java 里最高效、最常用的方式。它不扫描全量位,而是直接跳到下一个置位位置,时间复杂度接近 O(k),k 是实际为 1 的位数,远优于逐个 get(i) 判断。
标准遍历写法
核心循环结构简洁明确:
- 起始调用
bs.nextSetBit(0)获取第一个 1 的索引 - 每次迭代后传入
i + 1继续查找后续位置 - 返回
-1表示已无更多置位,循环终止
示例代码:
for (int i = bs.nextSetBit(0); i != -1; i = bs.nextSetBit(i + 1)) {System.out.println("位索引:" + i);
}
为什么不能用 length() 或 size() 控制循环
length() 返回的是「最高位 1 的索引 + 1」,不是总容量;中间可能有大量未设置的 0 位。比如 bs.set(0); bs.set(1000);,length() 是 1001,但真正要处理的只有两个位置。若用 for (int i = 0; i ,会做上千次无效判断。
边界与安全注意事项
- 参数必须 ≥ 0,否则抛
IndexOutOfBoundsException - 当位索引极大(如接近
Integer.MAX_VALUE)时,nextSetBit(i + 1)可能返回-1,无需额外防溢出,但可加i == Integer.MAX_VALUE判断避免 +1 溢出 - 空 BitSet(全 0)第一次调用就返回
-1,循环不执行,行为自然安全
和 cardinality() 搭配使用的场景
cardinality() 返回 1 的总数,适合预分配数组或校验遍历完整性。例如:
int[] ones = new int[count];
int idx = 0;
for (int i = bs.nextSetBit(0); i != -1; i = bs.nextSetBit(i + 1)) {
ones[idx++] = i;
}
这样既保证数组不扩容,又确保结果一一对应。

















