BitSegmentedArray

Мне предоставили реализовать класс, который наследует SegmentedArray и характеризуется следующим:

  • принимает большой массив
  • элементы массива — 0 и 1
  • частые запросы get() и set()

Чтобы была возможность хранить очень большой массив, я решила построить класс с помощью битовых операций. Это было возможно, так как элемент моего массива — это 0 и 1, и любое число можно представить в виде последовательности нулей и единиц. Поэтому внутри класса если массив long, в одной ячейке которого может храниться до 64 элементов. Так была решена проблема с расходом памяти.

Из-за представления чисел в двоичном коде, к ним легко применимы битовые операции. Например, для реализации метода get() достаточно использовать битовый сдвиг и битовое «и». Следовательно, метод работает за О(1).

В реализации метода set() мне помогла блочная структура (64 элемента в 1 ячейке массива). А именно: я проверяю границы заданного отрезка, а ячейки, которые попали внутрь полностью просто приравниваю константе: 0 — если все элементы ячейки нули, -1 — если все элементы ячейки единицы.

Точно так же реализован метод add().

С методом min() всё и того проще: ответом служит либо 0, либо 1. Первый же ноль, встреченный на заданном отрезке, определяет ответ.

Также я предположила, что, как и в большинстве олимпиадных задач, индексация массива начинается с единицы. То есть в методе get(), set(), add() и min() необходима сначала уменьшить каждый индекс на единицу, а лишь потом проводить операции над массивом, так как индексация в нём начинается с нуля.

Теоретическая оценка сложности методов:

  • get(i): O(1);
  • set(x, y, val): O((y-x)/64);
  • add(x, y, val): O((y-x)/64) — для val%2==1, и O(1) — для val%2==0;
  • min(x, y) — O((x-y)/64) — в худшем случае (на отрезке все элементы нули), O(1) — в лучшем случае (на отрезке все элементы единицы).

Код программы:

Протестировать программу можно здесь.

Простейшая реализация интерфейса: SimpleSegmentedArray.

Сравнение скорости работы методов: