com.google.common.collect.BstRangeOps Maven / Gradle / Ivy
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.BstSide.LEFT;
import static com.google.common.collect.BstSide.RIGHT;
import com.google.common.annotations.GwtCompatible;
import javax.annotation.Nullable;
/**
* A utility class with operations on binary search trees that operate on some interval.
*
* @author Louis Wasserman
*/
@GwtCompatible
final class BstRangeOps {
/**
* Returns the total value of the specified aggregation function on the specified tree restricted
* to the specified range. Assumes that the tree satisfies the binary search ordering property
* relative to {@code range.comparator()}.
*/
public static > long totalInRange(
BstAggregate super N> aggregate, GeneralRange range, @Nullable N root) {
checkNotNull(aggregate);
checkNotNull(range);
if (root == null || range.isEmpty()) {
return 0;
}
long total = aggregate.treeValue(root);
if (range.hasLowerBound()) {
total -= totalBeyondRangeToSide(aggregate, range, LEFT, root);
}
if (range.hasUpperBound()) {
total -= totalBeyondRangeToSide(aggregate, range, RIGHT, root);
}
return total;
}
// Returns total value strictly to the specified side of the specified range.
private static > long totalBeyondRangeToSide(
BstAggregate super N> aggregate, GeneralRange range, BstSide side, @Nullable N root) {
long accum = 0;
while (root != null) {
if (beyond(range, root.getKey(), side)) {
accum += aggregate.entryValue(root);
accum += aggregate.treeValue(root.childOrNull(side));
root = root.childOrNull(side.other());
} else {
root = root.childOrNull(side);
}
}
return accum;
}
/**
* Returns a balanced tree containing all nodes from the specified tree that were not in
* the specified range, using the specified balance policy. Assumes that the tree satisfies the
* binary search ordering property relative to {@code range.comparator()}.
*/
@Nullable
public static > N minusRange(GeneralRange range,
BstBalancePolicy balancePolicy, BstNodeFactory nodeFactory, @Nullable N root) {
checkNotNull(range);
checkNotNull(balancePolicy);
checkNotNull(nodeFactory);
N higher = range.hasUpperBound()
? subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, RIGHT, root)
: null;
N lower = range.hasLowerBound()
? subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, LEFT, root)
: null;
return balancePolicy.combine(nodeFactory, lower, higher);
}
/*
* Returns a balanced tree containing all nodes in the specified tree that are strictly to the
* specified side of the specified range.
*/
@Nullable
private static > N subTreeBeyondRangeToSide(GeneralRange range,
BstBalancePolicy balancePolicy, BstNodeFactory nodeFactory, BstSide side,
@Nullable N root) {
if (root == null) {
return null;
}
if (beyond(range, root.getKey(), side)) {
N left = root.childOrNull(LEFT);
N right = root.childOrNull(RIGHT);
switch (side) {
case LEFT:
right = subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, LEFT, right);
break;
case RIGHT:
left = subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, RIGHT, left);
break;
default:
throw new AssertionError();
}
return balancePolicy.balance(nodeFactory, root, left, right);
} else {
return subTreeBeyondRangeToSide(
range, balancePolicy, nodeFactory, side, root.childOrNull(side));
}
}
/**
* Returns the furthest path to the specified side in the specified tree that falls into the
* specified range.
*/
@Nullable
public static , P extends BstPath> P furthestPath(
GeneralRange range, BstSide side, BstPathFactory pathFactory, @Nullable N root) {
checkNotNull(range);
checkNotNull(pathFactory);
checkNotNull(side);
if (root == null) {
return null;
}
P path = pathFactory.initialPath(root);
return furthestPath(range, side, pathFactory, path);
}
private static , P extends BstPath> P furthestPath(
GeneralRange range, BstSide side, BstPathFactory pathFactory, P currentPath) {
N tip = currentPath.getTip();
K tipKey = tip.getKey();
if (beyond(range, tipKey, side)) {
if (tip.hasChild(side.other())) {
currentPath = pathFactory.extension(currentPath, side.other());
return furthestPath(range, side, pathFactory, currentPath);
} else {
return null;
}
} else if (tip.hasChild(side)) {
P alphaPath = pathFactory.extension(currentPath, side);
alphaPath = furthestPath(range, side, pathFactory, alphaPath);
if (alphaPath != null) {
return alphaPath;
}
}
return beyond(range, tipKey, side.other()) ? null : currentPath;
}
/**
* Returns {@code true} if {@code key} is beyond the specified side of the specified range.
*/
public static boolean beyond(GeneralRange range, @Nullable K key, BstSide side) {
checkNotNull(range);
switch (side) {
case LEFT:
return range.tooLow(key);
case RIGHT:
return range.tooHigh(key);
default:
throw new AssertionError();
}
}
private BstRangeOps() {}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy