algorithm →
Массив без инициализации
Введение
Привет, хабр. Я хотел бы рассказать о забавной структуре данных под названием «Массив без инициализации».
Во многих языках программирования для корректной работы с массивом необходимо его инициализировать сразу после объявления. Будем считать, что инициализация есть присвоение всем элементам какого-либо одинакового значения. Если массив состоит из N элементов, алгоритмическая сложность этой операции — O(N). Однако, можно показать, что располагая в трое большим объемом памяти, можно обойтись инициализацией за O(1).
Алгоритм
Формализуем задачу: имея O(N) памяти, реализовать за O(1) операции инициализации,
set(value, index)
и get(index)
, где index
в пределах от 1 до N; при этом, если для операции get
не было соответствующего вызова set
ранее, необходимо генерировать исключение.Заведем переменную
count
, в которой будем хранить количество уже использованных элементов, инициализируем ее нулем. Кроме этого, объявим три массива длины N: arr
, ind
, cnt
.В
arr
будем хранить сами значения на соответствующих местах, а для ind
и cnt
поддерживать следующий инвариант:- значение
cnt[i]
корректно, еслиi <= count
;
- если
cnt[i]
корректно, тоind[cnt[i]] = i
иarr[cnt[i]]
— уже установленное значение.
Другими словами, в
ind
и cnt
хранятся ссылки друг на друга, только в ind
индексы соответствуют вызовам set
, a cnt
заполняется по-порядку. Реализуем процедуру проверки, используется ли уже данный элемент:
bool isEmpty(int i) {
if (ind[i] > 0 && ind[i] <= count && cnt[ind[i]] == i) {
// В случае, если указатели в ind и cnt установлены верно
// и порядковый номер не превышает общее число элементов,
// этот элемент используется.
return 0;
}
return 1;
}
Теперь научимся изменять какую-нибудь ячейку:
void set(int v, int i) {
arr[i] = v; // Устанавливаем значение
if (isEmpty(i)) {
// Если инициализации здесь еще не было
ind[i] = ++count; // Увеличиваем общее количество и делаем первую ссылку
cnt[count] = i; // Делаем вторую ссылку
}
}
А
get
выглядит совсем просто:int get(int i) {
if (isEmpty(i)) {
// Генерируем исключение, элемент не проинициализирован
} else {
return arr[i];
}
}
16.08.2011 13:58+0400