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

来源:互联网 发布:手机微信刷屏软件 编辑:程序博客网 时间:2024/05/29 07:39

区间树

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

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 <phishman3579@gmail.com> */public class IntervalTree<O extends Object> {    private Interval<O> root = null;    private static final Comparator<IntervalData<?>> startComparator = new Comparator<IntervalData<?>>(){        /**         * {@inheritDoc}         */        @Override        public int compare(IntervalData<?> arg0, IntervalData<?> arg1) {            if (arg0.start<arg1.start) return -1;            if (arg1.start<arg0.start) return 1;            return 0;        }    };    private static final Comparator<IntervalData<?>> endComparator = new Comparator<IntervalData<?>>(){        /**         * {@inheritDoc}         */        @Override        public int compare(IntervalData<?> arg0, IntervalData<?> arg1) {            if (arg0.end<arg1.end) return -1;            if (arg1.end<arg0.end) return 1;            return 0;        }    };    /**     * Create interval tree from list of IntervalData objects;     *      * @param intervals is a list of IntervalData objects     */    public IntervalTree(List<IntervalData<O>> intervals) {        if (intervals.size()<=0) return;        root = createFromList(intervals);    }    protected static final <O extends Object> Interval<O> createFromList(List<IntervalData<O>> intervals) {        Interval<O> newInterval = new Interval<O>();        int half = intervals.size()/2;        IntervalData<O> middle = intervals.get(half);        newInterval.center = ((middle.start+middle.end)/2);        List<IntervalData<O>> leftIntervals = new ArrayList<IntervalData<O>>();        List<IntervalData<O>> rightIntervals = new ArrayList<IntervalData<O>>();        for (IntervalData<O> interval : intervals) {            if (interval.end<newInterval.center) {                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<O> 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<O> 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 <O extends Object> String getString(IntervalTree<O> tree) {            if (tree.root == null) return "Tree has no nodes.";            return getString(tree.root, "", true);        }        private static <O extends Object> String getString(Interval<O> interval, String prefix, boolean isTail) {            StringBuilder builder = new StringBuilder();                builder.append( prefix + (isTail ? "└── " : "├── ") + interval.toString() + "\n" );            List<Interval<O>> children = new ArrayList<Interval<O>>();            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<O> {        private long center = Long.MIN_VALUE;        private Interval<O> left = null;        private Interval<O> right = null;        private Set<IntervalData<O>> overlap = new TreeSet<IntervalData<O>>(startComparator);        /**         * Stabbing query         *          * @param index to query for.         * @return data at index.         */        public IntervalData<O> query(long index) {            IntervalData<O> results = null;            if (index<center) {                //overlap is sorted by start point                for (IntervalData<O> data : overlap) {                    if (data.start>index) break;                    IntervalData<O> 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<IntervalData<O>> overlapEnd = new TreeSet<IntervalData<O>>(endComparator);                overlapEnd.addAll(overlap);                for (IntervalData<O> data : overlapEnd) {                    if (data.end<index) break;                    IntervalData<O> temp = data.query(index);                    if (results==null && temp!=null) results = temp;                    else if (temp!=null) results.combined(temp);                }            }            if (index<center) {                if (left!=null) {                    IntervalData<O> 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<O> 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<O> query(long start, long end) {            IntervalData<O> results = null;            for (IntervalData<O> data : overlap) {                if (data.start > end) break;                 IntervalData<O> temp = data.query(start,end);                if (results==null && temp!=null) results = temp;                else if (temp!=null) results.combined(temp);            }            if (left!=null && start<center) {                IntervalData<O> 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<O> 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<O> implements Comparable<IntervalData<O>>{        private long start = Long.MIN_VALUE;        private long end = Long.MAX_VALUE;        private Set<O> set = new TreeSet<O>(); //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<O> set) {            this.start = start;            this.end = end;            this.set = set;            //Make sure they are unique            Iterator<O> 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<O> combined(IntervalData<O> data) {            if (data.start<this.start) this.start = 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<O> copy() {            Set<O> listCopy = new TreeSet<O>();            listCopy.addAll(set);            return new IntervalData<O>(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<O> query(long index) {            if (index<this.start || index>this.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<O> query(long start, long end) {            if (end<this.start || start>this.end) {                //Ignore            } else {                return copy();            }            return null;        }        /**         * {@inheritDoc}         */        @Override        public boolean equals(Object obj) {            if (!(obj instanceof IntervalData)) return false;            @SuppressWarnings("unchecked")            IntervalData<O> data = (IntervalData<O>) 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<O> 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 <phishman3579@gmail.com> */public class KdTree<T extends KdTree.XYZPoint> {    private int k = 3;    private KdNode root = null;    private static final Comparator<XYZPoint> X_COMPARATOR = new Comparator<XYZPoint>() {        /**         * {@inheritDoc}         */        @Override        public int compare(XYZPoint o1, XYZPoint o2) {            if (o1.x<o2.x) return -1;            if (o1.x>o2.x) return 1;            return 0;        }    };    private static final Comparator<XYZPoint> Y_COMPARATOR = new Comparator<XYZPoint>() {        /**         * {@inheritDoc}         */        @Override        public int compare(XYZPoint o1, XYZPoint o2) {            if (o1.y<o2.y) return -1;            if (o1.y>o2.y) return 1;            return 0;        }    };    private static final Comparator<XYZPoint> Z_COMPARATOR = new Comparator<XYZPoint>() {        /**         * {@inheritDoc}         */        @Override        public int compare(XYZPoint o1, XYZPoint o2) {            if (o1.z<o2.z) return -1;            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<XYZPoint> 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<XYZPoint> 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<XYZPoint> 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<XYZPoint> 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 <T extends KdTree.XYZPoint> KdNode getNode(KdTree<T> 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<XYZPoint> 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<XYZPoint> 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<XYZPoint> 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<XYZPoint> getTree(KdNode root) {        List<XYZPoint> list = new ArrayList<XYZPoint>();        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<T> nearestNeighbourSearch(int K, T value) {        if (value==null) return null;        //Map used for results        TreeSet<KdNode> results = new TreeSet<KdNode>(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<KdNode> examined = new HashSet<KdNode>();            //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<T> collection = new ArrayList<T>(K);        for (KdNode kdNode : results) {            collection.add((T)kdNode.id);        }        return collection;    }    private static final <T extends KdTree.XYZPoint> void searchNode(T value, KdNode node, int K, TreeSet<KdNode> results, Set<KdNode> 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()<K) {            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<KdNode> {        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<KdNode> {        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<XYZPoint> {        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 <T extends XYZPoint> String getString(KdTree<T> tree) {            if (tree.root == null) return "Tree has no nodes.";            return getString(tree.root, "", true);        }        private static <T extends Comparable<T>> 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<KdNode> children = null;            if (node.lesser != null || node.greater != null) {                children = new ArrayList<KdNode>(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 <phishman3579@gmail.com> */public class RedBlackTree<T extends Comparable<T>> extends BinarySearchTree<T> implements BinarySearchTree.INodeCreator<T> {    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<T> creator) {        super(creator);    }    /**     * {@inheritDoc}     */    @Override    protected Node<T> addValue(T id) {        RedBlackNode<T> 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<T>(null, id, BLACK);                root.lesser = new RedBlackNode<T>(root,null,BLACK);                root.greater = new RedBlackNode<T>(root,null,BLACK);            } else {                root = this.creator.createNewNode(null, id);                ((RedBlackNode<T>)root).color = BLACK;                root.lesser = this.creator.createNewNode(root,null);                ((RedBlackNode<T>)root.lesser).color = BLACK;                root.greater = this.creator.createNewNode(root,null);                ((RedBlackNode<T>)root.greater).color = BLACK;            }            nodeAdded = (RedBlackNode<T>) root;            added = true;        } else {            //Insert node like a BST would            Node<T> node = root;            while (node != null) {                if (node.id==null) {                    node.id = id;                    ((RedBlackNode<T>)node).color = RED;                    if (this.creator==null) {                        node.lesser = new RedBlackNode<T>(node,null,BLACK);                        node.greater = new RedBlackNode<T>(node,null,BLACK);                    } else {                        node.lesser = this.creator.createNewNode(node,null);                        ((RedBlackNode<T>)node.lesser).color = BLACK;                        node.greater = this.creator.createNewNode(node,null);                        ((RedBlackNode<T>)node.greater).color = BLACK;                    }                    nodeAdded = (RedBlackNode<T>) 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<T> node) {        RedBlackNode<T> parent = (RedBlackNode<T>) 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<T> grandParent = node.getGrandParent();        RedBlackNode<T> 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<T>) node.lesser;                     grandParent = node.getGrandParent();                    parent = (RedBlackNode<T>) node.parent;                    uncle = node.getUncle();                } else if (node.equals(parent.lesser) && parent.equals(grandParent.greater)) {                    //left-right                    rotateRight(parent);                    node = (RedBlackNode<T>) node.greater;                       grandParent = node.getGrandParent();                    parent = (RedBlackNode<T>) 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<T> removeValue(T value) {        RedBlackNode<T> nodeRemoved = (RedBlackNode<T>) 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<T> lesser = (RedBlackNode<T>) nodeRemoved.lesser;            RedBlackNode<T> greater = (RedBlackNode<T>) nodeRemoved.greater;            if (lesser.id!=null && greater.id!=null) {                //Two children                RedBlackNode<T> greatestInLesser = (RedBlackNode<T>) 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<T> child = (RedBlackNode<T>)((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<T> nodeToReplace, RedBlackNode<T> 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<T> nodeToReplace, RedBlackNode<T> 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<T> node) {        if (node.parent==null) {            //Case 1 - node is the new root.            return true;        }        RedBlackNode<T> parent = (RedBlackNode<T>) node.parent;        RedBlackNode<T> 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<T>) node.parent;                sibling = node.getSibling();            } else if (node.equals(parent.greater)) {                rotateRight(parent);                //Rotation, need to update parent/sibling                parent = (RedBlackNode<T>) 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<T>)sibling.lesser).color==BLACK &&             ((RedBlackNode<T>)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<T>)sibling.lesser).color==BLACK &&                    ((RedBlackNode<T>)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<T>)sibling.lesser).color==RED &&                     ((RedBlackNode<T>)sibling.greater).color==BLACK                ) {                    sibling.color = RED;                    ((RedBlackNode<T>)sibling.lesser).color = RED;                    rotateRight(sibling);                    //Rotation, need to update parent/sibling                    parent = (RedBlackNode<T>) node.parent;                    sibling = node.getSibling();                } else if (node.equals(parent.greater)  &&                            ((RedBlackNode<T>)sibling.lesser).color==BLACK &&                            ((RedBlackNode<T>)sibling.greater).color==RED                ) {                    sibling.color = RED;                    ((RedBlackNode<T>)sibling.greater).color = RED;                    rotateLeft(sibling);                    //Rotation, need to update parent/sibling                    parent = (RedBlackNode<T>) 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<T>)sibling.greater).color = BLACK;                rotateLeft(node.parent);            } else if (node.equals(parent.greater)) {                ((RedBlackNode<T>)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<T>)root).color == RED) {            //Root node should be black            return false;        }        return this.validateNode(root);    }    /**     * {@inheritDoc}     */    @Override    protected boolean validateNode(Node<T> node) {        RedBlackNode<T> rbNode = (RedBlackNode<T>) node;        RedBlackNode<T> lesser = (RedBlackNode<T>) rbNode.lesser;        RedBlackNode<T> greater = (RedBlackNode<T>) 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<T> createNewNode(Node<T> parent, T id) {        return (new RedBlackNode<T>(parent, id, BLACK));    }    protected static class RedBlackNode<T extends Comparable<T>> extends Node<T> {        protected boolean color = BLACK;        protected RedBlackNode(Node<T> parent, T id, boolean color) {            super(parent,id);            this.color = color;        }        protected RedBlackNode<T> getGrandParent() {            if (parent==null || parent.parent==null) return null;             return (RedBlackNode<T>) parent.parent;        }        protected RedBlackNode<T> getUncle() {            RedBlackNode<T> grandParent = getGrandParent();            if (grandParent == null) return null;            if (grandParent.lesser!=null && grandParent.lesser.equals(parent)) {                return (RedBlackNode<T>) grandParent.greater;            } else if (grandParent.greater!=null && grandParent.greater.equals(parent)) {                return (RedBlackNode<T>) grandParent.lesser;            }            return null;        }        protected RedBlackNode<T> getSibling() {            if (parent==null) return null;            if (parent.lesser.equals(this)) {                return (RedBlackNode<T>) parent.greater;            } else if (parent.greater.equals(this)) {                return (RedBlackNode<T>) 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 <T extends Comparable<T>> String getString(RedBlackTree<T> tree) {            if (tree.root == null) return "Tree has no nodes.";            return getString((RedBlackNode<T>)tree.root, "", true);        }        public static <T extends Comparable<T>> String getString(RedBlackNode<T> node) {            if (node == null) return "Sub-tree has no nodes.";            return getString(node, "", true);        }        private static <T extends Comparable<T>> String getString(RedBlackNode<T> node, String prefix, boolean isTail) {            StringBuilder builder = new StringBuilder();            builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + ((node.color==RED)?"RED":"BLACK") + ") " + node.id + "\n");            List<Node<T>> children = null;            if (node.lesser != null || node.greater != null) {                children = new ArrayList<Node<T>>(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<T>)children.get(i), prefix + (isTail ? "    " : "│   "), false));                }                if (children.size() >= 1) {                    builder.append(getString((RedBlackNode<T>)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 <phishman3579@gmail.com> */public abstract class SegmentTree<D extends SegmentTree.Data> {    protected Segment<D> 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<Data> {        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<N extends Number> 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<N> q = null;                if (data instanceof RangeMaximumData) {                    q = (RangeMaximumData<N>) data;                    this.combined(q);                }                return this;            }            /**             * Combined for range maximum specific data.             *              * @param data resulted from the combination.             */            private void combined(RangeMaximumData<N> 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<N>(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<N> data = (RangeMaximumData<N>) 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<N extends Number> 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<N> q = null;                if (data instanceof RangeMinimumData) {                    q = (RangeMinimumData<N>) data;                    this.combined(q);                }                return this;            }            /**             * Combined specific to range minimum specific data.             *              * @param data resulted from combination.             */            private void combined(RangeMinimumData<N> 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<N>(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<N> data = (RangeMinimumData<N>) 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<N extends Number> 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<N> q = null;                if (data instanceof RangeSumData) {                    q = (RangeSumData<N>) data;                    this.combined(q);                }                return this;            }            /**             * Combined specific to range sum specific data.             *              * @param data resulted from combination.             */            @SuppressWarnings("unchecked")            private void combined(RangeSumData<N> 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<N>(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<N> data = (RangeSumData<N>) 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<O extends Object> extends Data {            private Set<O> set = new TreeSet<O>(); //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<O> set) {                super(start,end);                this.set = set;                //Make sure they are unique                Iterator<O> 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<O> q = null;                if (data instanceof IntervalData) {                    q = (IntervalData<O>) data;                    this.combined(q);                }                return this;            }            /**             * Combined for interval specific data.             *              * @param data resulted from combination.             */            private void combined(IntervalData<O> data) {                if (data.start<this.start) this.start = data.start;                if (data.end>this.end) this.end = data.end;                this.set.addAll(data.set);            }            /**             * {@inheritDoc}             */            @Override            public Data copy() {                Set<O> listCopy = new TreeSet<O>();                listCopy.addAll(set);                return new IntervalData<O>(start,end,listCopy);            }            /**             * {@inheritDoc}             */            @Override            public Data query(long start, long end) {                if (end<this.start || start>this.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<O> data = (IntervalData<O>) 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<D extends Data> implements Comparable<Segment<D>> {        protected Segment<D>[] 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<D> getLeftChild() {            return segments[0];        }        protected Segment<D> 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<D> p) {            if (this.end < p.end) return -1;            if (p.end < this.end) return 1;            return 0;        }    }    protected static class SegmentTreePrinter {        public static <D extends SegmentTree.Data> String getString(SegmentTree<D> tree) {            if (tree.root == null) return "Tree has no nodes.";            return getString(tree.root, "", true);        }        private static <D extends SegmentTree.Data> String getString(Segment<D> segment, String prefix, boolean isTail) {            StringBuilder builder = new StringBuilder();            builder.append( prefix + (isTail ? "└── " : "├── ") + segment.toString() + "\n" );            List<Segment<D>> children = new ArrayList<Segment<D>>();            if (segment.segments!=null) {                for (Segment<D> 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<D extends Data> extends SegmentTree<D> {        public FlatSegmentTree(List<D> data) {            this(data,1);        }        @SuppressWarnings("unchecked")        public FlatSegmentTree(List<D> 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.size()-2); 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<NonOverlappingSegment<D>> segments = new ArrayList<NonOverlappingSegment<D>>();            for (int i=0; i<data.size(); i++) {                if (i<data.size()-1) {                    Data d1 = data.get(i);                     NonOverlappingSegment<D> s1 = new NonOverlappingSegment<D>(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<D> s3 = new NonOverlappingSegment<D>(minLength,d3.start,d3.end,(D)d3);                         segments.add(s3);                    }                } else {                    Data d1 = data.get(i);                     NonOverlappingSegment<D> s1 = new NonOverlappingSegment<D>(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<root.start) start = root.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<D extends Data> extends Segment<D> {            private Set<Segment<D>> set = new TreeSet<Segment<D>>();            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 <D extends Data> Segment<D> createFromList(int minLength, List<NonOverlappingSegment<D>> segments, long start, int length) {                NonOverlappingSegment<D> segment = new NonOverlappingSegment<D>(minLength);                segment.start = start;                segment.end = start+(length-1);                segment.length = length;                for (Segment<D> 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<NonOverlappingSegment<D>> s1 = new ArrayList<NonOverlappingSegment<D>>();                    List<NonOverlappingSegment<D>> s2 = new ArrayList<NonOverlappingSegment<D>>();                    for (int i = 0; i < segments.size(); i++) {                        NonOverlappingSegment<D> s = segments.get(i);                        long middle = segment.start+segment.half;                        if (s.end<middle) {                            s1.add(s);                        } else if (s.start>=middle) {                            s2.add(s);                        } else {                            //Need to split across middle                            NonOverlappingSegment<D> ss1 = new NonOverlappingSegment<D>(minLength,s.start,middle-1,s.data);                            s1.add(ss1);                            NonOverlappingSegment<D> ss2 = new NonOverlappingSegment<D>(minLength,middle,s.end,s.data);                            s2.add(ss2);                        }                    }                    Segment<D> sub1 = createFromList(minLength,s1,segment.start,segment.half);                    Segment<D> 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<D> 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 (end<this.start || start>this.end) {                        //Ignore                    } else {                        D dataToReturn = null;                        if (this.set.size()==0) return dataToReturn;                        for (Segment<D> 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<D extends Data> extends SegmentTree<D> {        public DynamicSegmentTree(List<D> data) {            this(data,1);        }        @SuppressWarnings("unchecked")        public DynamicSegmentTree(List<D> data, int minLength) {            if (data.size()<=0) return;            //Check for gaps            List<OverlappingSegment<D>> segments = new ArrayList<OverlappingSegment<D>>();            for (int i=0; i<data.size(); i++) {                if (i<data.size()-1) {                    Data d1 = data.get(i);                     OverlappingSegment<D> s1 = new OverlappingSegment<D>(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<D> s3 = new OverlappingSegment<D>(minLength,d3.start,d3.end,(D)d3);                         segments.add(s3);                    }                } else {                    Data d1 = data.get(i);                     OverlappingSegment<D> s1 = new OverlappingSegment<D>(minLength,d1.start,d1.end,(D)d1);                    segments.add(s1);                }            }            //First start first            Collections.sort(segments,                 new Comparator<OverlappingSegment<D>>(){                    @Override                    public int compare(OverlappingSegment<D> arg0, OverlappingSegment<D> arg1) {                        if (arg0.start<arg1.start) return -1;                        if (arg1.start<arg0.start) return 1;                        return 0;                    }                }            );            OverlappingSegment<D> startNode = segments.get(0);            long start = startNode.start-1;            OverlappingSegment<D> s1 = new OverlappingSegment<D>(minLength,start,startNode.start,null);            segments.add(0,s1);            //Last end last            Collections.sort(segments,                 new Comparator<OverlappingSegment<D>>(){                    @Override                    public int compare(OverlappingSegment<D> arg0, OverlappingSegment<D> arg1) {                        if (arg0.end<arg1.end) return -1;                        if (arg1.end<arg0.end) return 1;                        return 0;                    }                }            );            OverlappingSegment<D> endNode = segments.get(segments.size()-1);            long end = endNode.end+1;            OverlappingSegment<D> s2 = new OverlappingSegment<D>(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<root.start) start = root.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<D extends Data> extends Segment<D> {            //Separate range set for fast range queries            protected Set<Segment<D>> range = new HashSet<Segment<D>>();            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 <D extends Data> Segment<D> createFromList(int minLength, List<OverlappingSegment<D>> segments, long start, int length) {                OverlappingSegment<D> segment = new OverlappingSegment<D>(minLength);                segment.start = start;                segment.end = start+(length-1);                segment.length = length;                for (Segment<D> s : segments) {                    if (s.data==null) continue;                    if (s.end<segment.start || s.start>segment.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<OverlappingSegment<D>> s1 = new ArrayList<OverlappingSegment<D>>();                    List<OverlappingSegment<D>> s2 = new ArrayList<OverlappingSegment<D>>();                    for (int i = 0; i < segments.size(); i++) {                        OverlappingSegment<D> s = segments.get(i);                        long middle = segment.start+segment.half;                        if (s.end<middle) {                            s1.add(s);                        } else if (s.start>=middle) {                            s2.add(s);                        } else {                            //Need to split across middle                            OverlappingSegment<D> ss1 = new OverlappingSegment<D>(minLength,s.start,middle-1,s.data);                            s1.add(ss1);                            OverlappingSegment<D> ss2 = new OverlappingSegment<D>(minLength,middle,s.end,s.data);                            s2.add(ss2);                        }                    }                    Segment<D> sub1 = createFromList(minLength,s1,segment.start,segment.half);                    Segment<D> 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<D> 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 (end<this.start || start>this.end) {                        //Ignore                    } else {                        for (Segment<D> s : this.range) {                            if (end<s.start || start>s.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 && end>=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<middle) {                        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 <phishman3579@gmail.com> */public class SplayTree<T extends Comparable<T>> extends BinarySearchTree<T> {    /**     * {@inheritDoc}     */    @Override    protected Node<T> addValue(T id) {        Node<T> nodeToReturn = super.addValue(id);        Node<T> 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<T> removeValue(T value) {        Node<T> nodeToRemove = super.removeValue(value);        if (nodeToRemove!=null) {            if (nodeToRemove.parent!=null) {                Node<T> 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<T> 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<T> node) {        Node<T> parent = node.parent;        Node<T> 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<T> 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<T> nodeGreater = node.greater;                    node.greater = parent;                    parent.parent = node;                    parent.lesser = nodeGreater;                    if (nodeGreater != null) nodeGreater.parent = parent;                    Node<T> parentGreater = parent.greater;                    parent.greater = grandParent;                    grandParent.parent = parent;                    grandParent.lesser = parentGreater;                    if (parentGreater != null) parentGreater.parent = grandParent;                } else {                    Node<T> nodeLesser = node.lesser;                    node.lesser = parent;                    parent.parent = node;                    parent.greater = nodeLesser;                    if (nodeLesser != null) nodeLesser.parent = parent;                    Node<T> 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<T> nodeLesser = node.greater;                    Node<T> 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<T> nodeLesser = node.lesser;                    Node<T> 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 <phishman3579@gmail.com> */public class SuffixTree<C extends CharSequence> {    private static final char DEFAULT_END_SEQ_CHAR = '$';    private String string = null;    private char[] characters = null;    private Map<Integer, Link> linksMap = new HashMap<Integer, Link>();    private Map<Integer, Edge<C>> edgeMap = new TreeMap<Integer, Edge<C>>();    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<String> getSuffixes() {        Set<String> 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<String> getSuffixes(int start) {        Set<String> set = new TreeSet<String>();        for (int key : edgeMap.keySet()) {            Edge<C> 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<String> 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<C> 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<C> 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<C>(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<C> 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<C> 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<Link> {        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<C extends CharSequence> implements Comparable<Edge<C>> {        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<C> tree = null;        private int startNode = -1;        private int endNode = 0;        private int firstCharIndex = 0;        private int lastCharIndex = 0;        private Edge(SuffixTree<C> 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<C> edge) {            tree.edgeMap.put(edge.getKey(), edge);        }        private void remove(Edge<C> edge) {            int i = edge.getKey();            Edge<C> 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 <C extends CharSequence> Edge<C> find(SuffixTree<C> 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<C> newEdge = new Edge<C>(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<C> e = (Edge<C>) 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<C> 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 <C extends CharSequence> void printNode(SuffixTree<C> tree) {            System.out.println(getString(tree, null, "", true));        }        public static <C extends CharSequence> String getString(SuffixTree<C> tree) {            return getString(tree, null, "", true);        }        private static <C extends CharSequence> String getString(SuffixTree<C> tree, Edge<C> 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<Edge<C>> children = new LinkedList<Edge<C>>();                for (Edge<C> 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<C> edge = children.get(i);                        builder.append(getString(tree, edge, prefix + (isTail ? "    " : "│   "), false));                    }                    if (children.size() >= 1) {                        Edge<C> 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<IntervalTree.IntervalData<String>> intervals = new ArrayList<IntervalTree.IntervalData<String>>();            intervals.add((new IntervalTree.IntervalData<String>(2, 6, "RED")));            intervals.add((new IntervalTree.IntervalData<String>(3, 5, "ORANGE")));            intervals.add((new IntervalTree.IntervalData<String>(4, 11, "GREEN")));            intervals.add((new IntervalTree.IntervalData<String>(5, 10, "DARK_GREEN")));            intervals.add((new IntervalTree.IntervalData<String>(8, 12, "BLUE")));            intervals.add((new IntervalTree.IntervalData<String>(9, 14, "PURPLE")));            intervals.add((new IntervalTree.IntervalData<String>(13, 15, "BLACK")));            IntervalTree<String> tree = new IntervalTree<String>(intervals);            if (debug>1) System.out.println(tree);            IntervalTree.IntervalData<String> 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<IntervalTree.IntervalData<String>> intervals = new ArrayList<IntervalTree.IntervalData<String>>();            intervals.add((new IntervalTree.IntervalData<String>(1888, 1971, "Stravinsky")));            intervals.add((new IntervalTree.IntervalData<String>(1874, 1951, "Schoenberg")));            intervals.add((new IntervalTree.IntervalData<String>(1843, 1907, "Grieg")));            intervals.add((new IntervalTree.IntervalData<String>(1779, 1828, "Schubert")));            intervals.add((new IntervalTree.IntervalData<String>(1756, 1791, "Mozart")));            intervals.add((new IntervalTree.IntervalData<String>(1585, 1672, "Schuetz")));            IntervalTree<String> tree = new IntervalTree<String>(intervals);            if (debug>1) System.out.println(tree);            IntervalTree.IntervalData<String> 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<Integer> tree = new java.util.TreeSet<Integer>();            for (int i=0; i<unsorted.length; 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<unsorted.length; 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<unsorted.length; 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<sorted.length; 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<KdTree.XYZPoint> points = new ArrayList<KdTree.XYZPoint>();            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.XYZPoint> kdTree = new KdTree<KdTree.XYZPoint>(points);            if (debug>1) System.out.println(kdTree.toString());            Collection<KdTree.XYZPoint> 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<SegmentTree.Data.QuadrantData> segments = new ArrayList<SegmentTree.Data.QuadrantData>();            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<SegmentTree.Data.QuadrantData> tree = new FlatSegmentTree<SegmentTree.Data.QuadrantData>(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<SegmentTree.Data.RangeMaximumData<Integer>> segments = new ArrayList<SegmentTree.Data.RangeMaximumData<Integer>>();            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(0, (Integer)4));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(1, (Integer)2));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(2, (Integer)6));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(3, (Integer)3));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(4, (Integer)1));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(5, (Integer)5));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(6, (Integer)0));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(7, 17, (Integer)7));            segments.add(new SegmentTree.Data.RangeMaximumData<Integer>(21, (Integer)10));            FlatSegmentTree<SegmentTree.Data.RangeMaximumData<Integer>> tree = new FlatSegmentTree<SegmentTree.Data.RangeMaximumData<Integer>>(segments,3);            if (debug>1) System.out.println(tree);            SegmentTree.Data.RangeMaximumData<Integer> 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<SegmentTree.Data.RangeMinimumData<Integer>> segments = new ArrayList<SegmentTree.Data.RangeMinimumData<Integer>>();            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(0, (Integer)4));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(1, (Integer)2));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(2, (Integer)6));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(3, (Integer)3));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(4, (Integer)1));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(5, (Integer)5));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(6, (Integer)0));            segments.add(new SegmentTree.Data.RangeMinimumData<Integer>(17, (Integer)7));            FlatSegmentTree<SegmentTree.Data.RangeMinimumData<Integer>> tree = new FlatSegmentTree<SegmentTree.Data.RangeMinimumData<Integer>>(segments,5);            if (debug>1) System.out.println(tree);            SegmentTree.Data.RangeMinimumData<Integer> 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<SegmentTree.Data.RangeSumData<Integer>> segments = new ArrayList<SegmentTree.Data.RangeSumData<Integer>>();            segments.add(new SegmentTree.Data.RangeSumData<Integer>(0, (Integer)4));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(1, (Integer)2));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(2, (Integer)6));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(3, (Integer)3));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(4, (Integer)1));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(5, (Integer)5));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(6, (Integer)0));            segments.add(new SegmentTree.Data.RangeSumData<Integer>(17, (Integer)7));            FlatSegmentTree<SegmentTree.Data.RangeSumData<Integer>> tree = new FlatSegmentTree<SegmentTree.Data.RangeSumData<Integer>>(segments,10);            if (debug>1) System.out.println(tree);            SegmentTree.Data.RangeSumData<Integer> 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<SegmentTree.Data.IntervalData<String>> segments = new ArrayList<SegmentTree.Data.IntervalData<String>>();            segments.add((new SegmentTree.Data.IntervalData<String>(2, 6, "RED")));            segments.add((new SegmentTree.Data.IntervalData<String>(3, 5, "ORANGE")));            segments.add((new SegmentTree.Data.IntervalData<String>(4, 11, "GREEN")));            segments.add((new SegmentTree.Data.IntervalData<String>(5, 10, "DARK_GREEN")));            segments.add((new SegmentTree.Data.IntervalData<String>(8, 12, "BLUE")));            segments.add((new SegmentTree.Data.IntervalData<String>(9, 14, "PURPLE")));            segments.add((new SegmentTree.Data.IntervalData<String>(13, 15, "BLACK")));            DynamicSegmentTree<SegmentTree.Data.IntervalData<String>> tree = new DynamicSegmentTree<SegmentTree.Data.IntervalData<String>>(segments);            if (debug>1) System.out.println(tree);            SegmentTree.Data.IntervalData<String> 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<SegmentTree.Data.IntervalData<String>> segments = new ArrayList<SegmentTree.Data.IntervalData<String>>();            segments.add((new SegmentTree.Data.IntervalData<String>(1888, 1971, "Stravinsky")));            segments.add((new SegmentTree.Data.IntervalData<String>(1874, 1951, "Schoenberg")));            segments.add((new SegmentTree.Data.IntervalData<String>(1843, 1907, "Grieg")));            segments.add((new SegmentTree.Data.IntervalData<String>(1779, 1828, "Schubert")));            segments.add((new SegmentTree.Data.IntervalData<String>(1756, 1791, "Mozart")));            segments.add((new SegmentTree.Data.IntervalData<String>(1585, 1672, "Schuetz")));            DynamicSegmentTree<SegmentTree.Data.IntervalData<String>> tree = new DynamicSegmentTree<SegmentTree.Data.IntervalData<String>>(segments,25);            if (debug>1) System.out.println(tree);            SegmentTree.Data.IntervalData<String> 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<Integer> splay = new SplayTree<Integer>();            for (int i=0; i<unsorted.length; 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<unsorted.length; 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<unsorted.length; 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<sorted.length; 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<String> tree = new SuffixTree<String>(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;    }


原创粉丝点击