商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 如何在 Java 中利用 BitSet.cardinality() 统计位图中设置为 true 的总位数

如何在 Java 中利用 BitSet.cardinality() 统计位图中设置为 true 的总位数

  发布于2026-07-10 阅读(0)

扫一扫,手机访问

在 Ja va 里,如果你想统计一个 BitSet 中到底有多少位被设为 truecardinality() 就是最简单直接、效率也最高的那个方法。它不需要你写循环去遍历每一位,也不用引入什么第三方库,一行代码就能搞定。

cardinality() 的行为和边界条件

这个方法内部做的是稀疏位计数优化——说白了就是分段查表加上 Long.bitCount。从时间复杂度上说,它接近 O(1),严格来讲是 O(有效字长数),但在绝大多数场景下完全可以当作常量来看。使用时有几个点需要留意:

  • BitSet(没调用过任何 set)返回 0,这很符合直觉。
  • 哪怕你设置了索引 1,000,000 这一位,中间全是 falsecardinality() 也只统计真正置位的那些位,不会傻乎乎地把整个范围扫一遍。
  • 调用前不用纠结要不要先调 trimToSize(),因为方法本身已经过滤掉了那些没被分配的 word 段。
  • 注意线程安全——多线程并发的场景下,如果你不手动加锁,结果可能会对不上。

与手动遍历的性能对比

有的人可能会想着自己写个循环,用 nextSetBit()get(i) 逐位统计。这么做不仅看着啰嗦,跑起来也慢得多。举个例子:

// ❌ 不推荐:O(n) 全量扫描,n 是最大索引+1int count = 0;for (int i = 0; i < bs.length(); i++) {    if (bs.get(i)) count++;}// ✅ 推荐:O(实际置位块数),快一个数量级以上int count = bs.cardinality();

尤其是当 BitSet 很稀疏的时候——比如只在索引 10000 和 200000 两处置了 true——cardinality() 几乎是瞬间出结果,而手动循环要老老实实检查 20 万次,差距不是一个量级。

常见误用:混淆 length() 和 cardinality()

BitSet.length() 返回的是「最高置位索引 + 1」,根本不是 true 的个数;它甚至可能大于实际内部容量(因为数组没压缩)。不少初学者会犯这样的错误:

  • 误以为 bs.length() == bs.cardinality() —— 实际上前者是“逻辑长度”,后者才是“真值个数”,两码事。
  • bs.size()(返回内部 long[] 数组的总容量)来估算 true 位数——这完全是两回事,返回值通常远大于实际置位数。
  • 在从来没有 set 任何位的时候,bs.length() 返回 0,cardinality() 也返回 0,此时两者数值相等,但这个巧合不能推广到有数据的情况。

真正需要记住的就是:统计 true 位数,只用 cardinality()。它不撒谎,不近似,JVM 对它做了深度优化。唯一需要操心的就是确保操作的是同一个 BitSet 实例,并且在并发写入时别漏掉同步。

本文转载于:https://www.php.cn/faq/2393238.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注