/*
* FenwickTree.java
*
* Copyright (C) 2010 Leo Osvald <leo.osvald@gmail.com>
*
* This file is part of SGLJ.
*
* SGLJ is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SGLJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sglj.util.struct;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
import org.sglj.math.discrete.CodomainMergeable;
import org.sglj.math.discrete.SubCodomainInheritable;
/**
* TODO
*
* @author Leo Osvald
*
* @param <E>
* @param <T>
*/
public abstract class FenwickTree<E, T>
extends AbstractIndexedStaticCollection<E>
implements RetrieveIndexQueryable<T>, RetrieveRangeQueryable<T>,
CodomainMergeable<T>, SubCodomainInheritable<T>, RandomAccess {
private final E[] elements;
private final T[] data;
private final boolean rightToLeft;
@SuppressWarnings("unchecked")
public FenwickTree(int size, boolean rightToLeft) {
this.elements = (E[]) new Object[size];
this.data = (T[]) new Object[size + 1];
for (int i = 1; i < data.length; ++i)
data[i] = createData(null);
this.rightToLeft = rightToLeft;
}
public FenwickTree(E[] elements, boolean rightToLeft) {
this(elements.length, rightToLeft);
for (int i = 0; i < elements.length; ++i)
set(i, elements[i]);
}
public FenwickTree(StaticCollection<? extends E> c, boolean rightToLeft) {
this(c.size(), rightToLeft);
int index = 0;
for (StaticIterator<? extends E> it = c.iterator(); it.hasNext(); )
set(index++, it.next());
}
public FenwickTree(Collection<? extends E> c, boolean rightToLeft) {
this(c.size(), rightToLeft);
int index = 0;
for (E e : c)
set(index++, e);
}
@Override
public E get(int index) {
return elements[index];
}
@Override
public void set(int index, E element) {
E oldElement = elements[index];
elements[index] = element;
T diff = inheritSubCodomain(createData(element), createData(oldElement));
if (!rightToLeft) {
for (++index; index < data.length; index += index & -index)
data[index] = mergeCodomains(data[index], diff);
} else {
for (++index; index > 0; index -= index & -index)
data[index] = mergeCodomains(data[index], diff);
}
}
@Override
public int size() {
int ret = 0;
for (int i = 1; i < elements.length; ++i)
if (elements[i] != null)
++ret;
return ret;
}
@Override
public int capacity() {
return elements.length;
}
@Override
public T retrieveQuery(int index) {
T ret = createData(null);
if (!rightToLeft) {
for (; index > 0; index -= index & -index)
ret = mergeCodomains(ret, data[index]);
} else {
for (++index; index < data.length; index += index & -index)
ret = mergeCodomains(ret, data[index]);
}
return ret;
}
@Override
public T retrieveQuery(int fromIndex, int toIndex) {
return inheritSubCodomain(
retrieveQuery(toIndex),
retrieveQuery(fromIndex));
}
public boolean isRightToLeft() {
return rightToLeft;
}
protected abstract T createData(E element);
@Override
public String toString() {
return super.toString() + "\n" + Arrays.toString(data);
}
}