Задача нахождения суммы элементов массива на интервале, методы её решения
29 ноября 2009 г.
Определение
Часто возникает задача, когда нужно посчитать сумму от i-го до j-го элемента в массиве A.
Формально определим её:
Найти sum = ![]()
Рассмотрим как такую задачу решают простым методом.
Методы решения
- Можно каждый раз суммировать элементы с
i-го поj-тый
Эффективность такого метода:
Обновление массива:O(1)
Вычисление суммы:O(n) - Можно завести дополнительный массив частичных сумм
P, гдеP[1] = A[1], P[i] = P[i-1] + A[i], i>1
И тогда сумма равна:
Sum =
| P[j] – P[i-1] , i>1
| P[j], i=1
Эффективность такого метода:
Обновление массива:O(n)
Вычисление суммы:O(1) - Оказывается можно объединить эти два метода и получить решение, которое способно обновлять массив и вычислять сумму более эффективно
Этот метод использует дерево Фенвика.
Дерево Фенвика — структура данных, позволяющая быстро изменять значения в массиве и находить некоторые функции от элементов массива. Впервые описано Питером Фенвиком в 1994 году. Дерево Фенвика напоминает дерево отрезков, однако проще в реализации.
Нужно хранить частичные суммы в исходном массиве не от начала до i-го, а от такого элемента, номер которого вычисляется по формуле:i-f(i)+1.
То естьP[i] = ? A[j], j € (i-f(i);i],гдеf(i)– максимальная степень двойки, на которую делитсяi.
Нетрудно убедиться, чтоf(i)=i?(i & (i?1)).
Пустьn— длина массиваA.
Выберем такое минимальноеk, что2^k >=n.
Тогда для хранения дерева Фенвика понадобится массивPиз2^kэлементов. Будем нумеровать их от1до2k.
В ячейкеP[i]будет храниться сумма в ячейках массиваAсi - f(i) + 1поi.
Исходный код для вычисления суммы с 1 по k
for(int i=k;i>0;i-=i&-i)
Sum+=P[i];
Исходный код для увеличения значения t-й ячейки массива A на число x:
for(int i=t;i<=n;i+=i&-i)
P[i]+=x;
В приведенном коде i&-i и есть то вычисление следующего f(i).
В итоге искомая сумма будет равна:
Sum =
| P[j] – P[i-1] , i>1
| P[j], i=1
Эффективность такого метода:
Обновление массива: O(log(n))
Вычисление суммы: O(log(n))
рубрика Программирование