java实现kd树代码,java 关于区间树,KD树,线段树,舒展树,后缀树,红黑树的几段代码...

java 关于区间树,KD树,线段树,伸展树,后缀树,红黑树的几段代码

区间树

可以统计某个区间对应的重复的区间

package com.jwetherell.algorithms.data_structures;

import java.security.InvalidParameterException;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.Iterator;

import java.util.List;

import java.util.Set;

import java.util.TreeSet;

/**

* An interval tree is an ordered tree data structure to hold intervals. Specifically, it

* allows one to efficiently find all intervals that overlap with any given interval or point.

*

* http://en.wikipedia.org/wiki/Interval_tree

*

* @author Justin Wetherell

*/

public class IntervalTree {

private Interval root = null;

private static final Comparator> startComparator = new Comparator>(){

/**

* {@inheritDoc}

*/

@Override

public int compare(IntervalData> arg0, IntervalData> arg1) {

if (arg0.start

if (arg1.start

return 0;

}

};

private static final Comparator> endComparator = new Comparator>(){

/**

* {@inheritDoc}

*/

@Override

public int compare(IntervalData> arg0, IntervalData> arg1) {

if (arg0.end

if (arg1.end

return 0;

}

};

/**

* Create interval tree from list of IntervalData objects;

*

* @param intervals is a list of IntervalData objects

*/

public IntervalTree(List> intervals) {

if (intervals.size()<=0) return;

root = createFromList(intervals);

}

protected static final Interval createFromList(List> intervals) {

Interval newInterval = new Interval();

int half = intervals.size()/2;

IntervalData middle = intervals.get(half);

newInterval.center = ((middle.start+middle.end)/2);

List> leftIntervals = new ArrayList>();

List> rightIntervals = new ArrayList>();

for (IntervalData interval : intervals) {

if (interval.end

leftIntervals.add(interval);

} else if (interval.start>newInterval.center) {

rightIntervals.add(interval);

} else {

newInterval.overlap.add(interval);

}

}

if (leftIntervals.size()>0) newInterval.left = createFromList(leftIntervals);

if (rightIntervals.size()>0) newInterval.right = createFromList(rightIntervals);

return newInterval;

}

/**

* Stabbing query

*

* @param index to query for.

* @return data at index.

*/

public IntervalData query(long index) {

return root.query(index);

}

/**

* Range query

*

* @param start of range to query for.

* @param end of range to query for.

* @return data for range.

*/

public IntervalData query(long start, long end) {

return root.query(start, end);

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(IntervalTreePrinter.getString(this));

return builder.toString();

}

protected static class IntervalTreePrinter {

public static String getString(IntervalTree tree) {

if (tree.root == null) return "Tree has no nodes.";

return getString(tree.root, "", true);

}

private static String getString(Interval interval, String prefix, boolean isTail) {

StringBuilder builder = new StringBuilder();

builder.append( prefix + (isTail ? "└── " : "├── ") + interval.toString() + "\n" );

List> children = new ArrayList>();

if (interval.left!=null) children.add(interval.left);

if (interval.right!=null) children.add(interval.right);

if (children.size()>0) {

for (int i = 0; i < children.size() - 1; i++) {

builder.append(getString(children.get(i), prefix + (isTail ? " " : "│ "), false));

}

if (children.size() > 0) {

builder.append(getString(children.get(children.size() - 1), prefix + (isTail ? " " : "│ "), true));

}

}

return builder.toString();

}

}

public static final class Interval {

private long center = Long.MIN_VALUE;

private Interval left = null;

private Interval right = null;

private Set> overlap = new TreeSet>(startComparator);

/**

* Stabbing query

*

* @param index to query for.

* @return data at index.

*/

public IntervalData query(long index) {

IntervalData results = null;

if (index

//overlap is sorted by start point

for (IntervalData data : overlap) {

if (data.start>index) break;

IntervalData temp = data.query(index);

if (results==null && temp!=null) results = temp;

else if (temp!=null) results.combined(temp);

}

} else if (index>=center) {

//overlapEnd is sorted by end point

Set> overlapEnd = new TreeSet>(endComparator);

overlapEnd.addAll(overlap);

for (IntervalData data : overlapEnd) {

if (data.end

IntervalData temp = data.query(index);

if (results==null && temp!=null) results = temp;

else if (temp!=null) results.combined(temp);

}

}

if (index

if (left!=null) {

IntervalData temp = left.query(index);

if (results==null && temp!=null) results = temp;

else if (temp!=null) results.combined(temp);

}

} else if (index>=center) {

if (right!=null) {

IntervalData temp = right.query(index);

if (results==null && temp!=null) results = temp;

else if (temp!=null) results.combined(temp);

}

}

return results;

}

/**

* Range query

*

* @param start of range to query for.

* @param end of range to query for.

* @return data for range.

*/

public IntervalData query(long start, long end) {

IntervalData results = null;

for (IntervalData data : overlap) {

if (data.start > end) break;

IntervalData temp = data.query(start,end);

if (results==null && temp!=null) results = temp;

else if (temp!=null) results.combined(temp);

}

if (left!=null && start

IntervalData temp = left.query(start,end);

if (temp!=null && results==null) results = temp;

else if (temp!=null) results.combined(temp);

}

if (right!=null && end>=center) {

IntervalData temp = right.query(start,end);

if (temp!=null && results==null) results = temp;

else if (temp!=null) results.combined(temp);

}

return results;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("Center=").append(center);

builder.append(" Set=").append(overlap);

return builder.toString();

}

}

/**

* Data structure representing an interval.

*/

public static final class IntervalData implements Comparable>{

private long start = Long.MIN_VALUE;

private long end = Long.MAX_VALUE;

private Set set = new TreeSet(); //Sorted

/**

* Interval data using O as it's unique identifier

* @param object Object which defines the interval data

*/

public IntervalData(long index, O object) {

this.start = index;

this.end = index;

this.set.add(object);

}

/**

* Interval data using O as it's unique identifier

* @param object Object which defines the interval data

*/

public IntervalData(long start, long end, O object) {

this.start = start;

this.end = end;

this.set.add(object);

}

/**

* Interval data list which should all be unique

* @param list of interval data objects

*/

public IntervalData(long start, long end, Set set) {

this.start = start;

this.end = end;

this.set = set;

//Make sure they are unique

Iterator iter = set.iterator();

while (iter.hasNext()) {

O obj1 = iter.next();

O obj2 = null;

if (iter.hasNext()) obj2 = iter.next();

if (obj1.equals(obj2)) throw new InvalidParameterException("Each interval data in the list must be unique.");

}

}

/**

* Clear the indices.

*/

public void clear() {

this.start = Long.MIN_VALUE;

this.end = Long.MAX_VALUE;

this.set.clear();

}

/**

* Combined this IntervalData with data.

*

* @param data to combined with.

* @return Data which represents the combination.

*/

public IntervalData combined(IntervalData data) {

if (data.start

if (data.end>this.end) this.end = data.end;

this.set.addAll(data.set);

return this;

}

/**

* Deep copy of data.

*

* @return deep copy.

*/

public IntervalData copy() {

Set listCopy = new TreeSet();

listCopy.addAll(set);

return new IntervalData(start,end,listCopy);

}

/**

* Query inside this data object.

*

* @param start of range to query for.

* @param end of range to query for.

* @return Data queried for or NULL if it doesn't match the query.

*/

public IntervalData query(long index) {

if (indexthis.end) {

//Ignore

} else {

return copy();

}

return null;

}

/**

* Query inside this data object.

*

* @param start of range to query for.

* @param end of range to query for.

* @return Data queried for or NULL if it doesn't match the query.

*/

public IntervalData query(long start, long end) {

if (endthis.end) {

//Ignore

} else {

return copy();

}

return null;

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof IntervalData)) return false;

@SuppressWarnings("unchecked")

IntervalData data = (IntervalData) obj;

if (this.start==data.start && this.end==data.end) {

if (this.set.size()!=data.set.size()) return false;

for (O o : set) {

if (!data.set.contains(o)) return false;

}

return true;

}

return false;

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(IntervalData d) {

if (this.end < d.end) return -1;

if (d.end < this.end) return 1;

return 0;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(start).append("->").append(end);

builder.append(" set=").append(set);

return builder.toString();

}

}

}

KD树,统计某个点最近的区间

package com.jwetherell.algorithms.data_structures;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Collections;

import java.util.Comparator;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import java.util.TreeSet;

/**

* A k-d tree (short for k-dimensional tree) is a space-partitioning data structure for organizing

* points in a k-dimensional space. k-d trees are a useful data structure for several applications,

* such as searches involving a multidimensional search key (e.g. range searches and nearest neighbor

* searches). k-d trees are a special case of binary space partitioning trees.

*

* http://en.wikipedia.org/wiki/K-d_tree

*

* @author Justin Wetherell

*/

public class KdTree {

private int k = 3;

private KdNode root = null;

private static final Comparator X_COMPARATOR = new Comparator() {

/**

* {@inheritDoc}

*/

@Override

public int compare(XYZPoint o1, XYZPoint o2) {

if (o1.x

if (o1.x>o2.x) return 1;

return 0;

}

};

private static final Comparator Y_COMPARATOR = new Comparator() {

/**

* {@inheritDoc}

*/

@Override

public int compare(XYZPoint o1, XYZPoint o2) {

if (o1.y

if (o1.y>o2.y) return 1;

return 0;

}

};

private static final Comparator Z_COMPARATOR = new Comparator() {

/**

* {@inheritDoc}

*/

@Override

public int compare(XYZPoint o1, XYZPoint o2) {

if (o1.z

if (o1.z>o2.z) return 1;

return 0;

}

};

protected static final int X_AXIS = 0;

protected static final int Y_AXIS = 1;

protected static final int Z_AXIS = 2;

/**

* Default constructor.

*/

public KdTree() { }

/**

* More efficient constructor.

*

* @param list of XYZPoints.

*/

public KdTree(List list) {

root = createNode(list, k, 0);

}

/**

* Create node from list of XYZPoints.

*

* @param list of XYZPoints.

* @param k of the tree.

* @param depth depth of the node.

* @return node created.

*/

private static KdNode createNode(List list, int k, int depth) {

if (list==null || list.size()==0) return null;

int axis = depth % k;

if (axis==X_AXIS) Collections.sort(list, X_COMPARATOR);

else if (axis==Y_AXIS) Collections.sort(list, Y_COMPARATOR);

else Collections.sort(list, Z_COMPARATOR);

int mediaIndex = list.size()/2;

KdNode node = new KdNode(k,depth,list.get(mediaIndex));

if (list.size()>0) {

if ((mediaIndex-1)>=0) {

List less = list.subList(0, mediaIndex);

if (less.size()>0) {

node.lesser = createNode(less,k,depth+1);

node.lesser.parent = node;

}

}

if ((mediaIndex+1)<=(list.size()-1)) {

List more = list.subList(mediaIndex+1, list.size());

if (more.size()>0) {

node.greater = createNode(more,k,depth+1);

node.greater.parent = node;

}

}

}

return node;

}

/**

* Add value to the tree. Tree can contain multiple equal values.

*

* @param value T to add to the tree.

* @return True if successfully added to tree.

*/

public boolean add(T value) {

if (value==null) return false;

if (root==null) {

root = new KdNode(value);

return true;

}

KdNode node = root;

while (true) {

if (KdNode.compareTo(node.depth, node.k, node.id, value)<=0) {

//Lesser

if (node.lesser==null) {

KdNode newNode = new KdNode(k,node.depth+1,value);

newNode.parent = node;

node.lesser = newNode;

break;

} else {

node = node.lesser;

}

} else {

//Greater

if (node.greater==null) {

KdNode newNode = new KdNode(k,node.depth+1,value);

newNode.parent = node;

node.greater = newNode;

break;

} else {

node = node.greater;

}

}

}

return true;

}

/**

* Does the tree contain the value.

*

* @param value T to locate in the tree.

* @return True if tree contains value.

*/

public boolean contains(T value) {

if (value==null) return false;

KdNode node = getNode(this,value);

return (node!=null);

}

/**

* Locate T in the tree.

*

* @param tree to search.

* @param value to search for.

* @return KdNode or NULL if not found

*/

private static final KdNode getNode(KdTree tree, T value) {

if (tree==null || tree.root==null || value==null) return null;

KdNode node = tree.root;

while (true) {

if (node.id.equals(value)) {

return node;

} else if (KdNode.compareTo(node.depth, node.k, node.id, value)<0) {

//Greater

if (node.greater==null) {

return null;

} else {

node = node.greater;

}

} else {

//Lesser

if (node.lesser==null) {

return null;

} else {

node = node.lesser;

}

}

}

}

/**

* Remove first occurrence of value in the tree.

*

* @param value T to remove from the tree.

* @return True if value was removed from the tree.

*/

public boolean remove(T value) {

if (value==null) return false;

KdNode node = getNode(this,value);

if (node==null) return false;

KdNode parent = node.parent;

if (parent!=null) {

if (parent.lesser!=null && node.equals(parent.lesser)) {

List nodes = getTree(node);

if (nodes.size()>0) {

parent.lesser = createNode(nodes,node.k,node.depth);

if (parent.lesser!=null) {

parent.lesser.parent = parent;

}

} else {

parent.lesser = null;

}

} else {

List nodes = getTree(node);

if (nodes.size()>0) {

parent.greater = createNode(nodes,node.k,node.depth);

if (parent.greater!=null) {

parent.greater.parent = parent;

}

} else {

parent.greater = null;

}

}

} else {

//root

List nodes = getTree(node);

if (nodes.size()>0) root = createNode(nodes,node.k,node.depth);

else root = null;

}

return true;

}

/**

* Get the (sub) tree rooted at root.

*

* @param root of tree to get nodes for.

* @return points in (sub) tree, not including root.

*/

private static final List getTree(KdNode root) {

List list = new ArrayList();

if (root==null) return list;

if (root.lesser!=null) {

list.add(root.lesser.id);

list.addAll(getTree(root.lesser));

}

if (root.greater!=null) {

list.add(root.greater.id);

list.addAll(getTree(root.greater));

}

return list;

}

/**

* K Nearest Neighbor search

*

* @param K Number of neighbors to retrieve. Can return more than K, if last nodes are equal distances.

* @param value to find neighbors of.

* @return collection of T neighbors.

*/

@SuppressWarnings("unchecked")

public Collection nearestNeighbourSearch(int K, T value) {

if (value==null) return null;

//Map used for results

TreeSet results = new TreeSet(new EuclideanComparator(value));

//Find the closest leaf node

KdNode prev = null;

KdNode node = root;

while (node!=null) {

if (KdNode.compareTo(node.depth, node.k, node.id, value)<0) {

//Greater

prev = node;

node = node.greater;

} else {

//Lesser

prev = node;

node = node.lesser;

}

}

KdNode leaf = prev;

if (leaf!=null) {

//Used to not re-examine nodes

Set examined = new HashSet();

//Go up the tree, looking for better solutions

node = leaf;

while (node!=null) {

//Search node

searchNode(value,node,K,results,examined);

node = node.parent;

}

}

//Load up the collection of the results

Collection collection = new ArrayList(K);

for (KdNode kdNode : results) {

collection.add((T)kdNode.id);

}

return collection;

}

private static final void searchNode(T value, KdNode node, int K, TreeSet results, Set examined) {

examined.add(node);

//Search node

KdNode lastNode = null;

Double lastDistance = Double.MAX_VALUE;

if (results.size()>0) {

lastNode = results.last();

lastDistance = lastNode.id.euclideanDistance(value);

}

Double nodeDistance = node.id.euclideanDistance(value);

if (nodeDistance.compareTo(lastDistance)<0) {

if (results.size()==K && lastNode!=null) results.remove(lastNode);

results.add(node);

} else if (nodeDistance.equals(lastDistance)) {

results.add(node);

} else if (results.size()

results.add(node);

}

lastNode = results.last();

lastDistance = lastNode.id.euclideanDistance(value);

int axis = node.depth % node.k;

KdNode lesser = node.lesser;

KdNode greater = node.greater;

//Search children branches, if axis aligned distance is less than current distance

if (lesser!=null && !examined.contains(lesser)) {

examined.add(lesser);

double nodePoint = Double.MIN_VALUE;

double valuePlusDistance = Double.MIN_VALUE;

if (axis==X_AXIS) {

nodePoint = node.id.x;

valuePlusDistance = value.x-lastDistance;

} else if (axis==Y_AXIS) {

nodePoint = node.id.y;

valuePlusDistance = value.y-lastDistance;

} else {

nodePoint = node.id.z;

valuePlusDistance = value.z-lastDistance;

}

boolean lineIntersectsCube = ((valuePlusDistance<=nodePoint)?true:false);

//Continue down lesser branch

if (lineIntersectsCube) searchNode(value,lesser,K,results,examined);

}

if (greater!=null && !examined.contains(greater)) {

examined.add(greater);

double nodePoint = Double.MIN_VALUE;

double valuePlusDistance = Double.MIN_VALUE;

if (axis==X_AXIS) {

nodePoint = node.id.x;

valuePlusDistance = value.x+lastDistance;

} else if (axis==Y_AXIS) {

nodePoint = node.id.y;

valuePlusDistance = value.y+lastDistance;

} else {

nodePoint = node.id.z;

valuePlusDistance = value.z+lastDistance;

}

boolean lineIntersectsCube = ((valuePlusDistance>=nodePoint)?true:false);

//Continue down greater branch

if (lineIntersectsCube) searchNode(value,greater,K,results,examined);

}

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

return TreePrinter.getString(this);

}

protected static class EuclideanComparator implements Comparator {

private XYZPoint point = null;

public EuclideanComparator(XYZPoint point) {

this.point = point;

}

/**

* {@inheritDoc}

*/

@Override

public int compare(KdNode o1, KdNode o2) {

Double d1 = point.euclideanDistance(o1.id);

Double d2 = point.euclideanDistance(o2.id);

if (d1.compareTo(d2)<0) return -1;

else if (d2.compareTo(d1)<0) return 1;

return o1.id.compareTo(o2.id);

}

};

public static class KdNode implements Comparable {

private int k = 3;

private int depth = 0;

private XYZPoint id = null;

private KdNode parent = null;

private KdNode lesser = null;

private KdNode greater = null;

public KdNode(XYZPoint id) {

this.id = id;

}

public KdNode(int k, int depth, XYZPoint id) {

this(id);

this.k = k;

this.depth = depth;

}

public static int compareTo(int depth, int k, XYZPoint o1, XYZPoint o2) {

int axis = depth % k;

if (axis==X_AXIS) return X_COMPARATOR.compare(o1, o2);

return Y_COMPARATOR.compare(o1, o2);

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (obj==null) return false;

if (!(obj instanceof KdNode)) return false;

KdNode kdNode = (KdNode) obj;

if (this.compareTo(kdNode)==0) return true;

return false;

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(KdNode o) {

return compareTo(depth, k, this.id, o.id);

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("k=").append(k);

builder.append(" depth=").append(depth);

builder.append(" id=").append(id.toString());

return builder.toString();

}

}

public static class XYZPoint implements Comparable {

private double x = Double.NEGATIVE_INFINITY;

private double y = Double.NEGATIVE_INFINITY;

private double z = Double.NEGATIVE_INFINITY;

public XYZPoint(double x, double y) {

this.x = x;

this.y = y;

this.z = 0;

}

public XYZPoint(double x, int y, double z) {

this.x = x;

this.y = y;

this.z = z;

}

/**

* Computes the Euclidean distance from this point to the other.

*

* @param o1 other point.

* @return euclidean distance.

*/

public double euclideanDistance(XYZPoint o1) {

return euclideanDistance(o1,this);

}

/**

* Computes the Euclidean distance from one point to the other.

*

* @param o1 first point.

* @param o2 second point.

* @return euclidean distance.

*/

private static final double euclideanDistance(XYZPoint o1, XYZPoint o2) {

return Math.sqrt(Math.pow((o1.x-o2.x),2)+Math.pow((o1.y-o2.y),2)+Math.pow((o1.z-o2.z),2));

};

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (obj == null) return false;

if (!(obj instanceof XYZPoint)) return false;

XYZPoint xyzPoint = (XYZPoint) obj;

int xComp = X_COMPARATOR.compare(this, xyzPoint);

if (xComp!=0) return false;

int yComp = Y_COMPARATOR.compare(this, xyzPoint);

return (yComp==0);

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(XYZPoint o) {

int xComp = X_COMPARATOR.compare(this, o);

if (xComp!=0) return xComp;

int yComp = Y_COMPARATOR.compare(this, o);

return yComp;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("(");

builder.append(x).append(", ");

builder.append(y).append(", ");

builder.append(z);

builder.append(")");

return builder.toString();

}

}

protected static class TreePrinter {

public static String getString(KdTree tree) {

if (tree.root == null) return "Tree has no nodes.";

return getString(tree.root, "", true);

}

private static > String getString(KdNode node, String prefix, boolean isTail) {

StringBuilder builder = new StringBuilder();

if (node.parent!=null) {

String side = "left";

if (node.parent.greater!=null && node.id.equals(node.parent.greater.id)) side = "right";

builder.append(prefix + (isTail ? "└── " : "├── ") + "[" + side + "] " + "depth=" + node.depth + " id=" + node.id + "\n");

} else {

builder.append(prefix + (isTail ? "└── " : "├── ") + "depth=" + node.depth + " id=" + node.id + "\n");

}

List children = null;

if (node.lesser != null || node.greater != null) {

children = new ArrayList(2);

if (node.lesser != null) children.add(node.lesser);

if (node.greater != null) children.add(node.greater);

}

if (children != null) {

for (int i = 0; i < children.size() - 1; i++) {

builder.append(getString(children.get(i), prefix + (isTail ? " " : "│ "), false));

}

if (children.size() >= 1) {

builder.append(getString(children.get(children.size() - 1), prefix + (isTail ? " " : "│ "), true));

}

}

return builder.toString();

}

}

}

红黑树

package com.jwetherell.algorithms.data_structures;

import java.util.ArrayList;

import java.util.List;

/**

* A red–black tree is a type of self-balancing binary search tree, a data structure

* used in computer science, typically to implement associative arrays. A red–black tree

* is a binary search tree that inserts and deletes in such a way that the tree is always

* reasonably balanced. Red-black trees are often compared with AVL trees. AVL trees are

* more rigidly balanced, they are faster than red-black trees for lookup intensive

* applications. However, red-black trees are faster for insertion and removal.

*

* http://en.wikipedia.org/wiki/Red%E2%80%93black_tree

*

* @author Justin Wetherell

*/

public class RedBlackTree> extends BinarySearchTree implements BinarySearchTree.INodeCreator {

protected static final boolean BLACK = false;

protected static final boolean RED = true;

/**

* Default constructor.

*/

public RedBlackTree() {

this.creator = this;

}

/**

* Constructor with external Node creator.

*/

public RedBlackTree(INodeCreator creator) {

super(creator);

}

/**

* {@inheritDoc}

*/

@Override

protected Node addValue(T id) {

RedBlackNode nodeAdded = null;

boolean added = false;

if (root == null) {

//Case 1 - The current node is at the root of the tree.

if (this.creator==null) {

root = new RedBlackNode(null, id, BLACK);

root.lesser = new RedBlackNode(root,null,BLACK);

root.greater = new RedBlackNode(root,null,BLACK);

} else {

root = this.creator.createNewNode(null, id);

((RedBlackNode)root).color = BLACK;

root.lesser = this.creator.createNewNode(root,null);

((RedBlackNode)root.lesser).color = BLACK;

root.greater = this.creator.createNewNode(root,null);

((RedBlackNode)root.greater).color = BLACK;

}

nodeAdded = (RedBlackNode) root;

added = true;

} else {

//Insert node like a BST would

Node node = root;

while (node != null) {

if (node.id==null) {

node.id = id;

((RedBlackNode)node).color = RED;

if (this.creator==null) {

node.lesser = new RedBlackNode(node,null,BLACK);

node.greater = new RedBlackNode(node,null,BLACK);

} else {

node.lesser = this.creator.createNewNode(node,null);

((RedBlackNode)node.lesser).color = BLACK;

node.greater = this.creator.createNewNode(node,null);

((RedBlackNode)node.greater).color = BLACK;

}

nodeAdded = (RedBlackNode) node;

added = true;

break;

} else if (id.compareTo(node.id) <= 0) {

node = node.lesser;

} else {

node = node.greater;

}

}

}

if (added==true) {

balanceAfterInsert(nodeAdded);

size++;

}

return nodeAdded;

}

/**

* Post insertion balancing algorithm.

*

* @param node to begin balancing at.

* @return True if balanced.

*/

private void balanceAfterInsert(RedBlackNode node) {

RedBlackNode parent = (RedBlackNode) node.parent;

if (parent == null) {

//Case 1 - The current node is at the root of the tree.

node.color = BLACK;

return;

}

if (parent.color == BLACK) {

//Case 2 - The current node's parent is black, so property 4 (both children of every red node are black) is not invalidated.

return;

}

RedBlackNode grandParent = node.getGrandParent();

RedBlackNode uncle = node.getUncle();

if (parent.color==RED && uncle.color==RED) {

//Case 3 - If both the parent and the uncle are red, then both of them can be repainted black and the grandparent becomes

// red (to maintain property 5 (all paths from any given node to its leaf nodes contain the same number of black nodes)).

parent.color=BLACK;

uncle.color=BLACK;

if (grandParent!=null) {

grandParent.color=RED;

balanceAfterInsert(grandParent);

}

} else {

if (parent.color==RED && uncle.color==BLACK) {

//Case 4 - The parent is red but the uncle is black; also, the current node is the right child of parent, and parent in turn

// is the left child of its parent grandparent.

if (node.equals(parent.greater) && parent.equals(grandParent.lesser)) {

//right-left

rotateLeft(parent);

node = (RedBlackNode) node.lesser;

grandParent = node.getGrandParent();

parent = (RedBlackNode) node.parent;

uncle = node.getUncle();

} else if (node.equals(parent.lesser) && parent.equals(grandParent.greater)) {

//left-right

rotateRight(parent);

node = (RedBlackNode) node.greater;

grandParent = node.getGrandParent();

parent = (RedBlackNode) node.parent;

uncle = node.getUncle();

}

}

if (parent.color==RED && uncle.color==BLACK) {

//Case 5 - The parent is red but the uncle is black, the current node is the left child of parent, and parent is the left child of its parent G.

parent.color = BLACK;

grandParent.color = RED;

if (node.equals(parent.lesser) && parent.equals(grandParent.lesser)) {

//left-left

rotateRight(grandParent);

} else if (node.equals(parent.greater) && parent.equals(grandParent.greater)) {

//right-right

rotateLeft(grandParent);

}

}

}

}

/**

* {@inheritDoc}

*/

@Override

protected Node removeValue(T value) {

RedBlackNode nodeRemoved = (RedBlackNode) super.getNode(value);

if (nodeRemoved==null) return null;

if (nodeRemoved.isLeaf()) {

//No children

nodeRemoved.id = null;

if (nodeRemoved.parent==null) {

root = null;

} else {

nodeRemoved.id = null;

nodeRemoved.color = BLACK;

nodeRemoved.lesser = null;

nodeRemoved.greater = null;

}

} else {

//At least one child

RedBlackNode lesser = (RedBlackNode) nodeRemoved.lesser;

RedBlackNode greater = (RedBlackNode) nodeRemoved.greater;

if (lesser.id!=null && greater.id!=null) {

//Two children

RedBlackNode greatestInLesser = (RedBlackNode) this.getGreatest(lesser);

if (greatestInLesser==null || greatestInLesser.id==null) greatestInLesser = lesser;

//Replace node with greatest in his lesser tree, which leaves us with only one child

replaceValueOnly(nodeRemoved,greatestInLesser);

nodeRemoved = greatestInLesser;

}

//Handle one child

RedBlackNode child = (RedBlackNode)((nodeRemoved.lesser.id!=null)?nodeRemoved.lesser:nodeRemoved.greater);

if (nodeRemoved.color==BLACK) {

if (child.color==BLACK) {

nodeRemoved.color = RED;

}

boolean result = balanceAfterDelete(nodeRemoved);

if (!result) return null;

}

replaceWithChild(nodeRemoved,child);

if (root.equals(nodeRemoved) && nodeRemoved.isLeaf()) {

//If we replaced the root with a leaf, just null out root

root = null;

}

}

size--;

return nodeRemoved;

}

/**

* Replace value of nodeToReplaceWith with nodeToReplace.

*

* @param nodeToReplace will get value of nodeToReplaceWith.

* @param nodeToReplaceWith will get value NULLed.

*/

private void replaceValueOnly(RedBlackNode nodeToReplace, RedBlackNode nodeToReplaceWith) {

nodeToReplace.id = nodeToReplaceWith.id;

nodeToReplaceWith.id = null;

}

/**

* Replace entire contents of nodeToReplace with nodeToReplaceWith.

*

* @param nodeToReplace will get it's contents replace with nodeToReplaceWith contents.

* @param nodeToReplaceWith will not be changed.

*/

private void replaceWithChild(RedBlackNode nodeToReplace, RedBlackNode nodeToReplaceWith) {

nodeToReplace.id = nodeToReplaceWith.id;

nodeToReplace.color = nodeToReplaceWith.color;

//root should always be black

if (nodeToReplace.parent==null) nodeToReplace.color = BLACK;

nodeToReplace.lesser = nodeToReplaceWith.lesser;

nodeToReplace.greater = nodeToReplaceWith.greater;

}

/**

* Post delete balancing algorithm.

*

* @param node to begin balancing at.

* @return True if balanced or false if error.

*/

private boolean balanceAfterDelete(RedBlackNode node) {

if (node.parent==null) {

//Case 1 - node is the new root.

return true;

}

RedBlackNode parent = (RedBlackNode) node.parent;

RedBlackNode sibling = node.getSibling();

if (sibling.color==RED) {

//Case 2 - sibling is red.

parent.color = RED;

sibling.color = BLACK;

if (node.equals(parent.lesser)) {

rotateLeft(parent);

//Rotation, need to update parent/sibling

parent = (RedBlackNode) node.parent;

sibling = node.getSibling();

} else if (node.equals(parent.greater)) {

rotateRight(parent);

//Rotation, need to update parent/sibling

parent = (RedBlackNode) node.parent;

sibling = node.getSibling();

} else {

System.err.println("Yikes! I'm not related to my parent.");

return false;

}

}

if (parent.color==BLACK &&

sibling.color==BLACK &&

((RedBlackNode)sibling.lesser).color==BLACK &&

((RedBlackNode)sibling.greater).color==BLACK

) {

//Case 3 - parent, sibling, and sibling's children are black.

sibling.color = RED;

boolean result = balanceAfterDelete(parent);

if (!result) return false;

} else if (parent.color==RED &&

sibling.color==BLACK &&

((RedBlackNode)sibling.lesser).color==BLACK &&

((RedBlackNode)sibling.greater).color==BLACK

) {

//Case 4 - sibling and sibling's children are black, but parent is red.

sibling.color = RED;

parent.color = BLACK;

} else {

if (sibling.color==BLACK) {

//Case 5 - sibling is black, sibling's left child is red, sibling's right child is black, and node is the left child of its parent.

if (node.equals(parent.lesser) &&

((RedBlackNode)sibling.lesser).color==RED &&

((RedBlackNode)sibling.greater).color==BLACK

) {

sibling.color = RED;

((RedBlackNode)sibling.lesser).color = RED;

rotateRight(sibling);

//Rotation, need to update parent/sibling

parent = (RedBlackNode) node.parent;

sibling = node.getSibling();

} else if (node.equals(parent.greater) &&

((RedBlackNode)sibling.lesser).color==BLACK &&

((RedBlackNode)sibling.greater).color==RED

) {

sibling.color = RED;

((RedBlackNode)sibling.greater).color = RED;

rotateLeft(sibling);

//Rotation, need to update parent/sibling

parent = (RedBlackNode) node.parent;

sibling = node.getSibling();

}

}

//Case 6 - sibling is black, sibling's right child is red, and node is the left child of its parent.

sibling.color = parent.color;

parent.color = BLACK;

if (node.equals(parent.lesser)) {

((RedBlackNode)sibling.greater).color = BLACK;

rotateLeft(node.parent);

} else if (node.equals(parent.greater)) {

((RedBlackNode)sibling.lesser).color = BLACK;

rotateRight(node.parent);

} else {

System.err.println("Yikes! I'm not related to my parent. "+node.toString());

return false;

}

}

return true;

}

/**

* {@inheritDoc}

*/

@Override

public boolean validate() {

if (root==null) return true;

if (((RedBlackNode)root).color == RED) {

//Root node should be black

return false;

}

return this.validateNode(root);

}

/**

* {@inheritDoc}

*/

@Override

protected boolean validateNode(Node node) {

RedBlackNode rbNode = (RedBlackNode) node;

RedBlackNode lesser = (RedBlackNode) rbNode.lesser;

RedBlackNode greater = (RedBlackNode) rbNode.greater;

if (rbNode.isLeaf() && rbNode.color==RED) {

//Leafs should not be red

return false;

}

if (rbNode.color==RED) {

//You should not have two red nodes in a row

if (lesser.color==RED) return false;

if (greater.color==RED) return false;

}

if (!lesser.isLeaf()) {

//Check BST property

boolean lesserCheck = lesser.id.compareTo(rbNode.id)<=0;

if (!lesserCheck) return false;

//Check red-black property

lesserCheck = this.validateNode(lesser);

if (!lesserCheck) return false;

}

if (!greater.isLeaf()) {

//Check BST property

boolean greaterCheck = greater.id.compareTo(rbNode.id)>0;

if (!greaterCheck) return false;

//Check red-black property

greaterCheck = this.validateNode(greater);

if (!greaterCheck) return false;

}

return true;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

return RedBlackTreePrinter.getString(this);

}

/**

* {@inheritDoc}

*/

@Override

public Node createNewNode(Node parent, T id) {

return (new RedBlackNode(parent, id, BLACK));

}

protected static class RedBlackNode> extends Node {

protected boolean color = BLACK;

protected RedBlackNode(Node parent, T id, boolean color) {

super(parent,id);

this.color = color;

}

protected RedBlackNode getGrandParent() {

if (parent==null || parent.parent==null) return null;

return (RedBlackNode) parent.parent;

}

protected RedBlackNode getUncle() {

RedBlackNode grandParent = getGrandParent();

if (grandParent == null) return null;

if (grandParent.lesser!=null && grandParent.lesser.equals(parent)) {

return (RedBlackNode) grandParent.greater;

} else if (grandParent.greater!=null && grandParent.greater.equals(parent)) {

return (RedBlackNode) grandParent.lesser;

}

return null;

}

protected RedBlackNode getSibling() {

if (parent==null) return null;

if (parent.lesser.equals(this)) {

return (RedBlackNode) parent.greater;

} else if (parent.greater.equals(this)) {

return (RedBlackNode) parent.lesser;

} else {

System.err.println("Yikes! I'm not my parents child.");

}

return null;

}

protected boolean isLeaf() {

if (lesser!=null) return false;

if (greater!=null) return false;

return true;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

return "value=" + id +

" color=" + ((color==RED)?"RED":"BLACK") +

" isLeaf=" + isLeaf() +

" parent=" + ((parent != null) ? parent.id : "NULL") +

" lesser=" + ((lesser != null) ? lesser.id : "NULL") +

" greater=" + ((greater != null) ? greater.id : "NULL");

}

}

protected static class RedBlackTreePrinter {

public static > String getString(RedBlackTree tree) {

if (tree.root == null) return "Tree has no nodes.";

return getString((RedBlackNode)tree.root, "", true);

}

public static > String getString(RedBlackNode node) {

if (node == null) return "Sub-tree has no nodes.";

return getString(node, "", true);

}

private static > String getString(RedBlackNode node, String prefix, boolean isTail) {

StringBuilder builder = new StringBuilder();

builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + ((node.color==RED)?"RED":"BLACK") + ") " + node.id + "\n");

List> children = null;

if (node.lesser != null || node.greater != null) {

children = new ArrayList>(2);

if (node.lesser != null) children.add(node.lesser);

if (node.greater != null) children.add(node.greater);

}

if (children != null) {

for (int i = 0; i < children.size() - 1; i++) {

builder.append(getString((RedBlackNode)children.get(i), prefix + (isTail ? " " : "│ "), false));

}

if (children.size() >= 1) {

builder.append(getString((RedBlackNode)children.get(children.size() - 1), prefix + (isTail ? " " : "│ "), true));

}

}

return builder.toString();

}

}

}

线段树,可以统计线段的最小值,最大值,和等

package com.jwetherell.algorithms.data_structures;

import java.security.InvalidParameterException;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.HashSet;

import java.util.Iterator;

import java.util.List;

import java.util.Set;

import java.util.TreeSet;

/**

* Segment tree using objects and pointers. A segment tree is a tree data

* structure for storing intervals, or segments. It allows querying which of the

* stored segments contain a given point. It is, in principle, a static

* structure; that is, its content cannot be modified once the structure is

* built.

*

* http://en.wikipedia.org/wiki/Segment_tree

*

* This class is meant to be somewhat generic, all you'd have to do is extend the

* Data abstract class to store your custom data. I've also included a range minimum,

* range maximum, range sum, and interval stabbing implementations.

*

* @author Justin Wetherell

*/

public abstract class SegmentTree {

protected Segment root = null;

/**

* Stabbing query

*

* @param index to query for.

* @return data at index.

*/

public abstract D query(long index);

/**

* Range query

*

* @param start of range to query for.

* @param end of range to query for.

* @return data for range.

*/

public abstract D query(long start, long end);

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(SegmentTreePrinter.getString(this));

return builder.toString();

}

public abstract static class Data implements Comparable {

protected long start = Long.MIN_VALUE;

protected long end = Long.MAX_VALUE;

/**

* Constructor for data at index.

*

* @param index of data.

*/

public Data(long index) {

this.start = index;

this.end = index;

}

/**

* Constructor for data at range.

*

* @param start of range for data.

* @param end of range for data.

*/

public Data(long start, long end) {

this.start = start;

this.end = end;

}

/**

* Clear the indices.

*/

public void clear() {

start = Long.MIN_VALUE;

end = Long.MAX_VALUE;

}

/**

* Combined this data with data.

*

* @param data to combined with.

* @return Data which represents the combination.

*/

public abstract Data combined(Data data);

/**

* Deep copy of data.

*

* @return deep copy.

*/

public abstract Data copy();

/**

* Query inside this data object.

*

* @param start of range to query for.

* @param end of range to query for.

* @return Data queried for or NULL if it doesn't match the query.

*/

public abstract Data query(long start, long end);

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(start).append("->").append(end);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(Data d) {

if (this.end < d.end) return -1;

if (d.end < this.end) return 1;

return 0;

}

/**

* Data structure representing points in the x,y space and their location

* in the quadrants.

*/

public static final class QuadrantData extends Data {

public long quad1 = 0;

public long quad2 = 0;

public long quad3 = 0;

public long quad4 = 0;

public QuadrantData(long index) {

super(index);

}

public QuadrantData(long start, long end) {

super(start,end);

}

public QuadrantData(long index, long quad1, long quad2, long quad3, long quad4) {

super(index);

this.quad1 = quad1;

this.quad2 = quad2;

this.quad3 = quad3;

this.quad4 = quad4;

}

/**

* {@inheritDoc}

*/

@Override

public void clear() {

super.clear();

quad1 = 0;

quad2 = 0;

quad3 = 0;

quad4 = 0;

}

/**

* {@inheritDoc}

*/

@Override

public Data combined(Data data) {

QuadrantData q = null;

if (data instanceof QuadrantData) {

q = (QuadrantData) data;

this.combined(q);

}

return this;

}

/**

* Combined specific to quadrant data.

*

* @param data to combined.

*/

private void combined(QuadrantData data) {

this.quad1 += data.quad1;

this.quad2 += data.quad2;

this.quad3 += data.quad3;

this.quad4 += data.quad4;

}

/**

* {@inheritDoc}

*/

@Override

public QuadrantData copy() {

QuadrantData copy = new QuadrantData(start,end);

copy.quad1 = this.quad1;

copy.quad2 = this.quad2;

copy.quad3 = this.quad3;

copy.quad4 = this.quad4;

return copy;

}

/**

* {@inheritDoc}

*/

@Override

public Data query(long start, long end) {

return copy();

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append(quad1).append(",");

builder.append(quad2).append(",");

builder.append(quad3).append(",");

builder.append(quad4);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof QuadrantData)) return false;

QuadrantData data = (QuadrantData) obj;

if (this.start==data.start && this.end==data.end &&

this.quad1==data.quad1 && this.quad2==data.quad2 && this.quad3==data.quad3 && this.quad4==data.quad4)

{

return true;

}

return false;

}

}

/**

* Data structure representing maximum in the range.

*/

public static final class RangeMaximumData extends Data {

public N maximum = null;

public RangeMaximumData(long index) {

super(index);

}

public RangeMaximumData(long start, long end) {

super(start,end);

}

public RangeMaximumData(long index, N number) {

super(index);

this.maximum = number;

}

public RangeMaximumData(long start, long end, N number) {

super(start,end);

this.maximum = number;

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public Data combined(Data data) {

RangeMaximumData q = null;

if (data instanceof RangeMaximumData) {

q = (RangeMaximumData) data;

this.combined(q);

}

return this;

}

/**

* Combined for range maximum specific data.

*

* @param data resulted from the combination.

*/

private void combined(RangeMaximumData data) {

if (this.maximum==null && data.maximum==null) return;

else if (this.maximum!=null && data.maximum==null) return;

else if (this.maximum==null && data.maximum!=null) this.maximum = data.maximum;

else if (data.maximum.doubleValue() > this.maximum.doubleValue()) {

this.maximum = data.maximum;

}

}

/**

* {@inheritDoc}

*/

@Override

public Data copy() {

return new RangeMaximumData(start,end,maximum);

}

/**

* {@inheritDoc}

*/

@Override

public Data query(long start, long end) {

return copy();

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("maximum=").append(maximum);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof RangeMaximumData)) return false;

@SuppressWarnings("unchecked")

RangeMaximumData data = (RangeMaximumData) obj;

if (this.start==data.start && this.end==data.end && this.maximum.equals(data.maximum)) return true;

return false;

}

}

/**

* Data structure representing minimum in the range.

*/

public static final class RangeMinimumData extends Data {

public N minimum = null;

public RangeMinimumData(long index) {

super(index);

}

public RangeMinimumData(long start, long end) {

super(start,end);

}

public RangeMinimumData(long index, N number) {

super(index);

this.minimum = number;

}

public RangeMinimumData(long start, long end, N number) {

super(start,end);

this.minimum = number;

}

/**

* {@inheritDoc}

*/

@Override

public void clear() {

super.clear();

minimum = null;

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public Data combined(Data data) {

RangeMinimumData q = null;

if (data instanceof RangeMinimumData) {

q = (RangeMinimumData) data;

this.combined(q);

}

return this;

}

/**

* Combined specific to range minimum specific data.

*

* @param data resulted from combination.

*/

private void combined(RangeMinimumData data) {

if (this.minimum==null && data.minimum==null) return;

else if (this.minimum!=null && data.minimum==null) return;

else if (this.minimum==null && data.minimum!=null) this.minimum = data.minimum;

else if (data.minimum.doubleValue() < this.minimum.doubleValue()) {

this.minimum = data.minimum;

}

}

/**

* {@inheritDoc}

*/

@Override

public Data copy() {

return new RangeMinimumData(start,end,minimum);

}

/**

* {@inheritDoc}

*/

@Override

public Data query(long start, long end) {

return copy();

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("minimum=").append(minimum);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof RangeMinimumData)) return false;

@SuppressWarnings("unchecked")

RangeMinimumData data = (RangeMinimumData) obj;

if (this.start==data.start && this.end==data.end && this.minimum.equals(data.minimum)) return true;

return false;

}

}

/**

* Data structure representing sum of the range.

*/

public static final class RangeSumData extends Data {

public N sum = null;

public RangeSumData(long index) {

super(index);

}

public RangeSumData(long start, long end) {

super(start,end);

}

public RangeSumData(long index, N number) {

super(index);

this.sum = number;

}

public RangeSumData(long start, long end, N number) {

super(start,end);

this.sum = number;

}

/**

* {@inheritDoc}

*/

@Override

public void clear() {

super.clear();

sum = null;

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public Data combined(Data data) {

RangeSumData q = null;

if (data instanceof RangeSumData) {

q = (RangeSumData) data;

this.combined(q);

}

return this;

}

/**

* Combined specific to range sum specific data.

*

* @param data resulted from combination.

*/

@SuppressWarnings("unchecked")

private void combined(RangeSumData data) {

if (this.sum==null && data.sum==null) return;

else if (this.sum!=null && data.sum==null) return;

else if (this.sum==null && data.sum!=null) this.sum = data.sum;

else {

Double d1 = this.sum.doubleValue();

Double d2 = data.sum.doubleValue();

Double r = d1+d2;

this.sum = (N)r;

}

}

/**

* {@inheritDoc}

*/

@Override

public Data copy() {

return new RangeSumData(start,end,sum);

}

/**

* {@inheritDoc}

*/

@Override

public Data query(long start, long end) {

return copy();

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("sum=").append(sum);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof RangeSumData)) return false;

@SuppressWarnings("unchecked")

RangeSumData data = (RangeSumData) obj;

if (this.start==data.start && this.end==data.end && this.sum.equals(data.sum)) return true;

return false;

}

}

/**

* Data structure representing an interval.

*/

public static final class IntervalData extends Data {

private Set set = new TreeSet(); //Sorted

/**

* Interval data using O as it's unique identifier

* @param object Object which defines the interval data

*/

public IntervalData(long index, O object) {

super(index);

this.set.add(object);

}

/**

* Interval data using O as it's unique identifier

* @param object Object which defines the interval data

*/

public IntervalData(long start, long end, O object) {

super(start,end);

this.set.add(object);

}

/**

* Interval data list which should all be unique

* @param list of interval data objects

*/

public IntervalData(long start, long end, Set set) {

super(start,end);

this.set = set;

//Make sure they are unique

Iterator iter = set.iterator();

while (iter.hasNext()) {

O obj1 = iter.next();

O obj2 = null;

if (iter.hasNext()) obj2 = iter.next();

if (obj1.equals(obj2)) throw new InvalidParameterException("Each interval data in the list must be unique.");

}

}

/**

* {@inheritDoc}

*/

@Override

public void clear() {

super.clear();

this.set.clear();

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public Data combined(Data data) {

IntervalData q = null;

if (data instanceof IntervalData) {

q = (IntervalData) data;

this.combined(q);

}

return this;

}

/**

* Combined for interval specific data.

*

* @param data resulted from combination.

*/

private void combined(IntervalData data) {

if (data.start

if (data.end>this.end) this.end = data.end;

this.set.addAll(data.set);

}

/**

* {@inheritDoc}

*/

@Override

public Data copy() {

Set listCopy = new TreeSet();

listCopy.addAll(set);

return new IntervalData(start,end,listCopy);

}

/**

* {@inheritDoc}

*/

@Override

public Data query(long start, long end) {

if (endthis.end) {

//Ignore

} else {

return copy();

}

return null;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("set=").append(set);

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (!(obj instanceof IntervalData)) return false;

@SuppressWarnings("unchecked")

IntervalData data = (IntervalData) obj;

if (this.start==data.start && this.end==data.end) {

if (this.set.size()!=data.set.size()) return false;

for (O o : set) {

if (!data.set.contains(o)) return false;

}

return true;

}

return false;

}

}

}

/**

* Data structure representing a segment.

*/

protected abstract static class Segment implements Comparable> {

protected Segment[] segments = null;

protected int length = 0;

protected int half = 0;

protected long start = 0;

protected long end = 0;

protected D data = null;

protected int minLength = 0;

public Segment(int minLength) {

this.minLength = minLength;

}

/**

* Query for data in range.

*

* @param start of the range to query for.

* @param end of range to query for.

* @return Data in the range.

*/

public abstract D query(long start, long end);

protected boolean hasChildren() {

return (segments!=null);

}

protected Segment getLeftChild() {

return segments[0];

}

protected Segment getRightChild() {

return segments[1];

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(start).append("->");

builder.append(end).append(" ");

builder.append("Length=").append(length).append(" ");

builder.append("Data={").append(data).append("}");

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(Segment p) {

if (this.end < p.end) return -1;

if (p.end < this.end) return 1;

return 0;

}

}

protected static class SegmentTreePrinter {

public static String getString(SegmentTree tree) {

if (tree.root == null) return "Tree has no nodes.";

return getString(tree.root, "", true);

}

private static String getString(Segment segment, String prefix, boolean isTail) {

StringBuilder builder = new StringBuilder();

builder.append( prefix + (isTail ? "└── " : "├── ") + segment.toString() + "\n" );

List> children = new ArrayList>();

if (segment.segments!=null) {

for (Segment c : segment.segments) children.add(c);

}

if (children != null) {

for (int i = 0; i < children.size() - 1; i++) {

builder.append(getString(children.get(i), prefix + (isTail ? " " : "│ "), false));

}

if (children.size() > 1) {

builder.append(getString(children.get(children.size() - 1), prefix + (isTail ? " " : "│ "), true));

}

}

return builder.toString();

}

}

/**

* Flat segment tree is a variant of segment tree that is designed to store a collection of non-overlapping

* segments. This structure is efficient when you need to store values associated with 1 dimensional segments

* that never overlap with each other. The end points of stored segments are inclusive, that is, when a

* segment spans from 2 to 6, an arbitrary point x within that segment can take a value of 2 <= x <= 6.

*/

public static final class FlatSegmentTree extends SegmentTree {

public FlatSegmentTree(List data) {

this(data,1);

}

@SuppressWarnings("unchecked")

public FlatSegmentTree(List data, int minLength) {

if (data.size()<=0)

throw new InvalidParameterException("Segments list is empty.");

Collections.sort(data); //Make sure they are sorted

//Make sure they don't overlap

if (data.size()>=2) {

for (int i=0; i

Data s1 = data.get(i);

Data s2 = data.get(i+1);

if (s1.end>s2.start)

throw new InvalidParameterException("Segments are overlapping.");

}

}

//Check for gaps

List> segments = new ArrayList>();

for (int i=0; i

if (i

Data d1 = data.get(i);

NonOverlappingSegment s1 = new NonOverlappingSegment(minLength,d1.start,d1.end,(D)d1);

segments.add(s1);

Data d2 = data.get(i+1);

if (d2.start-d1.end>1) {

Data d3 = d1.copy();

d3.clear();

d3.start = d1.end+1;

d3.end = d2.start-1;

NonOverlappingSegment s3 = new NonOverlappingSegment(minLength,d3.start,d3.end,(D)d3);

segments.add(s3);

}

} else {

Data d1 = data.get(i);

NonOverlappingSegment s1 = new NonOverlappingSegment(minLength,d1.start,d1.end,(D)d1);

segments.add(s1);

}

}

long start = segments.get(0).start;

long end = segments.get(segments.size()-1).end;

int length = (int)(end-start)+1;

root = NonOverlappingSegment.createFromList(minLength,segments,start,length);

}

/**

* {@inheritDoc}

*/

@Override

public D query(long index) {

return this.query(index, index);

}

/**

* {@inheritDoc}

*/

@Override

public D query(long start, long end) {

if (root==null) return null;

if (start

if (end>root.end) end = root.end;

return (D)root.query(start, end);

}

/**

* Data structure representing a non-overlapping segment.

*/

protected static final class NonOverlappingSegment extends Segment {

private Set> set = new TreeSet>();

public NonOverlappingSegment(int minLength) {

super(minLength);

}

public NonOverlappingSegment(int minLength, D data) {

this(minLength,data.start,data.end,data);

}

@SuppressWarnings("unchecked")

public NonOverlappingSegment(int minLength,long start, long end, D data) {

super(minLength);

this.start = start;

this.end = end;

this.length = ((int)(end-start))+1;

if (data==null) return;

this.data = ((D)data.copy());

}

@SuppressWarnings("unchecked")

protected static Segment createFromList(int minLength, List> segments, long start, int length) {

NonOverlappingSegment segment = new NonOverlappingSegment(minLength);

segment.start = start;

segment.end = start+(length-1);

segment.length = length;

for (Segment s : segments) {

if (segment.data==null) segment.data = ((D)s.data.copy());

else segment.data.combined(s.data); //Update our data to reflect all children's data

}

//If segment is greater or equal to two, split data into children

if (segment.length >= 2 && segment.length>=minLength) {

segment.half = segment.length / 2;

List> s1 = new ArrayList>();

List> s2 = new ArrayList>();

for (int i = 0; i < segments.size(); i++) {

NonOverlappingSegment s = segments.get(i);

long middle = segment.start+segment.half;

if (s.end

s1.add(s);

} else if (s.start>=middle) {

s2.add(s);

} else {

//Need to split across middle

NonOverlappingSegment ss1 = new NonOverlappingSegment(minLength,s.start,middle-1,s.data);

s1.add(ss1);

NonOverlappingSegment ss2 = new NonOverlappingSegment(minLength,middle,s.end,s.data);

s2.add(ss2);

}

}

Segment sub1 = createFromList(minLength,s1,segment.start,segment.half);

Segment sub2 = createFromList(minLength,s2,segment.start+segment.half,segment.length-segment.half);

segment.segments = new Segment[] { sub1, sub2 };

} else if (segment.length<=minLength) {

for (Segment s : segments) {

segment.set.add(s);

}

}

return segment;

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public D query(long start, long end) {

if (start == this.start && end == this.end) {

if (this.data==null) return null;

D dataToReturn = ((D)this.data.query(start,end));

return dataToReturn;

} else if (!this.hasChildren()) {

if (endthis.end) {

//Ignore

} else {

D dataToReturn = null;

if (this.set.size()==0) return dataToReturn;

for (Segment s : this.set) {

if (s.start >= start && s.end <= end) {

if (dataToReturn==null) dataToReturn = (D)s.data.query(start,end);

else dataToReturn.combined(s.data);

} else if (s.start <= start && s.end >= end) {

if (dataToReturn==null) dataToReturn = (D)s.data.query(start,end);

else dataToReturn.combined(s.data);

}

}

return dataToReturn;

}

} else if (this.hasChildren()) {

if (start <= this.getLeftChild().end && end > this.getLeftChild().end) {

Data q1 = this.getLeftChild().query(start, getLeftChild().end);

Data q2 = this.getRightChild().query(getRightChild().start, end);

if (q1==null && q2==null) return null;

if (q1!=null && q2==null) return (D)q1;

if (q1==null && q2!=null) return (D)q2;

return ((D)q1.combined(q2));

} else if (start <= this.getLeftChild().end && end <= this.getLeftChild().end) {

return this.getLeftChild().query(start, end);

}

return this.getRightChild().query(start, end);

}

return null;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("Set=").append(set);

return builder.toString();

}

}

}

/**

* Segment tree is a balanced-binary-tree based data structure efficient for detecting all intervals (or segments)

* that contain a given point. The segments may overlap with each other. The end points of stored segments are

* inclusive, that is, when an interval spans from 2 to 6, an arbitrary point x within that interval can take a

* value of 2 <= x <=6.

*/

public static final class DynamicSegmentTree extends SegmentTree {

public DynamicSegmentTree(List data) {

this(data,1);

}

@SuppressWarnings("unchecked")

public DynamicSegmentTree(List data, int minLength) {

if (data.size()<=0) return;

//Check for gaps

List> segments = new ArrayList>();

for (int i=0; i

if (i

Data d1 = data.get(i);

OverlappingSegment s1 = new OverlappingSegment(minLength,d1.start,d1.end,(D)d1);

segments.add(s1);

Data d2 = data.get(i+1);

if (d2.start-d1.end>1) {

Data d3 = d1.copy();

d3.clear();

d3.start = d1.end+1;

d3.end = d2.start-1;

OverlappingSegment s3 = new OverlappingSegment(minLength,d3.start,d3.end,(D)d3);

segments.add(s3);

}

} else {

Data d1 = data.get(i);

OverlappingSegment s1 = new OverlappingSegment(minLength,d1.start,d1.end,(D)d1);

segments.add(s1);

}

}

//First start first

Collections.sort(segments,

new Comparator>(){

@Override

public int compare(OverlappingSegment arg0, OverlappingSegment arg1) {

if (arg0.start

if (arg1.start

return 0;

}

}

);

OverlappingSegment startNode = segments.get(0);

long start = startNode.start-1;

OverlappingSegment s1 = new OverlappingSegment(minLength,start,startNode.start,null);

segments.add(0,s1);

//Last end last

Collections.sort(segments,

new Comparator>(){

@Override

public int compare(OverlappingSegment arg0, OverlappingSegment arg1) {

if (arg0.end

if (arg1.end

return 0;

}

}

);

OverlappingSegment endNode = segments.get(segments.size()-1);

long end = endNode.end+1;

OverlappingSegment s2 = new OverlappingSegment(minLength,endNode.end,end,null);

segments.add(s2);

int length = (int)(end-start)+1;

root = OverlappingSegment.createFromList(minLength,segments,start,length);

}

/**

* {@inheritDoc}

*/

@Override

public D query(long index) {

return this.query(index, index);

}

/**

* {@inheritDoc}

*/

@Override

public D query(long start, long end) {

if (root==null) return null;

if (start

if (end>root.end) end = root.end;

D result = root.query(start, end);

return result;

}

/**

* Data structure representing a possibly overlapping segment.

*/

protected static final class OverlappingSegment extends Segment {

//Separate range set for fast range queries

protected Set> range = new HashSet>();

public OverlappingSegment(int minLength) {

super(minLength);

}

@SuppressWarnings("unchecked")

public OverlappingSegment(int minLength, long start, long end, D data) {

super(minLength);

this.start = start;

this.end = end;

this.length = ((int)(end-start))+1;

if (data==null) return;

this.data = ((D)data.copy());

}

@SuppressWarnings("unchecked")

protected static Segment createFromList(int minLength, List> segments, long start, int length) {

OverlappingSegment segment = new OverlappingSegment(minLength);

segment.start = start;

segment.end = start+(length-1);

segment.length = length;

for (Segment s : segments) {

if (s.data==null) continue;

if (s.endsegment.end) {

//Ignore

} else {

segment.range.add(s);

}

if (s.start==segment.start && s.end==segment.end) {

if (segment.data==null) segment.data = ((D)s.data.copy());

else segment.data.combined(s.data); //Update our data to reflect all children's data

} else if (!segment.hasChildren() && s.start>=segment.start && s.end<=segment.end) {

if (segment.data==null) segment.data = ((D)s.data.copy());

else segment.data.combined(s.data); //Update our data to reflect all children's data

}

}

//If segment is greater or equal to two, split data into children

if (segment.length >= 2 && segment.length>=minLength) {

segment.half = segment.length / 2;

List> s1 = new ArrayList>();

List> s2 = new ArrayList>();

for (int i = 0; i < segments.size(); i++) {

OverlappingSegment s = segments.get(i);

long middle = segment.start+segment.half;

if (s.end

s1.add(s);

} else if (s.start>=middle) {

s2.add(s);

} else {

//Need to split across middle

OverlappingSegment ss1 = new OverlappingSegment(minLength,s.start,middle-1,s.data);

s1.add(ss1);

OverlappingSegment ss2 = new OverlappingSegment(minLength,middle,s.end,s.data);

s2.add(ss2);

}

}

Segment sub1 = createFromList(minLength,s1,segment.start,segment.half);

Segment sub2 = createFromList(minLength,s2,segment.start+segment.half,segment.length-segment.half);

segment.segments = new Segment[] { sub1, sub2 };

}

return segment;

}

/**

* {@inheritDoc}

*/

@Override

@SuppressWarnings("unchecked")

public D query(long start, long end) {

D result = null;

//Use the range data to make range queries faster

if (start==this.start && end==this.end) {

for (Segment s : this.range) {

D temp = (D)s.data.query(start, end);

if (temp!=null) {

if (result==null) result = (D)temp.copy();

else result.combined(temp);

}

}

} else if (!this.hasChildren()) {

if (endthis.end) {

//Ignore

} else {

for (Segment s : this.range) {

if (ends.end) {

//Ignore

} else {

D temp = (D)s.data.query(start, end);

if (temp!=null) {

if (result==null) result = (D)temp.copy();

else result.combined(temp);

}

}

}

}

} else {

long middle = this.start+this.half;

D temp = null;

if (start=middle) {

temp = this.getLeftChild().query(start, middle-1);

D temp2 = this.getRightChild().query(middle, end);

if (temp2!=null) {

if (temp==null) temp = (D)temp2.copy();

else temp.combined(temp2);

}

} else if (end

temp = this.getLeftChild().query(start, end);

} else if (start>=middle) {

temp = this.getRightChild().query(start, end);

}

if (temp!=null) result = (D)temp.copy();

}

return result;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append(super.toString()).append(" ");

builder.append("Range=").append(range);

return builder.toString();

}

}

}

}

伸展树 把最近访问的结点统计旋转变为根结点

package com.jwetherell.algorithms.data_structures;

/**

* A splay tree is a self-adjusting binary search tree (BST) with the additional

* property that recently accessed elements are quick to access again.

*

* http://en.wikipedia.org/wiki/Splay_tree

*

* @author Justin Wetherell

*/

public class SplayTree> extends BinarySearchTree {

/**

* {@inheritDoc}

*/

@Override

protected Node addValue(T id) {

Node nodeToReturn = super.addValue(id);

Node nodeAdded = nodeToReturn;

if (nodeAdded!=null) {

//Splay the new node to the root position

while (nodeAdded.parent!=null) {

this.splay(nodeAdded);

}

}

return nodeToReturn;

}

/**

* {@inheritDoc}

*/

@Override

protected Node removeValue(T value) {

Node nodeToRemove = super.removeValue(value);

if (nodeToRemove!=null) {

if (nodeToRemove.parent!=null) {

Node nodeParent = nodeToRemove.parent;

//Splay the parent node to the root position

while (nodeParent.parent!=null) {

this.splay(nodeParent);

}

}

}

return nodeToRemove;

}

/**

* {@inheritDoc}

*/

@Override

public boolean contains(T value) {

Node node = getNode(value);

if (node!=null) {

//Splay the new node to the root position

while (node.parent!=null) {

this.splay(node);

}

return true;

}

return false;

}

/**

* Splay the tree at the node.

* @param node to splay at.

*/

private void splay(Node node) {

Node parent = node.parent;

Node grandParent = (parent != null) ? parent.parent : null;

if (parent == root) {

// Zig step

root = node;

node.parent = null;

if (node == parent.lesser) {

parent.lesser = node.greater;

if (node.greater != null) node.greater.parent = parent;

node.greater = parent;

parent.parent = node;

} else {

parent.greater = node.lesser;

if (node.lesser != null) node.lesser.parent = parent;

node.lesser = parent;

parent.parent = node;

}

} else if (parent != null && grandParent != null) {

Node greatGrandParent = grandParent.parent;

if (greatGrandParent != null && greatGrandParent.lesser == grandParent) {

greatGrandParent.lesser = node;

node.parent = greatGrandParent;

} else if (greatGrandParent != null && greatGrandParent.greater == grandParent) {

greatGrandParent.greater = node;

node.parent = greatGrandParent;

} else {

// I am now root!

root = node;

node.parent = null;

}

if ((node == parent.lesser && parent == grandParent.lesser) || (node == parent.greater && parent == grandParent.greater)) {

// Zig-zig step

if (node == parent.lesser) {

Node nodeGreater = node.greater;

node.greater = parent;

parent.parent = node;

parent.lesser = nodeGreater;

if (nodeGreater != null) nodeGreater.parent = parent;

Node parentGreater = parent.greater;

parent.greater = grandParent;

grandParent.parent = parent;

grandParent.lesser = parentGreater;

if (parentGreater != null) parentGreater.parent = grandParent;

} else {

Node nodeLesser = node.lesser;

node.lesser = parent;

parent.parent = node;

parent.greater = nodeLesser;

if (nodeLesser != null) nodeLesser.parent = parent;

Node parentLesser = parent.lesser;

parent.lesser = grandParent;

grandParent.parent = parent;

grandParent.greater = parentLesser;

if (parentLesser != null) parentLesser.parent = grandParent;

}

} else {

// Zig-zag step

if (node == parent.lesser) {

Node nodeLesser = node.greater;

Node nodeGreater = node.lesser;

node.greater = parent;

parent.parent = node;

node.lesser = grandParent;

grandParent.parent = node;

parent.lesser = nodeLesser;

if (nodeLesser != null) nodeLesser.parent = parent;

grandParent.greater = nodeGreater;

if (nodeGreater != null) nodeGreater.parent = grandParent;

} else {

Node nodeLesser = node.lesser;

Node nodeGreater = node.greater;

node.lesser = parent;

parent.parent = node;

node.greater = grandParent;

grandParent.parent = node;

parent.greater = nodeLesser;

if (nodeLesser != null) nodeLesser.parent = parent;

grandParent.lesser = nodeGreater;

if (nodeGreater != null) nodeGreater.parent = grandParent;

}

}

}

}

}

后缀树

package com.jwetherell.algorithms.data_structures;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.List;

import java.util.Map;

import java.util.Set;

import java.util.TreeMap;

import java.util.TreeSet;

/**

* A suffix tree is a data structure that presents the suffixes of a given

* string in a way that allows for a particularly fast implementation of many

* important string operations. This implementation is based on the Ukkonen's

* algorithm.

*

* http://en.wikipedia.org/wiki/Suffix_tree

*

* @author Justin Wetherell

*/

public class SuffixTree {

private static final char DEFAULT_END_SEQ_CHAR = '$';

private String string = null;

private char[] characters = null;

private Map linksMap = new HashMap();

private Map> edgeMap = new TreeMap>();

private int currentNode = 0;

private int firstCharIndex = 0;

private int lastCharIndex = -1;

private char END_SEQ_CHAR = DEFAULT_END_SEQ_CHAR;

/**

* Create suffix tree with sequence and default end sequence.

*

* @param seq to create a suffix tree with.

*/

public SuffixTree(C seq) {

this(seq, DEFAULT_END_SEQ_CHAR);

}

/**

* Create suffix tree with sequence and end sequence parameter.

*

* @param seq to create a suffix tree with.

* @param endSeq which defines the end of a sequence.

*/

public SuffixTree(C seq, char endSeq) {

END_SEQ_CHAR = endSeq;

StringBuilder builder = new StringBuilder(seq);

if (builder.indexOf(String.valueOf(seq))>=0) builder.append(END_SEQ_CHAR);

string = builder.toString();

int length = string.length();

characters = new char[length];

for (int i = 0; i < length; i++) {

characters[i] = string.charAt(i);

}

for (int i = 0; i < length; i++) {

addPrefix(i);

}

}

/**

* Does the sub-sequence exist in the suffix tree.

*

* @param sub sub-sequence to locate in the tree.

* @return True if the sub-sequence exist in the tree.

*/

public boolean doesSubStringExist(C sub) {

char[] chars = new char[sub.length()];

for (int i = 0; i < sub.length(); i++) {

chars[i] = sub.charAt(i);

}

int[] indices = searchEdges(chars);

int start = indices[0];

int end = indices[1];

int length = end - start;

if (length == (chars.length - 1)) return true;

return false;

}

/**

* Get all the suffixes in the tree.

*

* @return set of suffixes in the tree.

*/

public Set getSuffixes() {

Set set = getSuffixes(0);

return set;

}

/**

* Get all suffixes at starting node.

*

* @param start node.

* @return set of suffixes in the tree at start node.

*/

private Set getSuffixes(int start) {

Set set = new TreeSet();

for (int key : edgeMap.keySet()) {

Edge e = edgeMap.get(key);

if (e == null) continue;

if (e.startNode != start) continue;

String s = (string.substring(e.firstCharIndex, e.lastCharIndex + 1));

Link n = linksMap.get(e.endNode);

if (n == null) {

int index = s.indexOf(END_SEQ_CHAR);

if (index>=0) s = s.substring(0, index);

set.add(s);

} else {

Set set2 = getSuffixes(e.endNode);

for (String s2 : set2) {

int index = s2.indexOf(END_SEQ_CHAR);

if (index>=0) s2 = s2.substring(0, index);

set.add(s + s2);

}

}

}

return set;

}

/**

* Get all edges in the table

*

* @return debug string.

*/

public String getEdgesTable() {

StringBuilder builder = new StringBuilder();

if (edgeMap.size() > 0) {

int lastCharIndex = characters.length;

builder.append("Edge\tStart\tEnd\tSuf\tfirst\tlast\tString\n");

for (int key : edgeMap.keySet()) {

Edge e = edgeMap.get(key);

Link link = linksMap.get(e.endNode);

int suffix = (link != null) ? link.suffixNode : -1;

builder.append("\t" + e.startNode + "\t" + e.endNode + "\t" + suffix + "\t" + e.firstCharIndex + "\t" + e.lastCharIndex + "\t");

int begin = e.firstCharIndex;

int end = (lastCharIndex < e.lastCharIndex) ? lastCharIndex : e.lastCharIndex;

builder.append(string.substring(begin, end + 1));

builder.append("\n");

}

builder.append("Link\tStart\tEnd\n");

for (int key : linksMap.keySet()) {

Link link = linksMap.get(key);

builder.append("\t" + link.node + "\t" + link.suffixNode + "\n");

}

}

return builder.toString();

}

/**

* Add prefix at index.

*

* @param index to add prefix at.

*/

private void addPrefix(int index) {

int parentNodeIndex = 0;

int lastParentIndex = -1;

while (true) {

Edge edge = null;

parentNodeIndex = currentNode;

if (isExplicit()) {

edge = Edge.find(this, currentNode, characters[index]);

if (edge != null) {

// Edge already exists

break;

}

} else {

// Implicit node, a little more complicated

edge = Edge.find(this, currentNode, characters[firstCharIndex]);

int span = lastCharIndex - firstCharIndex;

if (characters[edge.firstCharIndex + span + 1] == characters[index]) {

// If the edge is the last char, don't split

break;

}

parentNodeIndex = edge.split(currentNode, firstCharIndex, lastCharIndex);

}

edge = new Edge(this, index, characters.length - 1, parentNodeIndex);

if (lastParentIndex > 0) {

// Last parent is not root, create a link.

linksMap.get(lastParentIndex).suffixNode = parentNodeIndex;

}

lastParentIndex = parentNodeIndex;

if (currentNode == 0) {

firstCharIndex++;

} else {

// Current node is not root, follow link

currentNode = linksMap.get(currentNode).suffixNode;

}

if (!isExplicit()) canonize();

}

if (lastParentIndex > 0) {

// Last parent is not root, create a link.

linksMap.get(lastParentIndex).suffixNode = parentNodeIndex;

}

lastParentIndex = parentNodeIndex;

lastCharIndex++; // Now the endpoint is the next active point

if (!isExplicit()) canonize();

};

/**

* Is the tree explicit

*

* @return True if explicit.

*/

private boolean isExplicit() {

return firstCharIndex > lastCharIndex;

}

/**

* Canonize the tree.

*/

private void canonize() {

Edge edge = Edge.find(this, currentNode, characters[firstCharIndex]);

int edgeSpan = edge.lastCharIndex - edge.firstCharIndex;

while (edgeSpan <= (lastCharIndex - firstCharIndex)) {

firstCharIndex = firstCharIndex + edgeSpan + 1;

currentNode = edge.endNode;

if (firstCharIndex <= lastCharIndex) {

edge = Edge.find(this, edge.endNode, characters[firstCharIndex]);

edgeSpan = edge.lastCharIndex - edge.firstCharIndex;

}

}

}

/**

* Returns a two element int array who's 0th index is the start index and

* 1th is the end index.

*/

private int[] searchEdges(char[] query) {

int startNode = 0;

int queryPosition = 0;

int startIndex = -1;

int endIndex = -1;

boolean stop = false;

while (!stop && queryPosition < query.length) {

Edge edge = Edge.find(this, startNode, query[queryPosition]);

if (edge == null) {

stop = true;

break;

}

if (startNode == 0) startIndex = edge.firstCharIndex;

for (int i = edge.firstCharIndex; i <= edge.lastCharIndex; i++) {

if (queryPosition >= query.length) {

stop = true;

break;

} else if (query[queryPosition] == characters[i]) {

queryPosition++;

endIndex = i;

} else {

stop = true;

break;

}

}

if (!stop) { // proceed with next node

startNode = edge.endNode;

if (startNode == -1) stop = true;

}

}

return (new int[] { startIndex, endIndex });

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("String = ").append(this.string).append("\n");

builder.append("End of word character = ").append(END_SEQ_CHAR).append("\n");

builder.append(TreePrinter.getString(this));

return builder.toString();

}

private static class Link implements Comparable {

private int node = 0;

private int suffixNode = -1;

public Link(int node) {

this.node = node;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("node=").append(node).append("\n");

builder.append("suffixNode=").append(suffixNode).append("\n");

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(Link link) {

if (link == null) return -1;

if (node < link.node) return -1;

if (node > link.node) return 1;

if (suffixNode < link.suffixNode) return -1;

if (suffixNode > link.suffixNode) return 1;

return 0;

}

};

private static class Edge implements Comparable> {

private static final int KEY_MOD = 2179; // Should be a prime that is

// roughly 10% larger than the

// String

private static int count = 1;

private SuffixTree tree = null;

private int startNode = -1;

private int endNode = 0;

private int firstCharIndex = 0;

private int lastCharIndex = 0;

private Edge(SuffixTree tree, int first, int last, int parent) {

this.tree = tree;

firstCharIndex = first;

lastCharIndex = last;

startNode = parent;

endNode = count++;

insert(this);

}

private int getKey() {

return key(startNode, tree.characters[firstCharIndex]);

}

private static int key(int node, char c) {

return ((node << 8) + c) % KEY_MOD;

}

private void insert(Edge edge) {

tree.edgeMap.put(edge.getKey(), edge);

}

private void remove(Edge edge) {

int i = edge.getKey();

Edge e = tree.edgeMap.remove(i);

while (true) {

e.startNode = -1;

int j = i;

while (true) {

i = ++i % KEY_MOD;

e = tree.edgeMap.get(i);

if (e == null) return;

int r = key(e.startNode, tree.characters[e.firstCharIndex]);

if (i >= r && r > j) continue;

if (r > j && j > i) continue;

if (j > i && i >= r) continue;

break;

}

tree.edgeMap.put(j, e);

}

}

private static Edge find(SuffixTree tree, int node, char c) {

int key = key(node, c);

return tree.edgeMap.get(key);

}

private int split(int originNode, int firstCharIndex, int lastCharIndex) {

remove(this);

Edge newEdge = new Edge(tree, this.firstCharIndex, this.firstCharIndex + lastCharIndex - firstCharIndex, originNode);

Link link = tree.linksMap.get(newEdge.endNode);

if (link == null) {

link = new Link(newEdge.endNode);

tree.linksMap.put(newEdge.endNode, link);

}

tree.linksMap.get(newEdge.endNode).suffixNode = originNode;

this.firstCharIndex += lastCharIndex - firstCharIndex + 1;

this.startNode = newEdge.endNode;

insert(this);

return newEdge.endNode;

}

/**

* {@inheritDoc}

*/

@Override

public int hashCode() {

return getKey();

}

/**

* {@inheritDoc}

*/

@Override

public boolean equals(Object obj) {

if (obj == null) return false;

if (obj instanceof Edge) return false;

@SuppressWarnings("unchecked")

Edge e = (Edge) obj;

if (startNode == e.startNode && tree.characters[firstCharIndex] == tree.characters[e.firstCharIndex]) {

return true;

}

return false;

}

/**

* {@inheritDoc}

*/

@Override

public String toString() {

StringBuilder builder = new StringBuilder();

builder.append("startNode=").append(startNode).append("\n");

builder.append("endNode=").append(endNode).append("\n");

builder.append("firstCharIndex=").append(firstCharIndex).append("\n");

builder.append("lastCharIndex=").append(lastCharIndex).append("\n");

String s = tree.string.substring(firstCharIndex, lastCharIndex + 1);

builder.append("string=").append(s).append("\n");

return builder.toString();

}

/**

* {@inheritDoc}

*/

@Override

public int compareTo(Edge edge) {

if (edge == null) return -1;

if (startNode < edge.startNode) return -1;

if (startNode > edge.startNode) return 1;

if (endNode < edge.endNode) return -1;

if (endNode > edge.endNode) return 1;

if (firstCharIndex < edge.firstCharIndex) return -1;

if (firstCharIndex > edge.firstCharIndex) return 1;

if (lastCharIndex < edge.lastCharIndex) return -1;

if (lastCharIndex > edge.lastCharIndex) return 1;

return 0;

}

}

protected static class TreePrinter {

public static void printNode(SuffixTree tree) {

System.out.println(getString(tree, null, "", true));

}

public static String getString(SuffixTree tree) {

return getString(tree, null, "", true);

}

private static String getString(SuffixTree tree, Edge e, String prefix, boolean isTail) {

StringBuilder builder = new StringBuilder();

int value = 0;

if (e != null) {

value = e.endNode;

String string = tree.string.substring(e.firstCharIndex, e.lastCharIndex + 1);

int index = string.indexOf(tree.END_SEQ_CHAR);

if (index>=0) string = string.substring(0, index+1);

builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + value + ") " + string + "\n");

} else {

builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + 0 + ")" + "\n");

}

if (tree.edgeMap.size() > 0) {

List> children = new LinkedList>();

for (Edge edge : tree.edgeMap.values()) {

if (edge != null && (edge.startNode == value)) {

children.add(edge);

}

}

if (children.size()>0) {

for (int i = 0; i < children.size() - 1; i++) {

Edge edge = children.get(i);

builder.append(getString(tree, edge, prefix + (isTail ? " " : "│ "), false));

}

if (children.size() >= 1) {

Edge edge = children.get(children.size() - 1);

builder.append(getString(tree, edge, prefix + (isTail ? " " : "│ "), true));

}

}

}

return builder.toString();

}

}

}

测试代码

private static boolean testIntervalTree() {

{

//Interval tree

if (debug>1) System.out.println("Interval Tree.");

java.util.List> intervals = new ArrayList>();

intervals.add((new IntervalTree.IntervalData(2, 6, "RED")));

intervals.add((new IntervalTree.IntervalData(3, 5, "ORANGE")));

intervals.add((new IntervalTree.IntervalData(4, 11, "GREEN")));

intervals.add((new IntervalTree.IntervalData(5, 10, "DARK_GREEN")));

intervals.add((new IntervalTree.IntervalData(8, 12, "BLUE")));

intervals.add((new IntervalTree.IntervalData(9, 14, "PURPLE")));

intervals.add((new IntervalTree.IntervalData(13, 15, "BLACK")));

IntervalTree tree = new IntervalTree(intervals);

if (debug>1) System.out.println(tree);

IntervalTree.IntervalData query = tree.query(2);

if (debug>1) System.out.println("2: "+query);

query = tree.query(4); //Stabbing query

if (debug>1) System.out.println("4: "+query);

query = tree.query(9); //Stabbing query

if (debug>1) System.out.println("9: "+query);

query = tree.query(1, 16); //Range query

if (debug>1) System.out.println("1->16: "+query);

query = tree.query(7, 14); //Range query

if (debug>1) System.out.println("7->14: "+query);

query = tree.query(14, 15); //Range query

if (debug>1) System.out.println("14->15: "+query);

if (debug>1) System.out.println();

}

{

//Lifespan Interval tree

if (debug>1) System.out.println("Lifespan Interval Tree.");

java.util.List> intervals = new ArrayList>();

intervals.add((new IntervalTree.IntervalData(1888, 1971, "Stravinsky")));

intervals.add((new IntervalTree.IntervalData(1874, 1951, "Schoenberg")));

intervals.add((new IntervalTree.IntervalData(1843, 1907, "Grieg")));

intervals.add((new IntervalTree.IntervalData(1779, 1828, "Schubert")));

intervals.add((new IntervalTree.IntervalData(1756, 1791, "Mozart")));

intervals.add((new IntervalTree.IntervalData(1585, 1672, "Schuetz")));

IntervalTree tree = new IntervalTree(intervals);

if (debug>1) System.out.println(tree);

IntervalTree.IntervalData query = tree.query(1890);

if (debug>1) System.out.println("1890: "+query);

query = tree.query(1909); //Stabbing query

if (debug>1) System.out.println("1909: "+query);

query = tree.query(1792, 1903); //Range query

if (debug>1) System.out.println("1792->1903: "+query);

query = tree.query(1776, 1799); //Range query

if (debug>1) System.out.println("1776->1799: "+query);

if (debug>1) System.out.println();

}

return true;

}

private static boolean testJavaRedBlackTree() {

{

long count = 0;

long addTime = 0L;

long removeTime = 0L;

long beforeAddTime = 0L;

long afterAddTime = 0L;

long beforeRemoveTime = 0L;

long afterRemoveTime = 0L;

long memory = 0L;

long beforeMemory = 0L;

long afterMemory = 0L;

//Java's Red-Black Tree

if (debug>1) System.out.println("Java's Red-Black Tree");

testNames[testIndex] = "Java's RedBlack Tree";

count++;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddTime = System.currentTimeMillis();

java.util.TreeSet tree = new java.util.TreeSet();

for (int i=0; i

int item = unsorted[i];

tree.add(item);

}

if (debugTime) {

afterAddTime = System.currentTimeMillis();

addTime += afterAddTime-beforeAddTime;

if (debug>0) System.out.println("Java's Red-Black Tree add time = "+addTime/count+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Java's Red-Black Tree memory use = "+(memory/count)+" bytes");

}

boolean contains = tree.contains(INVALID);

boolean removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(tree.toString());

long lookupTime = 0L;

long beforeLookupTime = 0L;

long afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : unsorted) {

tree.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Java's Red-Black lookup time = "+lookupTime/count+" ms");

}

if (debugTime) beforeRemoveTime = System.currentTimeMillis();

for (int i=0; i

int item = unsorted[i];

tree.remove(item);

}

if (debugTime) {

afterRemoveTime = System.currentTimeMillis();

removeTime += afterRemoveTime-beforeRemoveTime;

if (debug>0) System.out.println("Java's Red-Black Tree remove time = "+removeTime/count+" ms");

}

contains = tree.contains(INVALID);

removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

count++;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddTime = System.currentTimeMillis();

for (int i=unsorted.length-1; i>=0; i--) {

int item = unsorted[i];

tree.add(item);

}

if (debugTime) {

afterAddTime = System.currentTimeMillis();

addTime += afterAddTime-beforeAddTime;

if (debug>0) System.out.println("Java's Red-Black Tree add time = "+addTime/count+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Java's Red-Black Tree memory use = "+(memory/count)+" bytes");

}

contains = tree.contains(INVALID);

removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(tree.toString());

lookupTime = 0L;

beforeLookupTime = 0L;

afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : unsorted) {

tree.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Java's Red-Black Tree lookup time = "+lookupTime/count+" ms");

}

if (debugTime) beforeRemoveTime = System.currentTimeMillis();

for (int i=0; i

int item = unsorted[i];

tree.remove(item);

}

if (debugTime) {

afterRemoveTime = System.currentTimeMillis();

removeTime += afterRemoveTime-beforeRemoveTime;

if (debug>0) System.out.println("Java's Red-Black Tree remove time = "+removeTime/count+" ms");

}

contains = tree.contains(INVALID);

removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

//sorted

long addSortedTime = 0L;

long removeSortedTime = 0L;

long beforeAddSortedTime = 0L;

long afterAddSortedTime = 0L;

long beforeRemoveSortedTime = 0L;

long afterRemoveSortedTime = 0L;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddSortedTime = System.currentTimeMillis();

for (int i=0; i

int item = sorted[i];

tree.add(item);

}

if (debugTime) {

afterAddSortedTime = System.currentTimeMillis();

addSortedTime += afterAddSortedTime-beforeAddSortedTime;

if (debug>0) System.out.println("Java's Red-Black Tree add time = "+addSortedTime+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Java's Red-Black Tree memory use = "+(memory/(count+1))+" bytes");

}

contains = tree.contains(INVALID);

removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(tree.toString());

lookupTime = 0L;

beforeLookupTime = 0L;

afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : sorted) {

tree.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Java's Red-Black Tree lookup time = "+lookupTime/(count+1)+" ms");

}

if (debugTime) beforeRemoveSortedTime = System.currentTimeMillis();

for (int i=sorted.length-1; i>=0; i--) {

int item = sorted[i];

tree.remove(item);

}

if (debugTime) {

afterRemoveSortedTime = System.currentTimeMillis();

removeSortedTime += afterRemoveSortedTime-beforeRemoveSortedTime;

if (debug>0) System.out.println("Java's Red-Black Tree remove time = "+removeSortedTime+" ms");

}

contains = tree.contains(INVALID);

removed = tree.remove(INVALID);

if (contains || removed) {

System.err.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Java's Red-Black Tree invalidity check. contains="+contains+" removed="+removed);

if (testResults[testIndex]==null) testResults[testIndex] = new long[6];

testResults[testIndex][0]+=addTime/count;

testResults[testIndex][1]+=removeTime/count;

testResults[testIndex][2]+=addSortedTime;

testResults[testIndex][3]+=removeSortedTime;

testResults[testIndex][4]+=lookupTime/(count+1);

testResults[testIndex++][5]+=memory/(count+1);

if (debug>1) System.out.println();

}

return true;

}

private static boolean testKdTree() {

{

// K-D TREE

if (debug>1) System.out.println("k-d tree with node.");

java.util.List points = new ArrayList();

KdTree.XYZPoint p1 = new KdTree.XYZPoint(2,3);

points.add(p1);

KdTree.XYZPoint p2 = new KdTree.XYZPoint(5,4);

points.add(p2);

KdTree.XYZPoint p3 = new KdTree.XYZPoint(9,6);

points.add(p3);

KdTree.XYZPoint p4 = new KdTree.XYZPoint(4,7);

points.add(p4);

KdTree.XYZPoint p5 = new KdTree.XYZPoint(8,1);

points.add(p5);

KdTree.XYZPoint p6 = new KdTree.XYZPoint(7,2);

points.add(p6);

KdTree kdTree = new KdTree(points);

if (debug>1) System.out.println(kdTree.toString());

Collection result = kdTree.nearestNeighbourSearch(1,p3);

if (debug>1) System.out.println("NNS for "+p3+" result="+result+"\n");

KdTree.XYZPoint search = new KdTree.XYZPoint(1,4);

result = kdTree.nearestNeighbourSearch(4,search);

if (debug>1) System.out.println("NNS for "+search+" result="+result+"\n");

kdTree.remove(p6);

if (debug>1) System.out.println("Removed "+p6+"\n"+kdTree.toString());

kdTree.remove(p4);

if (debug>1) System.out.println("Removed "+p4+"\n"+kdTree.toString());

kdTree.remove(p3);

if (debug>1) System.out.println("Removed "+p3+"\n"+kdTree.toString());

kdTree.remove(p5);

if (debug>1) System.out.println("Removed "+p5+"\n"+kdTree.toString());

kdTree.remove(p1);

if (debug>1) System.out.println("Removed "+p1+"\n"+kdTree.toString());

kdTree.remove(p2);

if (debug>1) System.out.println("Removed "+p2+"\n"+kdTree.toString());

if (debug>1) System.out.println();

}

return true;

} private static boolean testSegmentTree() {

{

//Quadrant Segment tree

if (debug>1) System.out.println("Quadrant Segment Tree.");

java.util.List segments = new ArrayList();

segments.add(new SegmentTree.Data.QuadrantData(0, 1, 0, 0, 0)); //first point in the 0th quadrant

segments.add(new SegmentTree.Data.QuadrantData(1, 0, 1, 0, 0)); //second point in the 1st quadrant

segments.add(new SegmentTree.Data.QuadrantData(2, 0, 0, 1, 0)); //third point in the 2nd quadrant

segments.add(new SegmentTree.Data.QuadrantData(3, 0, 0, 0, 1)); //fourth point in the 3rd quadrant

FlatSegmentTree tree = new FlatSegmentTree(segments);

if (debug>1) System.out.println(tree);

SegmentTree.Data.QuadrantData query = tree.query(0, 3);

if (debug>1) System.out.println("0->3: "+query+"\n");

query = tree.query(2, 3);

if (debug>1) System.out.println("2->3: "+query+"\n");

query = tree.query(0, 2);

if (debug>1) System.out.println("0->2: "+query+"\n");

if (debug>1) System.out.println();

}

{

//Range Maximum Segment tree

if (debug>1) System.out.println("Range Maximum Segment Tree.");

java.util.List> segments = new ArrayList>();

segments.add(new SegmentTree.Data.RangeMaximumData(0, (Integer)4));

segments.add(new SegmentTree.Data.RangeMaximumData(1, (Integer)2));

segments.add(new SegmentTree.Data.RangeMaximumData(2, (Integer)6));

segments.add(new SegmentTree.Data.RangeMaximumData(3, (Integer)3));

segments.add(new SegmentTree.Data.RangeMaximumData(4, (Integer)1));

segments.add(new SegmentTree.Data.RangeMaximumData(5, (Integer)5));

segments.add(new SegmentTree.Data.RangeMaximumData(6, (Integer)0));

segments.add(new SegmentTree.Data.RangeMaximumData(7, 17, (Integer)7));

segments.add(new SegmentTree.Data.RangeMaximumData(21, (Integer)10));

FlatSegmentTree> tree = new FlatSegmentTree>(segments,3);

if (debug>1) System.out.println(tree);

SegmentTree.Data.RangeMaximumData query = tree.query(0, 7);

if (debug>1) System.out.println("0->7: "+query+"\n");

query = tree.query(0, 21);

if (debug>1) System.out.println("0->21: "+query+"\n");

query = tree.query(2, 5);

if (debug>1) System.out.println("2->5: "+query+"\n");

query = tree.query(7);

if (debug>1) System.out.println("7: "+query+"\n");

if (debug>1) System.out.println();

}

{

//Range Minimum Segment tree

if (debug>1) System.out.println("Range Minimum Segment Tree.");

java.util.List> segments = new ArrayList>();

segments.add(new SegmentTree.Data.RangeMinimumData(0, (Integer)4));

segments.add(new SegmentTree.Data.RangeMinimumData(1, (Integer)2));

segments.add(new SegmentTree.Data.RangeMinimumData(2, (Integer)6));

segments.add(new SegmentTree.Data.RangeMinimumData(3, (Integer)3));

segments.add(new SegmentTree.Data.RangeMinimumData(4, (Integer)1));

segments.add(new SegmentTree.Data.RangeMinimumData(5, (Integer)5));

segments.add(new SegmentTree.Data.RangeMinimumData(6, (Integer)0));

segments.add(new SegmentTree.Data.RangeMinimumData(17, (Integer)7));

FlatSegmentTree> tree = new FlatSegmentTree>(segments,5);

if (debug>1) System.out.println(tree);

SegmentTree.Data.RangeMinimumData query = tree.query(0, 7);

if (debug>1) System.out.println("0->7: "+query+"\n");

query = tree.query(0, 17);

if (debug>1) System.out.println("0->17: "+query+"\n");

query = tree.query(1, 3);

if (debug>1) System.out.println("1->3: "+query+"\n");

query = tree.query(7);

if (debug>1) System.out.println("7: "+query+"\n");

if (debug>1) System.out.println();

}

{

//Range Sum Segment tree

if (debug>1) System.out.println("Range Sum Segment Tree.");

java.util.List> segments = new ArrayList>();

segments.add(new SegmentTree.Data.RangeSumData(0, (Integer)4));

segments.add(new SegmentTree.Data.RangeSumData(1, (Integer)2));

segments.add(new SegmentTree.Data.RangeSumData(2, (Integer)6));

segments.add(new SegmentTree.Data.RangeSumData(3, (Integer)3));

segments.add(new SegmentTree.Data.RangeSumData(4, (Integer)1));

segments.add(new SegmentTree.Data.RangeSumData(5, (Integer)5));

segments.add(new SegmentTree.Data.RangeSumData(6, (Integer)0));

segments.add(new SegmentTree.Data.RangeSumData(17, (Integer)7));

FlatSegmentTree> tree = new FlatSegmentTree>(segments,10);

if (debug>1) System.out.println(tree);

SegmentTree.Data.RangeSumData query = tree.query(0, 8);

if (debug>1) System.out.println("0->8: "+query+"\n");

query = tree.query(0, 17);

if (debug>1) System.out.println("0->17: "+query+"\n");

query = tree.query(2, 5);

if (debug>1) System.out.println("2->5: "+query+"\n");

query = tree.query(10, 17);

if (debug>1) System.out.println("10->17: "+query+"\n");

query = tree.query(16);

if (debug>1) System.out.println("16: "+query+"\n");

query = tree.query(17);

if (debug>1) System.out.println("17: "+query+"\n");

if (debug>1) System.out.println();

}

{

//Interval Segment tree

if (debug>1) System.out.println("Interval Segment Tree.");

java.util.List> segments = new ArrayList>();

segments.add((new SegmentTree.Data.IntervalData(2, 6, "RED")));

segments.add((new SegmentTree.Data.IntervalData(3, 5, "ORANGE")));

segments.add((new SegmentTree.Data.IntervalData(4, 11, "GREEN")));

segments.add((new SegmentTree.Data.IntervalData(5, 10, "DARK_GREEN")));

segments.add((new SegmentTree.Data.IntervalData(8, 12, "BLUE")));

segments.add((new SegmentTree.Data.IntervalData(9, 14, "PURPLE")));

segments.add((new SegmentTree.Data.IntervalData(13, 15, "BLACK")));

DynamicSegmentTree> tree = new DynamicSegmentTree>(segments);

if (debug>1) System.out.println(tree);

SegmentTree.Data.IntervalData query = tree.query(2);

if (debug>1) System.out.println("2: "+query);

query = tree.query(4); //Stabbing query

if (debug>1) System.out.println("4: "+query);

query = tree.query(9); //Stabbing query

if (debug>1) System.out.println("9: "+query);

query = tree.query(1, 16); //Range query

if (debug>1) System.out.println("1->16: "+query);

query = tree.query(7, 14); //Range query

if (debug>1) System.out.println("7->14: "+query);

query = tree.query(14, 15); //Range query

if (debug>1) System.out.println("14->15: "+query);

if (debug>1) System.out.println();

}

{

//Lifespan Interval Segment tree

if (debug>1) System.out.println("Lifespan Interval Segment Tree.");

java.util.List> segments = new ArrayList>();

segments.add((new SegmentTree.Data.IntervalData(1888, 1971, "Stravinsky")));

segments.add((new SegmentTree.Data.IntervalData(1874, 1951, "Schoenberg")));

segments.add((new SegmentTree.Data.IntervalData(1843, 1907, "Grieg")));

segments.add((new SegmentTree.Data.IntervalData(1779, 1828, "Schubert")));

segments.add((new SegmentTree.Data.IntervalData(1756, 1791, "Mozart")));

segments.add((new SegmentTree.Data.IntervalData(1585, 1672, "Schuetz")));

DynamicSegmentTree> tree = new DynamicSegmentTree>(segments,25);

if (debug>1) System.out.println(tree);

SegmentTree.Data.IntervalData query = tree.query(1890);

if (debug>1) System.out.println("1890: "+query);

query = tree.query(1909); //Stabbing query

if (debug>1) System.out.println("1909: "+query);

query = tree.query(1792, 1903); //Range query

if (debug>1) System.out.println("1792->1903: "+query);

query = tree.query(1776, 1799); //Range query

if (debug>1) System.out.println("1776->1799: "+query);

if (debug>1) System.out.println();

}

return true;

} private static boolean testSplayTree() {

{

long count = 0;

long addTime = 0L;

long removeTime = 0L;

long beforeAddTime = 0L;

long afterAddTime = 0L;

long beforeRemoveTime = 0L;

long afterRemoveTime = 0L;

long memory = 0L;

long beforeMemory = 0L;

long afterMemory = 0L;

//Splay Tree

if (debug>1) System.out.println("Splay Tree.");

testNames[testIndex] = "Splay Tree";

count++;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddTime = System.currentTimeMillis();

SplayTree splay = new SplayTree();

for (int i=0; i

int item = unsorted[i];

splay.add(item);

if (validateStructure && !(splay.size()==(i+1))) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && !splay.contains(item)) {

System.err.println("YIKES!! "+item+" doesn't exists.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterAddTime = System.currentTimeMillis();

addTime += afterAddTime-beforeAddTime;

if (debug>0) System.out.println("Splay Tree add time = "+addTime/count+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Splay Tree memory use = "+(memory/count)+" bytes");

}

boolean contains = splay.contains(INVALID);

boolean removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(splay.toString());

long lookupTime = 0L;

long beforeLookupTime = 0L;

long afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : unsorted) {

splay.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Splay Tree lookup time = "+lookupTime/count+" ms");

}

if (debugTime) beforeRemoveTime = System.currentTimeMillis();

for (int i=0; i

int item = unsorted[i];

splay.remove(item);

if (validateStructure && !(splay.size()==((unsorted.length-1)-i))) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && splay.contains(item)) {

System.err.println("YIKES!! "+item+" still exists.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterRemoveTime = System.currentTimeMillis();

removeTime += afterRemoveTime-beforeRemoveTime;

if (debug>0) System.out.println("Splay Tree remove time = "+removeTime/count+" ms");

}

contains = splay.contains(INVALID);

removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

count++;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddTime = System.currentTimeMillis();

for (int i=unsorted.length-1; i>=0; i--) {

int item = unsorted[i];

splay.add(item);

if (validateStructure && !(splay.size()==(unsorted.length-i))) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && !splay.contains(item)) {

System.err.println("YIKES!! "+item+" doesn't exists.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterAddTime = System.currentTimeMillis();

addTime += afterAddTime-beforeAddTime;

if (debug>0) System.out.println("Splay Tree add time = "+addTime/count+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Splay Tree memory use = "+(memory/count)+" bytes");

}

contains = splay.contains(INVALID);

removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(splay.toString());

lookupTime = 0L;

beforeLookupTime = 0L;

afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : unsorted) {

splay.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Splay Tree lookup time = "+lookupTime/count+" ms");

}

if (debugTime) beforeRemoveTime = System.currentTimeMillis();

for (int i=0; i

int item = unsorted[i];

splay.remove(item);

if (validateStructure && !(splay.size()==((unsorted.length-1)-i))) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && splay.contains(item)) {

System.err.println("YIKES!! "+item+" still exists.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterRemoveTime = System.currentTimeMillis();

removeTime += afterRemoveTime-beforeRemoveTime;

if (debug>0) System.out.println("Splay Tree remove time = "+removeTime/count+" ms");

}

contains = splay.contains(INVALID);

removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

//sorted

long addSortedTime = 0L;

long removeSortedTime = 0L;

long beforeAddSortedTime = 0L;

long afterAddSortedTime = 0L;

long beforeRemoveSortedTime = 0L;

long afterRemoveSortedTime = 0L;

if (debugMemory) beforeMemory = DataStructures.getMemoryUse();

if (debugTime) beforeAddSortedTime = System.currentTimeMillis();

for (int i=0; i

int item = sorted[i];

splay.add(item);

if (validateStructure && !(splay.size()==(i+1))) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && !splay.contains(item)) {

System.err.println("YIKES!! "+item+" doesn't exist.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterAddSortedTime = System.currentTimeMillis();

addSortedTime += afterAddSortedTime-beforeAddSortedTime;

if (debug>0) System.out.println("Splay Tree add time = "+addSortedTime+" ms");

}

if (debugMemory) {

afterMemory = DataStructures.getMemoryUse();

memory += afterMemory-beforeMemory;

if (debug>0) System.out.println("Splay Tree memory use = "+(memory/(count+1))+" bytes");

}

contains = splay.contains(INVALID);

removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

if (debug>1) System.out.println(splay.toString());

lookupTime = 0L;

beforeLookupTime = 0L;

afterLookupTime = 0L;

if (debugTime) beforeLookupTime = System.currentTimeMillis();

for (int item : sorted) {

splay.contains(item);

}

if (debugTime) {

afterLookupTime = System.currentTimeMillis();

lookupTime += afterLookupTime-beforeLookupTime;

if (debug>0) System.out.println("Splay Tree lookup time = "+lookupTime/(count+1)+" ms");

}

if (debugTime) beforeRemoveSortedTime = System.currentTimeMillis();

for (int i=sorted.length-1; i>=0; i--) {

int item = sorted[i];

splay.remove(item);

if (validateStructure && !(splay.size()==i)) {

System.err.println("YIKES!! "+item+" caused a size mismatch.");

handleError(splay);

return false;

}

if (validateContents && splay.contains(item)) {

System.err.println("YIKES!! "+item+" still exists.");

handleError(splay);

return false;

}

}

if (debugTime) {

afterRemoveSortedTime = System.currentTimeMillis();

removeSortedTime += afterRemoveSortedTime-beforeRemoveSortedTime;

if (debug>0) System.out.println("Splay Tree remove time = "+removeSortedTime+" ms");

}

contains = splay.contains(INVALID);

removed = splay.remove(INVALID);

if (contains || removed) {

System.err.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

return false;

} else System.out.println("Splay Tree invalidity check. contains="+contains+" removed="+removed);

if (testResults[testIndex]==null) testResults[testIndex] = new long[6];

testResults[testIndex][0]+=addTime/count;

testResults[testIndex][1]+=removeTime/count;

testResults[testIndex][2]+=addSortedTime;

testResults[testIndex][3]+=removeSortedTime;

testResults[testIndex][4]+=lookupTime/(count+1);

testResults[testIndex++][5]+=memory/(count+1);

if (debug>1) System.out.println();

}

return true;

}private static boolean testSuffixTree() {

{

//Suffix Tree

if (debug>1) System.out.println("Suffix Tree.");

String bookkeeper = "bookkeeper";

SuffixTree tree = new SuffixTree(bookkeeper);

if (debug>1) System.out.println(tree.toString());

if (debug>1) System.out.println(tree.getSuffixes());

boolean exists = tree.doesSubStringExist(bookkeeper);

if (!exists) {

System.err.println("YIKES!! "+bookkeeper+" doesn't exists.");

handleError(tree);

return false;

}

String failed = "booker";

exists = tree.doesSubStringExist(failed);

if (exists) {

System.err.println("YIKES!! "+failed+" exists.");

handleError(tree);

return false;

}

String pass = "kkee";

exists = tree.doesSubStringExist(pass);

if (!exists) {

System.err.println("YIKES!! "+pass+" doesn't exists.");

handleError(tree);

return false;

}

if (debug>1) System.out.println();

}

return true;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值