← Назад к вопросам

Как работает битовая карта?

2.2 Middle🔥 41 комментариев
#Другое#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает битовая карта

Битовая карта (bitmap) — это эффективная структура данных для хранения информации о наличии/отсутствии элементов. Это один из классических примеров оптимизации памяти в программировании.

Основной принцип

Битовая карта использует один бит для хранения одного булевого значения (есть/нет, 0/1). В отличие от массива boolean, где каждый элемент занимает минимум 1 байт (8 бит), битовая карта экономит память в 8 раз.

Концептуально:

Обычный массив boolean: [true, false, true, false, true]
Память: 5 байт (40 бит) → 11010... в памяти

Битовая карта: 11010 (в одном байте)
Память: 1 байт (8 бит)

Реализация в Java

Используем массив целых чисел (обычно long):

public class BitMap {
    private long[] bits;
    private int size;
    
    public BitMap(int size) {
        this.size = size;
        // Каждый long содержит 64 бита
        this.bits = new long[(size + 63) / 64]; // Округляем вверх
    }
    
    // Установить бит в 1 (set)
    public void set(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index / 64;  // Какой long
        int bitIndex = index % 64;   // Какой бит внутри long
        bits[wordIndex] |= (1L << bitIndex);
    }
    
    // Установить бит в 0 (clear)
    public void clear(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index / 64;
        int bitIndex = index % 64;
        bits[wordIndex] &= ~(1L << bitIndex);
    }
    
    // Проверить значение бита
    public boolean get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index / 64;
        int bitIndex = index % 64;
        return (bits[wordIndex] & (1L << bitIndex)) != 0;
    }
}

Пример использования

BitMap bitmap = new BitMap(100);

// Отметить присутствие элементов 5, 10, 99
bitmap.set(5);
bitmap.set(10);
bitmap.set(99);

// Проверить
System.out.println(bitmap.get(5));   // true
System.out.println(bitmap.get(6));   // false
System.out.println(bitmap.get(99));  // true

// Удалить
bitmap.clear(10);
System.out.println(bitmap.get(10));  // false

Битовые операции

Операции, на которых это основано:

// Побитовое ИЛИ (OR) — установить бит
long word = 0b0000_0000;
word |= (1L << 3);  // Установить 3-й бит
// word = 0b0000_1000

// Побитовое И (AND) с инверсией — очистить бит
word &= ~(1L << 3); // Очистить 3-й бит
// word = 0b0000_0000

// Побитовое И для проверки
boolean isBitSet = (word & (1L << 3)) != 0;

Реальные применения

1. Фильтр Блума — вероятностная структура для быстрой проверки наличия элемента

public class BloomFilter {
    private BitMap bitMap;
    private int[] hashes;
    
    public void add(String element) {
        for (int h : hash(element)) {
            bitMap.set(h % bitMap.size());
        }
    }
    
    public boolean contains(String element) {
        for (int h : hash(element)) {
            if (!bitMap.get(h % bitMap.size())) {
                return false; // Определённо нет
            }
        }
        return true; // Вероятно да
    }
}

2. Кеширование и индексирование:

  • Быстрая проверка, какие страницы в памяти
  • Отслеживание занятых блоков на диске

3. Представление множества:

  • Вместо HashSet можно использовать битовую карту, если элементы — небольшие целые числа
// Вместо Set<Integer> для чисел 0-1000000
BitMap set = new BitMap(1000001);
set.set(5);
set.set(100);
// В 1000 раз меньше памяти!

Преимущества и недостатки

Преимущества:

  • ✅ Минимальное потребление памяти (1 бит на элемент)
  • ✅ O(1) операции set/clear/get
  • ✅ Быстрые побитовые операции для массовых проверок

Недостатки:

  • ❌ Работает только с небольшим диапазоном целых чисел
  • ❌ Не гибкая для больших разреженных множеств
  • ❌ Требует предварительного знания размера

Java BitSet класс

Java уже предоставляет встроенный класс:

BitSet bitSet = new BitSet(100);
bitSet.set(5);
bitSet.set(10);
bitSet.set(99);

System.out.println(bitSet.get(5));    // true
System.out.println(bitSet.cardinality()); // 3 — количество установленных битов

// Операции с множествами
BitSet other = new BitSet(100);
other.set(5);
other.set(6);
bitSet.and(other);   // Пересечение
bitSet.or(other);    // Объединение
bitSet.xor(other);   // Исключающее ИЛИ

Битовая карта — это красивый пример того, как глубокое понимание битовых операций и структур данных позволяет написать крайне эффективный код.