`

java 关于二叉搜索树,平衡二叉树,b树,二叉堆的几段代码

 
阅读更多

最近重新学习数据结构和算法,刚刚看完java版的这几个数据结构,比较浅显易懂,有兴趣的可以自己去调试学习,关于这几个的介绍网上很多。

 

二叉搜索树,比较简单的树结构了

 

package com.jwetherell.algorithms.data_structures;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Queue;

/**
 * A binary search tree (BST), which may sometimes also be called an ordered or
 * sorted binary tree, is a node-based binary tree data structure which has the
 * following properties: 1) The left subtree of a node contains only nodes with
 * keys less than the node's key. 2) The right subtree of a node contains only
 * nodes with keys greater than the node's key. 3) Both the left and right
 * subtrees must also be binary search trees.
 * 
 * http://en.wikipedia.org/wiki/Binary_search_tree
 * 
 * @author Justin Wetherell <phishman3579@gmail.com>
 */
public class BinarySearchTree<T extends Comparable<T>> {

    private int modifications = 0;
    
    protected static final Random RANDOM = new Random();
    protected enum Position { LEFT, RIGHT };

    protected Node<T> root = null;
    protected int size = 0;
    protected INodeCreator<T> creator = null;


    /**
     * Default constructor.
     */
    public BinarySearchTree() { }

    /**
     * Constructor with external Node creator.
     */
    public BinarySearchTree(INodeCreator<T> creator) {
        this.creator = creator;
    }

    /**
     * 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) {
        Node<T> nodeAdded = this.addValue(value);
        return (nodeAdded!=null);
    }

    /**
     * Add value to the tree and return the Node that was added. Tree can 
     * contain multiple equal values.
     * 
     * @param value T to add to the tree.
     * @return Node<T> which was added to the tree.
     */
    protected Node<T> addValue(T value) {
        Node<T> newNode = null;
        if (this.creator == null) newNode = new Node<T>(null, value);
        else newNode = this.creator.createNewNode(null, value);

        //If root is null, assign
        if (root == null) {
            root = newNode;
            size++;
            return newNode;
        }

        Node<T> node = root;
        while (node != null) {
            if (newNode.id.compareTo(node.id) <= 0) {
                //Less than or equal to goes left
                if (node.lesser == null) {
                    // New left node
                    node.lesser = newNode;
                    newNode.parent = node;
                    size++;
                    return newNode;
                } else {
                    node = node.lesser;
                }
            } else {
                //Greater than goes right
                if (node.greater == null) {
                    // New right node
                    node.greater = newNode;
                    newNode.parent = node;
                    size++;
                    return newNode;
                } else {
                    node = node.greater;
                }
            }
        }

        return newNode;
    }

    /**
     * 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) {
        Node<T> node = getNode(value);
        return (node != null);
    }

    /**
     * Locate T in the tree.
     * 
     * @param value T to locate in the tree.
     * @return Node<T> representing first reference of value in tree or NULL if not found.
     */
    protected Node<T> getNode(T value) {
        Node<T> node = root;
        while (node != null && node.id!=null) {
            if (value.compareTo(node.id) == 0) {
                return node;
            } else if (value.compareTo(node.id) < 0) {
                node = node.lesser;
            } else {
                node = node.greater;
            }
        }
        return null;
    }

    /**
     * Rotate tree left at sub-tree rooted at node.
     * 
     * @param node Root of tree to rotate left.
     */
    protected void rotateLeft(Node<T> node) {
        Position parentPosition = null;
        Node<T> parent = node.parent;
        if (parent!=null) {
            if (node.equals(parent.lesser)) {
                //Lesser
                parentPosition = Position.LEFT;
            } else {
                //Greater
                parentPosition = Position.RIGHT;
            }
        }
        
        Node<T> greater = node.greater;
        node.greater = null;
        Node<T> lesser = greater.lesser;
        
        greater.lesser = node;
        node.parent = greater;
        
        node.greater = lesser;
        if (lesser!=null) lesser.parent = node;
        
        if (parentPosition!=null) {
            if (parentPosition==Position.LEFT) {
                parent.lesser = greater;
            } else {
                parent.greater = greater;
            }
            greater.parent = parent;
        } else {
            root = greater;
            greater.parent = null;
        }
    }

    /**
     * Rotate tree right at sub-tree rooted at node.
     * 
     * @param node Root of tree to rotate left.
     */
    protected void rotateRight(Node<T> node) {
        Position parentPosition = null;
        Node<T> parent = node.parent;
        if (parent!=null) {
            if (node.equals(parent.lesser)) {
                //Lesser
                parentPosition = Position.LEFT;
            } else {
                //Greater
                parentPosition = Position.RIGHT;
            }
        }
        
        Node<T> lesser = node.lesser;
        node.lesser = null;
        Node<T> greater = lesser.greater;
        
        lesser.greater = node;
        node.parent = lesser;
        
        node.lesser = greater;
        if (greater!=null) greater.parent = node;
        
        if (parentPosition!=null) {
            if (parentPosition==Position.LEFT) {
                parent.lesser = lesser;
            } else {
                parent.greater = lesser;
            }
            lesser.parent = parent;
        } else {
            root = lesser;
            lesser.parent = null;
        }
    }

    /**
     * Get greatest node in sub-tree rooted at startingNode. The 
     * search does not include startingNode in it's results.
     * 
     * @param startingNode Root of tree to search.
     * @return Node<T> which represents the greatest node in the 
     * startingNode sub-tree or NULL if startingNode has no greater
     * children.
     */
    protected Node<T> getGreatest(Node<T> startingNode) {
        if (startingNode==null) return null;

        Node<T> greater = startingNode.greater;
        while (greater!=null && greater.id!=null) {
            Node<T> node = greater.greater;
            if (node!=null && node.id!=null) greater = node;
            else break;
        }
        return greater;
    }

    /**
     * Get least node in sub-tree rooted at startingNode. The 
     * search does not include startingNode in it's results.
     * 
     * @param startingNode Root of tree to search.
     * @return Node<T> which represents the least node in the 
     * startingNode sub-tree or NULL if startingNode has no lesser
     * children.
     */
    protected Node<T> getLeast(Node<T> startingNode) {
        if (startingNode==null) return null;

        Node<T> lesser = startingNode.lesser;
        while (lesser!=null && lesser.id!=null) {
            Node<T> node = lesser.lesser;
            if (node!=null && node.id!=null) lesser = node;
            else break;
        }
        return 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) {
        Node<T> nodeToRemove = this.removeValue(value);
        return (nodeToRemove!=null);
    }

    /**
     * Remove first occurrence of value in the tree.
     * 
     * @param value T to remove from the tree.
     * @return Node<T> which was removed from the tree.
     */
    protected Node<T> removeValue(T value) {
        Node<T> nodeToRemoved = this.getNode(value);
        if (nodeToRemoved != null) {
            Node<T> replacementNode = this.getReplacementNode(nodeToRemoved);
            replaceNodeWithNode(nodeToRemoved,replacementNode);
        }
        return nodeToRemoved;
    }

    /**
     * Get the proper replacement node according to the binary 
     * search tree algorithm from the tree.
     * 
     * @param nodeToRemoved Node<T> to find a replacement for.
     * @return Node<T> which can be used to replace nodeToRemoved. 
     * nodeToRemoved should NOT be NULL.
     */
    protected Node<T> getReplacementNode(Node<T> nodeToRemoved) {
        Node<T> replacement = null;
        Node<T> parent = nodeToRemoved.parent;
        if (parent == null) {
            // Replacing the root node
            if (nodeToRemoved.lesser != null && nodeToRemoved.greater == null) {
                // Replace with lesser subtree
                replacement = nodeToRemoved.lesser;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser==null) {
                // Replace with greater subtree
                replacement = nodeToRemoved.greater;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser!=null) {
                //Two children
                replacement = this.getLeast(nodeToRemoved.greater);
                if (replacement==null) replacement = nodeToRemoved.greater;
            }
        } else if (parent.lesser != null && (parent.lesser.id.compareTo(nodeToRemoved.id) == 0)) {
            // If the node to remove is the parent's lesser node, replace
            // the parent's lesser node with one of the node to remove's
            // lesser/greater subtrees
            if (nodeToRemoved.lesser != null && nodeToRemoved.greater == null) {
                // Using the less subtree
                replacement = nodeToRemoved.lesser;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser == null) {
                // Using the greater subtree (there is no lesser subtree, no refactoring)
                replacement = nodeToRemoved.greater;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser!=null) {
                //Two children
                replacement = this.getLeast(nodeToRemoved.greater);
                if (replacement==null) replacement = nodeToRemoved.greater;
            }
        } else if (parent.greater != null && (parent.greater.id.compareTo(nodeToRemoved.id) == 0)) {
            // If the node to remove is the parent's greater node, replace
            // the parent's greater node with the node's greater node
            if (nodeToRemoved.lesser != null && nodeToRemoved.greater == null) {
                // Using the less subtree
                replacement = nodeToRemoved.lesser;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser == null) {
                // Using the greater subtree (there is no lesser subtree, no refactoring)
                replacement = nodeToRemoved.greater;
            } else if (nodeToRemoved.greater != null && nodeToRemoved.lesser!=null) {
                //Two children - use either the greatest child in the lesser branch or the least child in the greater branch
                
                //Add some randomness to deletions, so we don't always use the greatest/least on deletion
                if (modifications%2!=0) {
                    replacement = this.getGreatest(nodeToRemoved.lesser);
                    if (replacement==null) replacement = nodeToRemoved.lesser;
                } else { 
                    replacement = this.getLeast(nodeToRemoved.greater);
                    if (replacement==null) replacement = nodeToRemoved.greater;
                }
                modifications++;
            }
        }
        return replacement;
    }

    /**
     * Replace nodeToRemoved with replacementNode in the tree.
     * 
     * @param nodeToRemoved Node<T> to remove replace in the tree. nodeToRemoved 
     * should NOT be NULL.
     * @param replacementNode Node<T> to replace nodeToRemoved in the tree. replacementNode
     * can be NULL.
     */
    protected void replaceNodeWithNode(Node<T> nodeToRemoved, Node<T> replacementNode) {
        if (replacementNode!=null) {
            //Save for later
            Node<T> replacementNodeLesser = replacementNode.lesser;
            Node<T> replacementNodeGreater = replacementNode.greater;

            //Replace replacementNode's branches with nodeToRemove's branches
            Node<T> nodeToRemoveLesser = nodeToRemoved.lesser;
            if (nodeToRemoveLesser!=null && !nodeToRemoveLesser.equals(replacementNode)) {
                replacementNode.lesser = nodeToRemoveLesser;
                nodeToRemoveLesser.parent = replacementNode;
            }
            Node<T> nodeToRemoveGreater = nodeToRemoved.greater;
            if (nodeToRemoveGreater!=null && !nodeToRemoveGreater.equals(replacementNode)) {
                replacementNode.greater = nodeToRemoveGreater;
                nodeToRemoveGreater.parent = replacementNode;
            }

            //Remove link from replacementNode's parent to replacement
            Node<T> replacementParent = replacementNode.parent;
            if (replacementParent!=null && !replacementParent.equals(nodeToRemoved)) {
                Node<T> replacementParentLesser = replacementParent.lesser;
                Node<T> replacementParentGreater = replacementParent.greater;
                if (replacementParentLesser!=null && replacementParentLesser.equals(replacementNode)) {
                    replacementParent.lesser = replacementNodeGreater;
                    if (replacementNodeGreater!=null) replacementNodeGreater.parent = replacementParent;
                } else if (replacementParentGreater!=null && replacementParentGreater.equals(replacementNode)) {
                    replacementParent.greater = replacementNodeLesser;
                    if (replacementNodeLesser!=null) replacementNodeLesser.parent = replacementParent;
                }
            }
        }

        //Update the link in the tree from the nodeToRemoved to the replacementNode
        Node<T> parent = nodeToRemoved.parent;
        if (parent == null) {
            // Replacing the root node
            root = replacementNode;
            if (root!=null) root.parent = null;
        } else if (parent.lesser != null && (parent.lesser.id.compareTo(nodeToRemoved.id) == 0)) {
            parent.lesser = replacementNode;
            if (replacementNode!=null) replacementNode.parent = parent;
        } else if (parent.greater != null && (parent.greater.id.compareTo(nodeToRemoved.id) == 0)) {
            parent.greater = replacementNode;
            if (replacementNode!=null) replacementNode.parent = parent;
        }
        size--;
    }

    /**
     * Get number of nodes in the tree.
     * 
     * @return Number of nodes in the tree.
     */
    public int size() {
        return size;
    }

    /**
     * Validate the tree for all Binary Search Tree invariants.
     * 
     * @return True if tree is valid.
     */
    public boolean validate() {
        if (root==null) return true;
        return validateNode(root);
    }

    /**
     * Validate the node for all Binary Search Tree invariants.
     * 
     * @param node Node<T> to validate in the tree. node should
     * NOT be NULL. 
     * @return True if the node is valid.
     */
    protected boolean validateNode(Node<T> node) {
        Node<T> lesser = node.lesser;
        Node<T> greater = node.greater;

        boolean lesserCheck = true;
        if (lesser!=null && lesser.id!=null) {
            lesserCheck = (lesser.id.compareTo(node.id) <= 0);
            if (lesserCheck) lesserCheck = validateNode(lesser);
        }
        if (!lesserCheck) return false;

        boolean greaterCheck = true;
        if (greater!=null && greater.id!=null) {
            greaterCheck = (greater.id.compareTo(node.id) > 0);
            if (greaterCheck) greaterCheck = validateNode(greater);
        }
        return greaterCheck;
    }

    /**
     * Get an array representation of the tree in breath first search order.
     * 
     * @return breath first search sorted array representing the tree.
     */
    @SuppressWarnings("unchecked")
    public T[] getBFS() {
        Queue<Node<T>> queue = new ArrayDeque<Node<T>>();
        T[] values = (T[]) new Comparable[size];
        int count = 0;
        Node<T> node = root;
        while (node!=null) {
            values[count++] = node.id;
            if (node.lesser!=null) queue.add(node.lesser);
            if (node.greater!=null) queue.add(node.greater);
            if (!queue.isEmpty()) node = queue.remove();
            else node = null;
        }
        return values;
    }

    /**
     * Get an array representation of the tree in depth first search order.
     * 
     * @return depth first search sorted array representing the tree.
     */
    @SuppressWarnings("unchecked")
    public T[] getDFS() {
        List<Node<T>> added = new ArrayList<Node<T>>(2);
        T[] nodes = (T[]) new Comparable[size];
        int index = 0;
        Node<T> node = root;
        while (index < size && node != null) {
            Node<T> parent = node.parent;
            Node<T> lesser = (node.lesser != null && !added.contains(node.lesser)) ? node.lesser : null;
            Node<T> greater = (node.greater != null && !added.contains(node.greater)) ? node.greater : null;

            if (parent == null && lesser == null && greater == null) {
                if (!added.contains(node)) nodes[index++] = node.id;
                break;
            }

            if (lesser != null) {
                node = lesser;
            } else {
                if (!added.contains(node)) {
                    nodes[index++] = node.id;
                    added.add(node);
                }
                if (greater != null) {
                    node = greater;
                } else if (greater == null && added.contains(node)) {
                    node = parent;
                } else {
                    // We should not get here. Stop the loop!
                    node = null;
                }
            }
        }
        return nodes;
    }
    
    /**
     * Get an array representation of the tree in sorted order.
     * 
     * @return sorted array representing the tree.
     */
    public T[] getSorted() {
        // Depth first search to traverse the tree in order.
        return getDFS();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return TreePrinter.getString(this);
    }

    protected static class Node<T extends Comparable<T>> {

        protected T id = null;
        protected Node<T> parent = null;
        protected Node<T> lesser = null;
        protected Node<T> greater = null;


        /**
         * Node constructor.
         * 
         * @param parent Parent link in tree. parent can be NULL.
         * @param id T representing the node in the tree.
         */
        protected Node(Node<T> parent, T id) {
            this.parent = parent;
            this.id = id;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return "id =" + id + 
                   " parent=" + ((parent != null) ? parent.id : "NULL") + 
                   " lesser=" + ((lesser != null) ? lesser.id : "NULL") + 
                   " greater=" + ((greater != null) ? greater.id : "NULL");
        }
    }

    protected static interface INodeCreator<T extends Comparable<T>> {

        /**
         * Create a new Node with the following parameters.
         * 
         * @param parent of this node.
         * @param id of this node.
         * @return new Node
         */
        public Node<T> createNewNode(Node<T> parent, T id);
    }

    protected static class TreePrinter {

        public static <T extends Comparable<T>> String getString(BinarySearchTree<T> tree) {
            if (tree.root == null) return "Tree has no nodes.";
            return getString(tree.root, "", true);
        }

        private static <T extends Comparable<T>> String getString(Node<T> node, String prefix, boolean isTail) {
            StringBuilder builder = new StringBuilder();

            if (node.parent!=null) {
                String side = "left";
                if (node.equals(node.parent.greater)) side = "right";
                builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + side + ") " + node.id + "\n");
            } else {
                builder.append(prefix + (isTail ? "└── " : "├── ") + 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(children.get(i), prefix + (isTail ? "    " : "│   "), false));
                }
                if (children.size() >= 1) {
                    builder.append(getString(children.get(children.size() - 1), prefix + (isTail ? "    " : "│   "), true));
                }
            }

            return builder.toString();
        }
    }
}

 

平衡二叉树,AVL树,比较复杂了,需要对旋转

 

package com.jwetherell.algorithms.data_structures;

import java.util.ArrayList;
import java.util.List;


/**
 * An AVL tree is a self-balancing binary search tree, and it was the first such data 
 * structure to be invented. In an AVL tree, the heights of the two child subtrees 
 * of any node differ by at most one. AVL trees are often compared with red-black trees 
 * because they support the same set of operations and because red-black trees also take 
 * O(log n) time for the basic operations. Because 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/AVL_tree
 * 
 * @author Justin Wetherell <phishman3579@gmail.com>
 */
public class AVLTree<T extends Comparable<T>> extends BinarySearchTree<T> implements BinarySearchTree.INodeCreator<T> {

    private enum Balance { LEFT_LEFT, LEFT_RIGHT, RIGHT_LEFT, RIGHT_RIGHT }; 


    /**
     * Default constructor.
     */
    public AVLTree() {
        this.creator = this;
    }

    /**
     * Constructor with external Node creator.
     */
    public AVLTree(INodeCreator<T> creator) {
        super(creator);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Node<T> addValue(T id) {
        Node<T> nodeToReturn = super.addValue(id);
        AVLNode<T> nodeAdded = (AVLNode<T>) nodeToReturn;

        while (nodeAdded!=null) {
            nodeAdded.updateHeight();
            balanceAfterInsert(nodeAdded);
            nodeAdded = (AVLNode<T>) nodeAdded.parent;
        }

        return nodeToReturn;
    }

    /**
     * Balance the tree according to the AVL post-insert algorithm.
     * 
     * @param node Root of tree to balance.
     */
    private void balanceAfterInsert(AVLNode<T> node) {
        AVLNode<T> grandParent = (AVLNode<T>) node;
        int balanceFactor = grandParent.getBalanceFactor();
        if (balanceFactor>1 || balanceFactor<-1) {
            AVLNode<T> parent = null;
            AVLNode<T> child = null;
            Balance balance = null;
            if (balanceFactor<0) {
                parent = (AVLNode<T>) grandParent.lesser;
                balanceFactor = parent.getBalanceFactor();
                if (balanceFactor<0) {
                    child = (AVLNode<T>) parent.lesser;
                    balance = Balance.LEFT_LEFT;
                } else {
                    child = (AVLNode<T>) parent.greater;
                    balance = Balance.LEFT_RIGHT;
                }
            } else {
                parent = (AVLNode<T>) grandParent.greater;
                balanceFactor = parent.getBalanceFactor();
                if (balanceFactor<0) {
                    child = (AVLNode<T>) parent.lesser;
                    balance = Balance.RIGHT_LEFT;
                } else {
                    child = (AVLNode<T>) parent.greater;
                    balance = Balance.RIGHT_RIGHT;
                }
            }

            if (balance == Balance.LEFT_RIGHT) {
                //Left-Right (Left rotation, right rotation)
                rotateLeft(parent);
                rotateRight(grandParent);
            } else if (balance == Balance.RIGHT_LEFT) {
                //Right-Left (Right rotation, left rotation)
                rotateRight(parent);
                rotateLeft(grandParent);
            } else if (balance == Balance.LEFT_LEFT) {
                //Left-Left (Right rotation)
                rotateRight(grandParent);
            } else {
                //Right-Right (Left rotation)
                rotateLeft(grandParent);
            }

            grandParent.updateHeight(); //New child node
            child.updateHeight(); //New child node
            parent.updateHeight(); //New Parent node
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Node<T> removeValue(T value) {
        //Find node to remove
        Node<T> nodeToRemoved = this.getNode(value);
        if (nodeToRemoved != null) {
            //Find the replacement node
            Node<T> replacementNode = this.getReplacementNode(nodeToRemoved);

            //Find the parent of the replacement node to re-factor the height/balance of the tree
            AVLNode<T> nodeToRefactor = null;
            if (replacementNode!=null) nodeToRefactor = (AVLNode<T>) replacementNode.parent;
            if (nodeToRefactor==null) nodeToRefactor = (AVLNode<T>) nodeToRemoved.parent;
            if (nodeToRefactor!=null && nodeToRefactor.equals(nodeToRemoved)) nodeToRefactor = (AVLNode<T>) replacementNode;

            //Replace the node
            replaceNodeWithNode(nodeToRemoved,replacementNode);

            //Re-balance the tree all the way up the tree
            if (nodeToRefactor!=null) {
                while (nodeToRefactor!=null) {
                    nodeToRefactor.updateHeight();
                    balanceAfterDelete(nodeToRefactor);
                    nodeToRefactor = (AVLNode<T>) nodeToRefactor.parent;
                }
            }
        }
        return nodeToRemoved;
    }

    /**
     * Balance the tree according to the AVL post-delete algorithm.
     * 
     * @param node Root of tree to balance.
     */
    private void balanceAfterDelete(AVLNode<T> node) {
        int balanceFactor = node.getBalanceFactor();
        if (balanceFactor==-2 || balanceFactor==2) {
            if (balanceFactor==-2) {
                AVLNode<T> ll = (AVLNode<T>) node.lesser.lesser;
                int lesser = (ll!=null)?ll.height:0;
                AVLNode<T> lr = (AVLNode<T>) node.lesser.greater;
                int greater = (lr!=null)?lr.height:0;
                if (lesser>=greater) {
                    rotateRight(node);
                    node.updateHeight();
                    if (node.parent!=null) ((AVLNode<T>)node.parent).updateHeight();
                } else {
                    rotateLeft(node.lesser);
                    rotateRight(node);
                    
                    AVLNode<T> p = (AVLNode<T>) node.parent;
                    if (p.lesser!=null) ((AVLNode<T>)p.lesser).updateHeight();
                    if (p.greater!=null) ((AVLNode<T>)p.greater).updateHeight();
                    p.updateHeight();
                }
            } else if (balanceFactor==2) {
                AVLNode<T> rr = (AVLNode<T>) node.greater.greater;
                int greater = (rr!=null)?rr.height:0;
                AVLNode<T> rl = (AVLNode<T>) node.greater.lesser;
                int lesser = (rl!=null)?rl.height:0;
                if (greater>=lesser) {
                    rotateLeft(node);
                    node.updateHeight();
                    if (node.parent!=null) ((AVLNode<T>)node.parent).updateHeight();
                } else {
                    rotateRight(node.greater);
                    rotateLeft(node);

                    AVLNode<T> p = (AVLNode<T>) node.parent;
                    if (p.lesser!=null) ((AVLNode<T>)p.lesser).updateHeight();
                    if (p.greater!=null) ((AVLNode<T>)p.greater).updateHeight();
                    p.updateHeight();
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean validateNode(Node<T> node) {
        boolean bst = super.validateNode(node);
        if (!bst) return false;

        AVLNode<T> avlNode = (AVLNode<T>) node;
        int balanceFactor = avlNode.getBalanceFactor();
        if (balanceFactor>1 || balanceFactor<-1) {
            return false;
        }
        if (avlNode.isLeaf()) {
            if (avlNode.height!=1) return false;
        } else {
            AVLNode<T> avlNodeLesser = (AVLNode<T>) avlNode.lesser;
            int lesserHeight = 1;
            if (avlNodeLesser!=null) lesserHeight = avlNodeLesser.height;

            AVLNode<T> avlNodeGreater = (AVLNode<T>) avlNode.greater;
            int greaterHeight = 1;
            if (avlNodeGreater!=null) greaterHeight = avlNodeGreater.height;

            if (avlNode.height==(lesserHeight+1) || avlNode.height==(greaterHeight+1)) {
                return true;
            } else {
                return false;
            }
        }

        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return AVLTreePrinter.getString(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Node<T> createNewNode(Node<T> parent, T id) {
        return (new AVLNode<T>(parent,id));
    }

    protected static class AVLNode<T extends Comparable<T>> extends Node<T> {

        protected int height = 1;


        /**
         * Constructor for an AVL node
         * 
         * @param parent Parent of the node in the tree, can be NULL.
         * @param value Value of the node in the tree.
         */
        protected AVLNode(Node<T> parent, T value) {
            super(parent,value);
        }

        /**
         * Determines is this node is a leaf (has no children).
         * 
         * @return True if this node is a leaf.
         */
        protected boolean isLeaf() {
            return ((lesser == null) && (greater == null));
        }

        /**
         * Updates the height of this node based on it's children.
         */
        protected void updateHeight() {
            int lesserHeight = 0;
            int greaterHeight = 0;
            if (lesser != null) {
                AVLNode<T> lesserAVLNode = (AVLNode<T>) lesser;
                lesserHeight = lesserAVLNode.height;
            }
            if (greater != null) {
                AVLNode<T> greaterAVLNode = (AVLNode<T>) greater;
                greaterHeight = greaterAVLNode.height;
            }
            
            if (lesserHeight>greaterHeight) {
                height = lesserHeight+1;
            } else {
                height = greaterHeight+1;
            }
        }

        /**
         * Get the balance factor for this node.
         * 
         * @return An integer representing the balance factor for this node. It will be 
         * negative if the lesser branch is longer than the greater branch.
         */
        protected int getBalanceFactor() {
            int lesserHeight = 0;
            int greaterHeight = 0;
            if (lesser != null) {
                AVLNode<T> lesserAVLNode = (AVLNode<T>) lesser;
                lesserHeight = lesserAVLNode.height;
            }
            if (greater != null) {
                AVLNode<T> greaterAVLNode = (AVLNode<T>) greater;
                greaterHeight = greaterAVLNode.height;
            }
            return greaterHeight-lesserHeight;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return "value=" + id + 
                   " height=" + height + 
                   " parent=" + ((parent != null) ? parent.id : "NULL") + 
                   " lesser=" + ((lesser != null) ? lesser.id : "NULL") + 
                   " greater=" + ((greater != null) ? greater.id : "NULL");
        }
    }

    protected static class AVLTreePrinter {

        public static <T extends Comparable<T>> String getString(AVLTree<T> tree) {
            if (tree.root == null) return "Tree has no nodes.";
            return getString((AVLNode<T>)tree.root, "", true);
        }

        public static <T extends Comparable<T>> String getString(AVLNode<T> node) {
            if (node == null) return "Sub-tree has no nodes.";
            return getString(node, "", true);
        }

        private static <T extends Comparable<T>> String getString(AVLNode<T> node, String prefix, boolean isTail) {
            StringBuilder builder = new StringBuilder();

            builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + node.height + ") " + 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((AVLNode<T>)children.get(i), prefix + (isTail ? "    " : "│   "), false));
                }
                if (children.size() >= 1) {
                    builder.append(getString((AVLNode<T>)children.get(children.size() - 1), prefix + (isTail ? "    " : "│   "), true));
                }
            }

            return builder.toString();
        }
    }
}
 

 BTree 2-3树,分裂和合并部分还是比较简单的

 

import java.util.Arrays;
import java.util.Comparator;


/**
 * B-tree is a tree data structure that keeps data sorted and allows searches,
 * sequential access, insertions, and deletions in logarithmic time. The B-tree
 * is a generalization of a binary search tree in that a node can have more than
 * two children. Unlike self-balancing binary search trees, the B-tree is
 * optimized for systems that read and write large blocks of data. It is
 * commonly used in databases and file-systems.
 * 
 * http://en.wikipedia.org/wiki/B-tree
 * 
 * @author Justin Wetherell <phishman3579@gmail.com>
 */
public class BTree<T extends Comparable<T>> {

    // Default to 2-3 Tree
    private int minKeySize = 1;
    private int minChildrenSize = minKeySize + 1; //2
    private int maxKeySize = 2 * minKeySize; //2
    private int maxChildrenSize = maxKeySize + 1; //3
    
    private Node<T> root = null;
    private int size = 0;


    /**
     * Constructor for B-Tree which defaults to a 2-3 B-Tree.
     */
    public BTree() { }

    /**
     * Constructor for B-Tree of ordered parameter.
     * 
     * @param order of the B-Tree.
     */
    public BTree(int order) {
        this.minKeySize = order;
        this.minChildrenSize = minKeySize + 1;
        this.maxKeySize = 2 * minKeySize;
        this.maxChildrenSize = maxKeySize + 1;
    }

    /**
     * Add value to the tree. Tree can NOT contain multiple equal values.
     * 
     * @param value T to add to the tree.
     * @return True if successfully added to tree.
     */
    public void add(T value) {
        if (root == null) {
            root = new Node<T>(null, maxKeySize, maxChildrenSize);
            root.addKey(value);
        } else {
	        Node<T> node = root;
	        while (node != null) {
	            if (node.numberOfChildren() == 0) {
	                node.addKey(value);
	                if (node.numberOfKeys() <= maxKeySize) {
	                    // A-OK
	                    break;
	                } else {
	                    // Need to split up
	                    split(node);
	                    break;
	                }
	            } else {
	                // navigate
	                T lesser = node.getKey(0);
	                if (value.compareTo(lesser) < 0) {
	                    node = node.getChild(0);
	                    continue;
	                }
	
	                int size = node.numberOfKeys();
	                int last = size - 1;
	                T greater = node.getKey(last);
	                if (value.compareTo(greater) > 0) {
	                    node = node.getChild(size);
	                    continue;
	                }
	
	                for (int i = 1; i < node.numberOfKeys(); i++) {
	                    T prev = node.getKey(i - 1);
	                    T next = node.getKey(i);
	                    if (value.compareTo(prev) > 0 && value.compareTo(next) < 0) {
	                        node = node.getChild(i);
	                        break;
	                    }
	                }
	            }
	        }
        }

        size++;
    }

    /**
     * The node's key size is greater than maxKeySize, split down the middle. 
     * 
     * @param node to split.
     */
    private void split(Node<T> node) {
        int size = node.numberOfKeys();
        int medianIndex = size / 2;
        T medianValue = node.getKey(medianIndex);

        Node<T> left = new Node<T>(null, maxKeySize, maxChildrenSize);
        for (int i=0; i<medianIndex; i++) {
            left.addKey(node.getKey(i));
        }
        if (node.numberOfChildren()>0) {
            for (int j=0; j<=medianIndex; j++) {
                Node<T> c = node.getChild(j);
                left.addChild(c);
            }
        }

        Node<T> right = new Node<T>(null, maxKeySize, maxChildrenSize);
        for (int i = medianIndex+1; i < size; i++) {
            right.addKey(node.getKey(i));
        }
        if (node.numberOfChildren()>0) {
            for (int j=medianIndex+1; j<node.numberOfChildren(); j++) {
                Node<T> c = node.getChild(j);
                right.addChild(c);
            }
        }

        if (node.parent == null) {
            // new root, height of tree is increased
            Node<T> newRoot = new Node<T>(null, maxKeySize, maxChildrenSize);
            newRoot.addKey(medianValue);
            node.parent = newRoot;
            root = newRoot;
            node = root;
            node.addChild(left);
            node.addChild(right);
        } else {
            // Move the median value up to the parent
            Node<T> parent = node.parent;
            parent.addKey(medianValue);
            parent.removeChild(node);
            parent.addChild(left);
            parent.addChild(right);

            if (parent.numberOfKeys() > maxKeySize) split(parent);
        }
    }

    /**
     * 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) {
        Node<T> node = getNode(value);
        return (node != null);
    }

    /**
     * Get the node with value.
     * 
     * @param value to find in the tree.
     * @return Node<T> with value.
     */
    private Node<T> getNode(T value) {
        Node<T> node = root;
        while (node != null) {
            T lesser = node.getKey(0);
            if (value.compareTo(lesser) < 0) {
                if (node.numberOfChildren() > 0) node = node.getChild(0);
                else node = null;
                continue;
            }

            int size = node.numberOfKeys();
            int last = size - 1;
            T greater = node.getKey(last);
            if (value.compareTo(greater) > 0) {
                if (node.numberOfChildren() > size) node = node.getChild(size);
                else node = null;
                continue;
            }

            for (int i = 0; i < size; i++) {
                T currentValue = node.getKey(i);
                if (currentValue.compareTo(value) == 0) {
                    return node;
                }

                int next = i + 1;
                if (next <= last) {
                    T nextValue = node.getKey(next);
                    if (currentValue.compareTo(value) < 0 && nextValue.compareTo(value) > 0) {
                        if (next < node.numberOfChildren()) {
                            node = node.getChild(next);
                            break;
                        } else {
                            return null;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Remove the value from the tree.
     * 
     * @param value T to remove from the tree.
     * @return True if value was removed from the tree.
     */
    public boolean remove(T value) {
        Node<T> node = this.getNode(value);
        if (node == null) return false;

        int index = node.indexOf(value);
        node.removeKey(value);
        if (node.numberOfChildren()==0) {
        	//leaf node
        	if (node.parent!=null && node.numberOfKeys() < minKeySize) {
        		this.combined(node);
        	} else if (node.parent==null && node.numberOfKeys()==0) {
        		//Removing root node with no keys or children
        		root = null;
        	}
        } else {
        	//internal node
        	Node<T> lesser = node.getChild(index);
        	Node<T> greatest = this.getGreatestNode(lesser);
        	T replaceValue = this.removeGreatestValue(greatest);
        	node.addKey(replaceValue);
        	if (greatest.parent!=null && greatest.numberOfKeys() < minKeySize) {
        		this.combined(greatest);
        	}
        	if (greatest.numberOfChildren() > maxChildrenSize) {
        		this.split(greatest);
        	}
        }
        
        size--;

        return true;
    }

    /**
     * Remove greatest valued key from node.
     * 
     * @param node to remove greatest value from.
     * @return value removed;
     */
    private T removeGreatestValue(Node<T> node) {
    	T value = null;
    	if (node.numberOfKeys()>0) {
    		value = node.removeKey(node.numberOfKeys()-1);
    	}
    	return value;
    }

    /**
     * Get the greatest valued child from node.
     * 
     * @param node child with the greatest value.
     * @return Node<T> child with greatest value.
     */
    private Node<T> getGreatestNode(Node<T> node) {
    	while (node.numberOfChildren()>0) {
    	    node = node.getChild(node.numberOfChildren()-1);
    	}
    	return node;
    }

    /**
     * Combined children keys with parent when size is less than minKeySize.
     * 
     * @param node with children to combined.
     * @return True if combined successfully.
     */
    private boolean combined(Node<T> node) {
        Node<T> parent = node.parent;
        int index = parent.indexOf(node);
        int indexOfLeftNeighbor = index - 1;
        int indexOfRightNeighbor = index + 1;

        Node<T> rightNeighbor = null;
        int rightNeighborSize = -minChildrenSize;
        if (indexOfRightNeighbor < parent.numberOfChildren()) {
            rightNeighbor = parent.getChild(indexOfRightNeighbor);
            rightNeighborSize = rightNeighbor.numberOfKeys();
        }

        // Try to borrow neighbor
        if (rightNeighbor != null && rightNeighborSize > minKeySize) {
            // Try to borrow from right neighbor
            T removeValue = rightNeighbor.getKey(0);
            int prev = getIndexOfPreviousValue(parent, removeValue);
            T parentValue = parent.removeKey(prev);
            T neighborValue = rightNeighbor.removeKey(0);
            node.addKey(parentValue);
            parent.addKey(neighborValue);
            if (rightNeighbor.numberOfChildren()>0) {
                node.addChild(rightNeighbor.removeChild(0));
            }
        } else {
            Node<T> leftNeighbor = null;
            int leftNeighborSize = -minChildrenSize;
            if (indexOfLeftNeighbor >= 0) {
                leftNeighbor = parent.getChild(indexOfLeftNeighbor);
                leftNeighborSize = leftNeighbor.numberOfKeys();
            }

        	if (leftNeighbor != null && leftNeighborSize > minKeySize) {

	            // Try to borrow from left neighbor
	            T removeValue = leftNeighbor.getKey(leftNeighbor.numberOfKeys() - 1);
	            int prev = getIndexOfNextValue(parent, removeValue);
	            T parentValue = parent.removeKey(prev);
	            T neighborValue = leftNeighbor.removeKey(leftNeighbor.numberOfKeys() - 1);
	            node.addKey(parentValue);
	            parent.addKey(neighborValue);
	            if (leftNeighbor.numberOfChildren()>0) {
	                node.addChild(leftNeighbor.removeChild(leftNeighbor.numberOfChildren()-1));
	            }
	        } else if (rightNeighbor != null && parent.numberOfKeys() > 0) {
	            // Can't borrow from neighbors, try to combined with right neighbor
	            T removeValue = rightNeighbor.getKey(0);
	            int prev = getIndexOfPreviousValue(parent, removeValue);
	            T parentValue = parent.removeKey(prev);
	            parent.removeChild(rightNeighbor);
	            node.addKey(parentValue);
	            for (int i=0; i<rightNeighbor.keysSize; i++) {
	                T v = rightNeighbor.getKey(i);
	                node.addKey(v);
	            }
	            for (int i=0; i<rightNeighbor.childrenSize; i++) {
	                Node<T> c = rightNeighbor.getChild(i);
	            	node.addChild(c);
	            }
	
	            if (parent.parent != null && parent.numberOfKeys() < minKeySize) {
	            	// removing key made parent too small, combined up tree
	                this.combined(parent);
	            } else if (parent.numberOfKeys() == 0) {
	                // parent no longer has keys, make this node the new root
	            	// which decreases the height of the tree
	                node.parent = null;
	                root = node;
	            }
	        } else if (leftNeighbor != null && parent.numberOfKeys() > 0) {
	            // Can't borrow from neighbors, try to combined with left neighbor
	            T removeValue = leftNeighbor.getKey(leftNeighbor.numberOfKeys() - 1);
	            int prev = getIndexOfNextValue(parent, removeValue);
	            T parentValue = parent.removeKey(prev);
	            parent.removeChild(leftNeighbor);
	            node.addKey(parentValue);
                for (int i=0; i<leftNeighbor.keysSize; i++) {
                    T v = leftNeighbor.getKey(i);
                    node.addKey(v);
                }
                for (int i=0; i<leftNeighbor.childrenSize; i++) {
                    Node<T> c = leftNeighbor.getChild(i);
                    node.addChild(c);
                }
	
	            if (parent.parent != null && parent.numberOfKeys() < minKeySize) {
	            	// removing key made parent too small, combined up tree
	            	this.combined(parent);
	            } else if (parent.numberOfKeys() == 0) {
	                // parent no longer has keys, make this node the new root
	            	// which decreases the height of the tree
	                node.parent = null;
	                root = node;
	            }
	        }
        }

        return true;
    }

    /**
     * Get the index of previous key in node.
     * 
     * @param node to find the previous key in.
     * @param value to find a previous value for.
     * @return index of previous key or -1 if not found.
     */
    private int getIndexOfPreviousValue(Node<T> node, T value) {
        for (int i = 1; i < node.numberOfKeys(); i++) {
            T t = node.getKey(i);
            if (t.compareTo(value) >= 0) return i - 1;
        }
        return node.numberOfKeys() - 1;
    }

    /**
     * Get the index of next key in node.
     * 
     * @param node to find the next key in.
     * @param value to find a next value for.
     * @return index of next key or -1 if not found.
     */
    private int getIndexOfNextValue(Node<T> node, T value) {
        for (int i = 0; i < node.numberOfKeys(); i++) {
            T t = node.getKey(i);
            if (t.compareTo(value) >= 0) return i;
        }
        return node.numberOfKeys() - 1;
    }

    /**
     * Get number of nodes in the tree.
     * 
     * @return Number of nodes in the tree.
     */
    public int size() {
        return size;
    }

    /**
     * Validate the tree for all B-Tree invariants.
     * 
     * @return True if tree is valid.
     */
    public boolean validate() {
        if (root == null) return true;
        return validateNode(root);
    }

    /**
     * Validate the node according to the B-Tree invariants.
     * 
     * @param node to validate.
     * @return True if valid.
     */
    private boolean validateNode(Node<T> node) {
        int keySize = node.numberOfKeys();
        if (keySize > 1) {
            // Make sure the keys are sorted
            for (int i = 1; i < keySize; i++) {
                T p = node.getKey(i - 1);
                T n = node.getKey(i);
                if (p.compareTo(n) > 0) return false;
            }
        }
        int childrenSize = node.numberOfChildren();
        if (node.parent == null) {
        	//root
        	if (keySize > maxKeySize) {
        		// check max key size. root does not have a min key size
                return false;
            } else if (childrenSize==0) {
                // if root, no children, and keys are valid
                return true;
            } else if (childrenSize < 2) {
                // root should have zero or at least two children
                return false;
            } else if (childrenSize > maxChildrenSize) {
                return false;
            }
        } else {
        	//non-root
            if (keySize < minKeySize) {
                return false;
            } else if (keySize > maxKeySize) {
                return false;
            } else if (childrenSize==0) {
                return true;
            } else if (keySize != (childrenSize - 1)) {
                // If there are chilren, there should be one more child then keys
                return false;
            } else if (childrenSize < minChildrenSize) {
                return false;
            } else if (childrenSize > maxChildrenSize) {
                return false;
            }
        }

        Node<T> first = node.getChild(0);
        // The first child's last key should be less than the node's first key
        if (first.getKey(first.numberOfKeys() - 1).compareTo(node.getKey(0)) > 0) return false;

        Node<T> last = node.getChild(node.numberOfChildren() - 1);
        // The last child's first key should be greater than the node's last key
        if (last.getKey(0).compareTo(node.getKey(node.numberOfKeys() - 1)) < 0) return false;

        // Check that each node's first and last key holds it's invariance
        for (int i = 1; i < node.numberOfKeys(); i++) {
            T p = node.getKey(i - 1);
            T n = node.getKey(i);
            Node<T> c = node.getChild(i);
            if (p.compareTo(c.getKey(0)) > 0) return false;
            if (n.compareTo(c.getKey(c.numberOfKeys() - 1)) < 0) return false;
        }

        for (int i=0; i<node.childrenSize; i++) {
            Node<T> c = node.getChild(i);
            boolean valid = this.validateNode(c);
            if (!valid) return false;
        }
        
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return TreePrinter.getString(this);
    }

    private static class Node<T extends Comparable<T>> {

        private T[] keys = null;
        private int keysSize = 0;
        private Node<T>[] children = null;
        private int childrenSize = 0;
        private Comparator<Node<T>> comparator = new Comparator<Node<T>>() {
            @Override
            public int compare(Node<T> arg0, Node<T> arg1) {
                return arg0.getKey(0).compareTo(arg1.getKey(0));
            }
        };

        protected Node<T> parent = null;


        @SuppressWarnings("unchecked")
        private Node(Node<T> parent, int maxKeySize, int maxChildrenSize) {
            this.parent = parent;
            this.keys = (T[]) new Comparable[maxKeySize+1];
            this.keysSize = 0;
            this.children = new Node[maxChildrenSize+1];
            this.childrenSize = 0;
        }

        private T getKey(int index) {
            return keys[index];
        }
        private int indexOf(T value) {
            for (int i=0; i<keysSize; i++) {
                if (keys[i].equals(value)) return i;
            }
            return -1;
        }
        private void addKey(T value) {
            keys[keysSize++] = value;
            Arrays.sort(keys,0,keysSize);
        }
        private boolean removeKey(T value) {
            boolean found = false;
            if (keysSize==0) return found;
            for (int i=0; i<keysSize; i++) {
                if (keys[i].equals(value)) {
                    found = true;
                } else if (found) {
                    //shift the rest of the keys down
                    keys[i-1] = keys[i];
                }
            }
            if (found) {
                keysSize--;
                keys[keysSize] = null;
            }
            return found;
        }
        private T removeKey(int index) {
            if (index>=keysSize) return null;
            T value = keys[index];
            keys[index] = null;
            for (int i=index+1; i<keysSize; i++) {
                //shift the rest of the keys down
                keys[i-1] = keys[i];
            }
            keysSize--;
            keys[keysSize] = null;
            return value;
        }
        private int numberOfKeys() {
            return keysSize;
        }

        private Node<T> getChild(int index) {
            if (index>=childrenSize) return null;
            return children[index];
        }
        private int indexOf(Node<T> child) {
            for (int i=0; i<childrenSize; i++) {
                if (children[i].equals(child)) return i;
            }
            return -1;
        }
        private boolean addChild(Node<T> child) {
            child.parent = this;
            children[childrenSize++] = child;
            Arrays.sort(children,0,childrenSize,comparator);
            return true;
        }
        private boolean removeChild(Node<T> child) {
            boolean found = false;
            if (childrenSize==0) return found;
            for (int i=0; i<childrenSize; i++) {
                if (children[i].equals(child)) {
                    found = true;
                } else if (found) {
                    //shift the rest of the keys down
                    children[i-1] = children[i];
                }
            }
            if (found) {
                childrenSize--;
                children[childrenSize] = null;
            }
            return found;
        }
        private Node<T> removeChild(int index) {
            if (index>=childrenSize) return null;
            Node<T> value = children[index];
            children[index] = null;
            for (int i=index+1; i<childrenSize; i++) {
                //shift the rest of the keys down
                children[i-1] = children[i];
            }
            childrenSize--;
            children[childrenSize] = null;
            return value;
        }
        private int numberOfChildren() {
            return childrenSize;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();

            builder.append("keys=[");
            for (int i = 0; i < numberOfKeys(); i++) {
                T value = getKey(i);
                builder.append(value);
                if (i < numberOfKeys() - 1) builder.append(", ");
            }
            builder.append("]\n");

            if (parent != null) {
                builder.append("parent=[");
                for (int i = 0; i < parent.numberOfKeys(); i++) {
                    T value = parent.getKey(i);
                    builder.append(value);
                    if (i < parent.numberOfKeys() - 1) builder.append(", ");
                }
                builder.append("]\n");
            }

            if (children != null) {
                builder.append("children=").append(numberOfChildren()).append("\n");
            }

            return builder.toString();
        }
    }

    private static class TreePrinter {

        public static <T extends Comparable<T>> String getString(BTree<T> tree) {
            if (tree.root == null) return "Tree has no nodes.";
            return getString(tree.root, "", true);
        }

        private static <T extends Comparable<T>> String getString(Node<T> node, String prefix, boolean isTail) {
            StringBuilder builder = new StringBuilder();

            builder.append(prefix).append((isTail ? "└── " : "├── "));
            for (int i = 0; i < node.numberOfKeys(); i++) {
                T value = node.getKey(i);
                builder.append(value);
                if (i < node.numberOfKeys() - 1) builder.append(", ");
            }
            builder.append("\n");

            if (node.children != null) {
                for (int i = 0; i < node.numberOfChildren() - 1; i++) {
                    Node<T> obj = node.getChild(i);
                    builder.append(getString(obj, prefix + (isTail ? "    " : "│   "), false));
                }
                if (node.numberOfChildren() >= 1) {
                    Node<T> obj = node.getChild(node.numberOfChildren() - 1);
                    builder.append(getString(obj, prefix + (isTail ? "    " : "│   "), true));
                }
            }

            return builder.toString();
        }
    }
}

 

二叉堆,最简单的树结构实现了

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * A binary heap is a heap data structure created using a binary tree. It can be
 * seen as a binary tree with two additional constraints: 1) The shape property:
 * the tree is a complete binary tree; that is, all levels of the tree, except
 * possibly the last one (deepest) are fully filled, and, if the last level of
 * the tree is not complete, the nodes of that level are filled from left to
 * right. 2) The heap property: each node is right than or equal to each of its
 * children according to a comparison predicate defined for the data structure.
 * 
 * http://en.wikipedia.org/wiki/Binary_heap
 * 
 * @author Justin Wetherell <phishman3579@gmail.com>
 */
public abstract class BinaryHeap<T extends Comparable<T>> {

    public enum HeapType { Tree, Array };
    public enum Type { MIN, MAX };

    /**
     * Number of nodes in the heap.
     * 
     * @return Number of nodes in the heap.
     */
    public abstract int size();

    /**
     * Add value to the heap.
     * 
     * @param value to add to the heap.
     */
    public abstract void add(T value);

    /**
     * Does the value exist in the heap. Warning
     * this is a O(n) operation.
     * 
     * @param value to locate in the heap.
     * @return True if the value is in heap.
     */
    public abstract boolean contains(T value);

    /**
     * Get the heap in array form.
     * 
     * @return array representing the heap.
     */
    public abstract T[] getHeap();

    /**
     * Get the value of the head node from the heap.
     * 
     * @return value of the head node.
     */
    public abstract T getHeadValue();

    /**
     * Remove the head node from the heap.
     * 
     * @return value of the head node.
     */
    public abstract T removeHead();

    /**
     * Validate the heap according to the invariants.
     * 
     * @return True if the heap is valid.
     */
    public abstract boolean validate();

    public static <T extends Comparable<T>> BinaryHeap<T> createHeap(HeapType type) {
        switch (type) {
            case Array:
                return new BinaryHeapArray<T>();
            default:
                return new BinaryHeapTree<T>();
        }
    }


    /**
     * A binary heap using an array to hold the nodes.
     * 
     * @author Justin Wetherell <phishman3579@gmail.com>
     */
    public static class BinaryHeapArray<T extends Comparable<T>> extends BinaryHeap<T> {

        private static final int MINIMUM_SIZE = 10;

        private Type type = Type.MIN;      
        private int size = 0;
        @SuppressWarnings("unchecked")
        private T[] array = (T[]) new Comparable[MINIMUM_SIZE];


        /**
         * Get the parent index of this index, will return Integer.MIN_VALUE if no parent 
         * is possible.
         * 
         * @param index of the node to find a parent for.
         * @return index of parent node or Integer.MIN_VALUE if no parent.
         */
        private static final int getParentIndex(int index) {
            if (index>0) return (int) Math.floor((index-1)/2);
            else return Integer.MIN_VALUE;
        }

        /**
         * Get the left child index of this index.
         * 
         * @param index of the node to find a left child for.
         * @return index of left child node.
         */
        private static final int getLeftIndex(int index) {
            return 2*index+1;
        }

        /**
         * Get the right child index of this index.
         * 
         * @param index of the node to find a right child for.
         * @return index of right child node.
         */
        private static final int getRightIndex(int index) {
            return 2*index+2;
        }
        
        /**
         * Constructor for heap, defaults to a min-heap.
         */
        public BinaryHeapArray() {
            size = 0;
        }

        /**
         * Constructor for heap.
         * 
         * @param type Heap type.
         */
        public BinaryHeapArray(Type type) {
            this();
            this.type = type;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public int size() {
            return size;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public void add(T value) {
            if (size>=array.length) {
                array = Arrays.copyOf(array, ((size*3)/2)+1);
            }
            array[size] = value;

            heapUp(size++);
        }

        protected void heapUp(int nodeIndex) {
            T value = this.array[nodeIndex];
            while (nodeIndex>=0) {
                int parentIndex = getParentIndex(nodeIndex);
                if (parentIndex<0) break;
                T parent = this.array[parentIndex];

                if ( (type == Type.MIN && parent != null && value.compareTo(parent) < 0) || 
                     (type == Type.MAX && parent != null && value.compareTo(parent) > 0)
                ){
                    // Node is less than parent, switch node with parent
                    this.array[parentIndex] = value;
                    this.array[nodeIndex] = parent;
                } else {
                    nodeIndex = parentIndex;
                }
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean contains(T value) {
            if (array.length==0) return false;
            for (int i=0; i<size; i++) {
                T node = array[i];
                if (node.equals(value)) return true;
            }
            return false;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean validate() {
            if (array.length==0) return true;
            return validateNode(0);
        }

        /**
         * Validate the node for the heap invariants.
         * 
         * @param node to validate for.
         * @return True if node is valid.
         */
        private boolean validateNode(int index) {
            T value = this.array[index];
            int leftIndex = getLeftIndex(index);
            int rightIndex = getRightIndex(index);

            //We shouldn't ever have a right node without a left in a heap
            if (rightIndex!=Integer.MIN_VALUE && leftIndex==Integer.MIN_VALUE) return false;

            if (leftIndex!=Integer.MIN_VALUE && leftIndex<size) {
                T left = this.array[leftIndex];
                if ((type == Type.MIN && value.compareTo(left) < 0) || (type == Type.MAX && value.compareTo(left) > 0)) {
                    return validateNode(leftIndex);
                } else {
                    return false;
                }
            }
            if (rightIndex!=Integer.MIN_VALUE && rightIndex<size) {
                T right = this.array[rightIndex];
                if ((type == Type.MIN && value.compareTo(right) < 0) || (type == Type.MAX && value.compareTo(right) > 0)) {
                    return validateNode(rightIndex);
                } else {
                    return false;
                }
            }
            
            return true;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        @SuppressWarnings("unchecked")
        public T[] getHeap() {
            T[] nodes = (T[]) new Comparable[size];
            if (array.length==0) return nodes;

            for (int i=0; i<size; i++) {
                T node = this.array[i];
                nodes[i] = node;
            }
            return nodes;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public T getHeadValue() {
            if (array.length==0) return null;
            return array[0];
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public T removeHead() {
            T result = null;
            if (array.length==0) return result;

            //Get the root element in the array
            result = array[0];
            
            //Save the last element of the array and then null out the last element's index
            int lastIndex = --size;
            T lastNode = array[lastIndex];
            array[size] = null;

            //No more elements in the heap
            if (size<=0) {
                return result;
            }

            //Put the last element in the root's spot
            array[0] = lastNode;

            if (size>=MINIMUM_SIZE && size<array.length/2) {
                array = Arrays.copyOf(array, size);
            }

            //Heap down from the root
            heapDown(0);
            
            return result;
        }

        protected void heapDown(int index) {
            T value = this.array[index];
            int leftIndex = getLeftIndex(index);
            int rightIndex = getRightIndex(index);
            T left = (leftIndex!=Integer.MIN_VALUE && leftIndex<this.size)?this.array[leftIndex]:null;
            T right = (rightIndex!=Integer.MIN_VALUE && rightIndex<this.size)?this.array[rightIndex]:null;

            if (left == null && right == null) {
                // Nothing to do here
                return;
            }

            T nodeToMove = null;
            int nodeToMoveIndex = -1;
            if ( (type == Type.MIN && left != null && right != null && value.compareTo(left) > 0 && value.compareTo(right) > 0) || 
                 (type == Type.MAX && left != null && right != null && value.compareTo(left) < 0 && value.compareTo(right) < 0)
            ) {
                // Both children are greater/lesser than node
                if ((type == Type.MIN && right.compareTo(left) < 0) || 
                    (type == Type.MAX && right.compareTo(left) > 0)
                ) {
                    // Right is greater/lesser than left
                    nodeToMove = right;
                    nodeToMoveIndex = rightIndex;
                } else if ( (type == Type.MIN && left.compareTo(right) < 0) || 
                            (type == Type.MAX && left.compareTo(right) > 0)
                ){
                    // Left is greater/lesser than right
                    nodeToMove = left;
                    nodeToMoveIndex = leftIndex;
                } else {
                    // Both children are equal, use right
                    nodeToMove = right;
                    nodeToMoveIndex = rightIndex;
                }
            } else if ( (type == Type.MIN && right != null && value.compareTo(right) > 0) || 
                        (type == Type.MAX && right != null && value.compareTo(right) < 0)
            ) {
                // Right is greater/lesser than node
                nodeToMove = right;
                nodeToMoveIndex = rightIndex;
            } else if ( (type == Type.MIN && left != null && value.compareTo(left) > 0) || 
                        (type == Type.MAX && left != null && value.compareTo(left) < 0)
            ) {
                // Left is greater/lesser than node
                nodeToMove = left;
                nodeToMoveIndex = leftIndex;
            }
            // No node to move, stop recursion
            if (nodeToMove == null) return;

            // Re-factor heap sub-tree
            this.array[nodeToMoveIndex] = value;
            this.array[index] = nodeToMove;

            heapDown(nodeToMoveIndex);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return HeapPrinter.getString(this);
        }

        protected static class HeapPrinter {

            public static <T extends Comparable<T>> String getString(BinaryHeapArray<T> tree) {
                if (tree.array.length==0) return "Tree has no nodes.";

                T root = tree.array[0];
                if (root == null) return "Tree has no nodes.";
                return getString(tree, 0, "", true);
            }

            private static <T extends Comparable<T>> String getString(BinaryHeapArray<T> tree, int index, String prefix, boolean isTail) {
                StringBuilder builder = new StringBuilder();

                T value = tree.array[index];
                builder.append(prefix + (isTail ? "└── " : "├── ") + value + "\n");
                List<Integer> children = null;
                int leftIndex = getLeftIndex(index);
                int rightIndex = getRightIndex(index);
                if (leftIndex != Integer.MIN_VALUE || rightIndex != Integer.MIN_VALUE) {
                    children = new ArrayList<Integer>(2);
                    if (leftIndex != Integer.MIN_VALUE && leftIndex<tree.size) {
                        children.add(leftIndex);
                    }
                    if (rightIndex != Integer.MIN_VALUE && rightIndex<tree.size) {
                        children.add(rightIndex);
                    }
                }
                if (children != null) {
                    for (int i = 0; i < children.size() - 1; i++) {
                        builder.append(getString(tree, children.get(i), prefix + (isTail ? "    " : "│   "), false));
                    }
                    if (children.size() >= 1) {
                        builder.append(getString(tree, children.get(children.size() - 1), prefix + (isTail ? "    " : "│   "), true));
                    }
                }

                return builder.toString();
            }
        }
    }

    public static class BinaryHeapTree<T extends Comparable<T>> extends BinaryHeap<T> {

        private Type type = Type.MIN;      
        private int size = 0;
        private Node<T> root = null;        


        /**
         * Constructor for heap, defaults to a min-heap.
         */
        public BinaryHeapTree() {
            root = null;
            size = 0;
        }

        /**
         * Constructor for heap.
         * 
         * @param type Heap type.
         */
        public BinaryHeapTree(Type type) {
            this();
            this.type = type;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public int size() {
            return size;
        }

        /**
         * Get the navigation directions through the tree to the index.
         * 
         * @param index of the Node to get directions for.
         * @return Integer array representing the directions to the index.
         */
        private int[] getDirections(int index) {
            int directionsSize = (int) (Math.log10(index + 1) / Math.log10(2)) - 1;
            int[] directions = null;
            if (directionsSize > 0) {
                directions = new int[directionsSize];
                int i = directionsSize - 1;
                while (i >= 0) {
                    index = (index - 1) / 2;
                    directions[i--] = (index > 0 && index % 2 == 0) ? 1 : 0; // 0=left,
                                                                             // 1=right
                }
            }
            return directions;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public void add(T value) {
            add(new Node<T>(null, value));
        }

        private void add(Node<T> newNode) {
            if (root == null) {
                root = newNode;
                size++;
                return;
            }

            Node<T> node = root;
            int[] directions = getDirections(size); // size == index of new node
            if (directions != null && directions.length > 0) {
                for (int d : directions) {
                    if (d == 0) {
                        // Go left
                        node = node.left;
                    } else {
                        // Go right
                        node = node.right;
                    }
                }
            }
            if (node.left == null) {
                node.left = newNode;
            } else {
                node.right = newNode;
            }
            newNode.parent = node;

            size++;

            heapUp(newNode);
        }

        /**
         * Remove the root node.
         */
        private void removeRoot() {
            // Find the last node
            int[] directions = getDirections(size - 1); // Directions to the last node
            Node<T> lastNode = root;
            if (directions != null && directions.length > 0) {
                for (int d : directions) {
                    if (d == 0) {
                        // Go left
                        lastNode = lastNode.left;
                    } else {
                        // Go right
                        lastNode = lastNode.right;
                    }
                }
            }
            Node<T> lastNodeParent = null;
            if (lastNode.right != null) {
                lastNodeParent = lastNode;
                lastNode = lastNode.right;
                lastNodeParent.right = null;
            } else if (lastNode.left != null) {
                lastNodeParent = lastNode;
                lastNode = lastNode.left;
                lastNodeParent.left = null;
            }

            lastNode.left = root.left;
            if (lastNode.left != null) lastNode.left.parent = lastNode;
            lastNode.right = root.right;
            if (lastNode.right != null) lastNode.right.parent = lastNode;
            lastNode.parent = null;

            if (!lastNode.equals(root)) root = lastNode;
            else root = null;

            size--;

            heapDown(lastNode);
        }

        /**
         * Get the node in the startingNode sub-tree which has the value.
         * 
         * @param startingNode node rooted sub-tree to search in.
         * @param value to search for.
         * @return Node<T> which equals value in sub-tree or NULL if not found.
         */
        private Node<T> getNode(Node<T> startingNode, T value) {
            Node<T> result = null;
            if (startingNode != null && startingNode.value.equals(value)) {
                result = startingNode;
            } else if (startingNode != null && !startingNode.value.equals(value)) {
                Node<T> left = startingNode.left;
                if (left != null) {
                    result = getNode(left, value);
                    if (result != null) return result;
                }
                Node<T> right = startingNode.right;
                if (right != null) {
                    result = getNode(right, value);
                    if (result != null) return result;
                }
            }
            return result;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public boolean contains(T value) {
            if (root==null) return false;
            Node<T> node = getNode(root, value);
            return (node!=null);
        }

        /**
         * Heap up the heap from this node.
         * 
         * @param node to heap up.
         */
        protected void heapUp(Node<T> node) {
            while (node != null) {
                Node<T> heapNode = (Node<T>) node;
                Node<T> parent = heapNode.parent;

                if ( (type == Type.MIN && parent != null && node.value.compareTo(parent.value) < 0) || 
                     (type == Type.MAX && parent != null && node.value.compareTo(parent.value) > 0)
                ){
                    // Node is less than parent, switch node with parent
                    Node<T> grandParent = parent.parent;
                    Node<T> parentLeft = parent.left;
                    Node<T> parentRight = parent.right;

                    parent.left = heapNode.left;
                    if (parent.left != null) parent.left.parent = parent;
                    parent.right = heapNode.right;
                    if (parent.right != null) parent.right.parent = parent;

                    if (parentLeft != null && parentLeft.equals(node)) {
                        heapNode.left = parent;
                        heapNode.right = parentRight;
                        if (parentRight != null) parentRight.parent = heapNode;
                    } else {
                        heapNode.right = parent;
                        heapNode.left = parentLeft;
                        if (parentLeft != null) parentLeft.parent = heapNode;
                    }
                    parent.parent = heapNode;

                    if (grandParent == null) {
                        // New root.
                        heapNode.parent = null;
                        root = heapNode;
                    } else {
                        Node<T> grandLeft = grandParent.left;
                        if (grandLeft != null && grandLeft.equals(parent)) {
                            grandParent.left = heapNode;
                        } else {
                            grandParent.right = heapNode;
                        }
                        heapNode.parent = grandParent;
                    }
                } else {
                    node = heapNode.parent;
                }
            }
        }
        
        /**
         * Heap down the heap from this node.
         * 
         * @param node to heap down.
         */
        protected void heapDown(Node<T> node) {
            Node<T> heapNode = (Node<T>) node;
            Node<T> left = heapNode.left;
            Node<T> right = heapNode.right;

            if (left == null && right == null) {
                // Nothing to do here
                return;
            }

            Node<T> nodeToMove = null;

            if ( (type == Type.MIN && left != null && right != null && node.value.compareTo(left.value) > 0 && node.value.compareTo(right.value) > 0) || 
                 (type == Type.MAX && left != null && right != null && node.value.compareTo(left.value) < 0 && node.value.compareTo(right.value) < 0)
            ) {
                // Both children are greater/lesser than node
                if ((type == Type.MIN && right.value.compareTo(left.value) < 0) || 
                    (type == Type.MAX && right.value.compareTo(left.value) > 0)
                ) {
                    // Right is greater/lesser than left
                    nodeToMove = right;
                } else if ( (type == Type.MIN && left.value.compareTo(right.value) < 0) || 
                            (type == Type.MAX && left.value.compareTo(right.value) > 0)
                ){
                    // Left is greater/lesser than right
                    nodeToMove = left;
                } else {
                    // Both children are equal, use right
                    nodeToMove = right;
                }
            } else if ( (type == Type.MIN && right != null && node.value.compareTo(right.value) > 0) || 
                        (type == Type.MAX && right != null && node.value.compareTo(right.value) < 0)
            ) {
                // Right is greater than node
                nodeToMove = right;
            } else if ( (type == Type.MIN && left != null && node.value.compareTo(left.value) > 0) || 
                        (type == Type.MAX && left != null && node.value.compareTo(left.value) < 0)
            ) {
                // Left is greater than node
                nodeToMove = left;
            }
            // No node to move, stop recursion
            if (nodeToMove == null) return;

            // Re-factor heap sub-tree
            Node<T> nodeParent = heapNode.parent;
            if (nodeParent == null) {
                // heap down the root
                root = nodeToMove;
                root.parent = null;

                Node<T> nodeToMoveLeft = nodeToMove.left;
                Node<T> nodeToMoveRight = nodeToMove.right;
                if (heapNode.left.equals(nodeToMove)) {
                    nodeToMove.left = heapNode;
                    nodeToMove.right = heapNode.right;
                } else {
                    nodeToMove.left = heapNode.left;
                    nodeToMove.right = heapNode;
                }
                heapNode.parent = nodeToMove;
                heapNode.left = nodeToMoveLeft;
                heapNode.right = nodeToMoveRight;
            } else {
                // heap down a left
                if (nodeParent.left.equals(node)) {
                    nodeParent.left = nodeToMove;
                    nodeToMove.parent = nodeParent;
                } else {
                    nodeParent.right = nodeToMove;
                    nodeToMove.parent = nodeParent;
                }

                Node<T> nodeLeft = heapNode.left;
                Node<T> nodeRight = heapNode.right;
                Node<T> nodeToMoveLeft = nodeToMove.left;
                Node<T> nodeToMoveRight = nodeToMove.right;
                if (heapNode.left.equals(nodeToMove)) {
                    nodeToMove.right = nodeRight;
                    if (nodeRight != null) nodeRight.parent = nodeToMove;

                    nodeToMove.left = heapNode;
                    heapNode.parent = nodeToMove;
                } else {
                    nodeToMove.left = nodeLeft;
                    if (nodeLeft != null) nodeLeft.parent = nodeToMove;

                    nodeToMove.right = heapNode;
                    heapNode.parent = nodeToMove;
                }

                heapNode.left = nodeToMoveLeft;
                if (nodeToMoveLeft != null) nodeToMoveLeft.parent = heapNode;
                heapNode.right = nodeToMoveRight;
                if (nodeToMoveRight != null) nodeToMoveRight.parent = heapNode;
            }

            heapDown(node);
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public boolean validate() {
            if (root==null) return true;
            return validateNode(root);
        }

        /**
         * Validate node for heap invariants.
         * 
         * @param node to validate for.
         * @return True if node is valid.
         */
        private boolean validateNode(Node<T> node) {
            Node<T> left = ((Node<T>)node).left;
            Node<T> right = ((Node<T>)node).right;
            
            //We shouldn't ever have a right node without a left in a heap
            if (right!=null && left==null) return false;

            if (left!=null) {
                if ((type == Type.MIN && node.value.compareTo(left.value) < 0) || (type == Type.MAX && node.value.compareTo(left.value) > 0)) {
                    return validateNode(left);
                } else {
                    return false;
                }
            }
            if (right!=null) {
                if ((type == Type.MIN && node.value.compareTo(right.value) < 0) || (type == Type.MAX && node.value.compareTo(right.value) > 0)) {
                    return validateNode(right);
                } else {
                    return false;
                }
            }
            
            return true;
        }

        /**
         * Populate the node in the array at the index.
         * 
         * @param node to populate.
         * @param index of node in array.
         * @param array where the node lives.
         */
        private void getNodeValue(Node<T> node, int index, T[] array) {
            array[index] = node.value;
            index = (index * 2) + 1;

            Node<T> left = ((Node<T>)node).left;
            if (left != null) getNodeValue(left, index, array);
            Node<T> right = ((Node<T>)node).right;
            if (right != null) getNodeValue(right, index + 1, array);
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        @SuppressWarnings("unchecked")
        public T[] getHeap() {
            T[] nodes = (T[]) new Comparable[size];
            if (root != null) getNodeValue(root, 0, nodes);
            return nodes;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public T getHeadValue() {
            T result = null;
            if (root != null) result = root.value;
            return result;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public T removeHead() {
            T result = null;
            if (root != null) {
                result = root.value;
                removeRoot();
            }
            return result;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return HeapPrinter.getString(this);
        }

        protected static class HeapPrinter {

            public static <T extends Comparable<T>> void print(BinaryHeapTree<T> tree) {
                System.out.println(getString(tree.root, "", true));
            }

            public static <T extends Comparable<T>> String getString(BinaryHeapTree<T> tree) {
                if (tree.root == null) return "Tree has no nodes.";
                return getString(tree.root, "", true);
            }

            private static <T extends Comparable<T>> String getString(Node<T> node, String prefix, boolean isTail) {
                StringBuilder builder = new StringBuilder();

                builder.append(prefix + (isTail ? "└── " : "├── ") + node.value + "\n");
                List<Node<T>> children = null;
                if (node.left != null || node.right != null) {
                    children = new ArrayList<Node<T>>(2);
                    if (node.left != null) children.add(node.left);
                    if (node.right != null) children.add(node.right);
                }
                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();
            }
        }

        private static class Node<T extends Comparable<T>> {

            private T value = null;
            private Node<T> parent = null;
            private Node<T> left = null;
            private Node<T> right = null;


            private Node(Node<T> parent, T value) {
                this.value = value;
                this.parent = parent;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public String toString() {
                return "value=" + value + 
                       " parent=" + ((parent != null) ? parent.value : "NULL") + 
                       " left=" + ((left != null) ? left.value : "NULL") + 
                       " right=" + ((right != null) ? right.value : "NULL");
            }
        }
    }
}

 

后续把学习完的数据结构的其他树结构再贴出来。

1
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics