有效地找到 BitSet 中连续未设置位的范围

Efficiently find ranges of consecutive non-set bits in BitSet

我正在尝试使用 BitSet 表示特定日期的日历 available/unavailable 时段,每个位代表 15 分钟。设置的位代表被阻止的日历事件。为了获得空闲的插槽,我需要找到未设置位的范围。

我有以下 BitSet

00000000000000000011111001000000000011100000000000000000011000

如何有效地找到未设置的位的范围。在这种情况下 (1,18) 和 (24,25) 和 (27,36) 等

下面是我目前写的代码,感觉效率不高,也不干净。

int startIndex = -1;
int nextIndex = -1;
for(int i = getSlotIndex(currentWorkingStartDate); i <= getSlotIndex(currentWorkingEndDate); i++) {
    if(!matrix.get(i)) {
        if(startIndex == -1) {
            startIndex = i;
            nextIndex = i;
        }else {
            nextIndex = i;
        }
    }else if(startIndex != -1){

        ZonedDateTime availableStartDate = day.plusHours((startIndex/4)).plusMinutes(startIndex%4 * 15);
        ZonedDateTime availableEndDate = availableStartDate.plusMinutes((nextIndex - startIndex + 1) * 15L);
        currAvailabilitySlots.addAll(
                getSlotsBasedOnDurationWithTimeZone(new SlotModel(availableStartDate,availableEndDate),durationOfSlot,candidateTimeZoneId));
        startIndex = -1;
        nextIndex = -1;
    }
}

if(startIndex != -1) {
    ZonedDateTime availableStartDate = day.plusHours((startIndex/4)).plusMinutes(startIndex%4 * 15);
    ZonedDateTime availableEndDate = availableStartDate.plusMinutes((nextIndex - startIndex) * 15L);
    currAvailabilitySlots.addAll(
            getSlotsBasedOnDurationWithTimeZone(new SlotModel(availableStartDate,availableEndDate),durationOfSlot,candidateTimeZoneId));
}

有一种方法可以获取给定索引处或之后的下一个未设置位:BitSet.nextClearBit(int)

有一个补充方法,nextSetBit(int),用于查找下一个设置位。

所以,你可以用前者找到范围的开始,用后者找到范围的结束。

您需要小心处理方法的 return 值:

  • 如果nextSetBit returns -1,这意味着当前运行个清除位扩展到BitSet的末尾。
  • nextClearBit 不会 return -1,因为 BitSet 没有 clearly-defined 的大小清除位 - 它们本质上无限扩展,但实际上只分配存储空间来保存设置位。因此,如果 nextClearBit returns 的值超出 BitSet 的 逻辑 大小(即超出 day/date范围),你知道你可以停止搜索。