blob: 68e242ee7265a337ecd748aea4658adb97f70771 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ranger.plugin.geo;
public class BinarySearchTree<T extends Comparable<T> & RangeChecker<V>, V> {
private Node<T> root;
private int size;
public BinarySearchTree() {
root = null;
}
public void insert(final T value) {
Node<T> node = new Node<T>(value);
if (root == null) {
root = node;
return;
}
Node<T> focusNode = root;
Node<T> parent;
while (true) {
parent = focusNode;
int comparison = focusNode.getValue().compareTo(value);
if (comparison == 0) {
return;
}
if (comparison < 0) {
focusNode = focusNode.getRight();
if (focusNode == null) {
parent.setRight(node);
return;
}
} else {
focusNode = focusNode.getLeft();
if (focusNode == null) {
parent.setLeft(node);
return;
}
}
}
}
public T find(final V value) {
Node<T> focusNode = root;
int rangeCheck;
while (focusNode != null) {
rangeCheck = focusNode.getValue().compareToRange(value);
if (rangeCheck == 0) {
break;
} else if (rangeCheck < 0) {
focusNode = focusNode.getRight();
} else {
focusNode = focusNode.getLeft();
}
}
return focusNode == null ? null : focusNode.getValue();
}
final public void preOrderTraverseTree(final ValueProcessor<T> processor) {
preOrderTraverseTree(getRoot(), processor);
}
final public void inOrderTraverseTree(final ValueProcessor<T> processor) {
inOrderTraverseTree(getRoot(), processor);
}
Node<T> getRoot() {
return root;
}
void setRoot(final Node<T> newRoot) {
root = newRoot;
}
void rebalance() {
Node<T> dummy = new Node<T>(null);
dummy.setRight(root);
setRoot(dummy);
degenerate();
reconstruct();
setRoot(getRoot().getRight());
}
final void inOrderTraverseTree(final Node<T> focusNode, final ValueProcessor<T> processor) {
if (focusNode != null) {
inOrderTraverseTree(focusNode.getLeft(), processor);
processor.process(focusNode.getValue());
inOrderTraverseTree(focusNode.getRight(), processor);
}
}
final void preOrderTraverseTree(final Node<T> focusNode, final ValueProcessor<T> processor) {
if (focusNode != null) {
processor.process(focusNode.getValue());
preOrderTraverseTree(focusNode.getLeft(), processor);
preOrderTraverseTree(focusNode.getRight(), processor);
}
}
private void degenerate() {
Node<T> remainder, temp, sentinel;
sentinel = getRoot();
remainder = sentinel.getRight();
size = 0;
while (remainder != null) {
if (remainder.getLeft() == null) {
sentinel = remainder;
remainder = remainder.getRight();
size++;
} else {
temp = remainder.getLeft();
remainder.setLeft(temp.getRight());
temp.setRight(remainder);
remainder = temp;
sentinel.setRight(temp);
}
}
}
private void reconstruct() {
int sz = size;
Node<T> node = getRoot();
int fullCount = fullSize(sz);
rotateLeft(node, sz - fullCount);
for (sz = fullCount; sz > 1; sz /= 2) {
rotateLeft(node, sz / 2);
}
}
private void rotateLeft(Node<T> root, final int count) {
if (root == null) return;
Node<T> scanner = root;
for (int i = 0; i < count; i++) {
//Leftward rotation
Node<T> child = scanner.getRight();
scanner.setRight(child.getRight());
scanner = child.getRight();
child.setRight(scanner.getLeft());
scanner.setLeft(child);
}
}
private int fullSize(final int size) {
// Full portion of a complete tree
int ret = 1;
while (ret <= size) {
ret = 2*ret + 1;
}
return ret / 2;
}
static class Node<T> {
private T value;
private Node<T> left;
private Node<T> right;
public Node(final T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(final T value) {
this.value = value;
}
public Node<T> getLeft() {
return left;
}
public void setLeft(final Node<T> left) {
this.left = left;
}
public Node<T> getRight() {
return right;
}
public void setRight(final Node<T> right) {
this.right = right;
}
}
}