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
