于是自己稍微改进了一下书中的二叉树的实现代码,让使用时更加简单方便。

2. 实现

java.util.LinkedList; /** * 二叉树 * * @author D.K * @date 2015年10月14日 下午9:10:00 * @Description: TODO */ public class BinaryTree<T> { public static final int ORDER_TYPE_PREORDER = 1; public static final int ORDER_TYPE_INORDER = 2; public static final int ORDER_TYPE_POSTORDER = 3; public static final int ORDER_TYPE_LEVEL = 4; private BinaryTreeNode<T> rootNode; private Cursor<T> cursor; private int size; private int height; public BinaryTree() { } public BinaryTree(T root) { root(root); size = 1; height = 1; } /** * 获取根元素 * * @return */ public T root() { if (isEmpty()) { throw new RuntimeException("该树是空树!"); } return rootNode.data; } /** * 设置树的根元素(如果有,则替换) * * @param root * @return */ public Cursor<T> root(T root) { final BinaryTreeNode<T> newRootNode = new BinaryTreeNode<>(root, null, 1); if (isEmpty()) cursor = new Cursor<>(this); else { newRootNode.left = rootNode.left; newRootNode.right = rootNode.right; } rootNode = newRootNode; cursor.node = rootNode; return cursor; } /** * 将游标指向到根元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2Root() { if (!isEmpty()) { cursor.node = rootNode; return true; } return false; } /** * 将游标指向到当前指向元素的父元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2Parent() { if (cursor.node.parent != null) { cursor.node = cursor.node.parent; return true; } return false; } /** * 将游标指向到当前指向元素的父元素的左侧相邻元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2ParentLeftNeighbor() { return move2Parent() && move2LeftNeighbor(); } /** * 将游标指向到当前指向元素的父元素的右侧相邻元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2ParentRightNeighbor() { return move2Parent() && move2RightNeighbor(); } /** * 将游标指向到当前指向元素的祖父元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2Grandparent() { if (cursor.node.parent != null || cursor.node.parent.parent != null) { cursor.node = cursor.node.parent.parent; return true; } return false; } /** * 将游标指向到当前指向元素的祖父元素的左侧相邻元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2GrandparentLeftNeighbor() { return move2Grandparent() && move2LeftNeighbor(); } /** * 将游标指向到当前指向元素的祖父元素的右侧相邻元素 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2GrandparentRightNeighbor() { return move2Grandparent() && move2RightNeighbor(); } /** * 将游标移动到当前指向元素的左孩子 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2LeftChild() { if (cursor.node.left != null) { cursor.node = cursor.node.left; return true; } return false; } /** * 将游标移动到当前指向元素相邻左侧的元素(可能是兄弟,也可能不是兄弟) * * @return */ public boolean move2LeftNeighbor() { if (cursor.node == rootNode) { return false; } if (cursor.isRightChild()) { // 当前指向元素是其父元素的右孩子,这种情况很简单 if (cursor.node.parent.left != null) { cursor.node = cursor.node.parent.left; return true; } return false; } // 当前指向元素是其父元素的左孩子 // 创建临时移动的cursor final Cursor<T> tempCursor = new Cursor<>(cursor); final int level = tempCursor.level(); while (Cursor.isLeftChild(tempCursor.node.parent)) { tempCursor.node = tempCursor.node.parent; } // 此时tempCursor指向元素的父元素是根元素或右孩子 if (tempCursor.node.parent == rootNode) { return false; } // tempCursor移动到当前元素的祖父元素的左孩子 tempCursor.node = tempCursor.node.parent.parent.left; while (tempCursor.node.right != null && tempCursor.node.right.level != level) { tempCursor.node = tempCursor.node.right; } final boolean result = tempCursor.node.right != null; if (result) { cursor.node = tempCursor.node.right; } return result; } /** * 将游标移动到当前指向元素相邻右侧的元素(可能是兄弟,也可能不是兄弟) * * @return */ public boolean move2RightNeighbor() { if (cursor.node == rootNode) { return false; } if (cursor.isLeftChild()) { // 当前指向元素是其父元素的左孩子,这种情况很简单 if (cursor.node.parent.right != null) { cursor.node = cursor.node.parent.right; return true; } return false; } // 当前指向元素是其父元素的右孩子 // 临时移动的cursor final Cursor<T> tempCursor = new Cursor<>(cursor); final int level = tempCursor.level(); while (Cursor.isRightChild(tempCursor.node.parent)) { tempCursor.node = tempCursor.node.parent; } // 此时tempCursor指向元素的父元素是根元素或右孩子 if (tempCursor.node.parent == rootNode) { return false; } // tempCursor移动到当前元素的祖父元素的右孩子 tempCursor.node = tempCursor.node.parent.parent.right; while (tempCursor.node.left != null && tempCursor.node.left.level != level) { tempCursor.node = tempCursor.node.left; } final boolean result = tempCursor.node.left != null; if (result) { cursor.node = tempCursor.node.left; } return result; } /** * 将游标移动到当前指向元素的右孩子 * * @return true表示移动成功;否则表示移动失败(要移自的位置没有元素)。 */ public boolean move2RightChild() { if (cursor.node.right != null) { cursor.node = cursor.node.right; return true; } return false; } public void foreach(OnForeachListener foreachListener) { foreach(ORDER_TYPE_PREORDER, foreachListener); } public void foreach(int orderType, OnForeachListener foreachListener) { switch (orderType) { case ORDER_TYPE_POSTORDER: postorder(rootNode, foreachListener); break; case ORDER_TYPE_INORDER: inorder(rootNode, foreachListener); break; case ORDER_TYPE_LEVEL: levelorder(foreachListener); break; case ORDER_TYPE_PREORDER: default: preorder(rootNode, foreachListener); break; } } /** * 先根遍历(递归) */ private void preorder(BinaryTreeNode<T> node, OnForeachListener foreachListener) { if (node != null && foreachListener != null) { foreachListener.foreach(node.data); preorder(node.left, foreachListener); preorder(node.right, foreachListener); } } /** * 中根遍历(递归) */ private void inorder(BinaryTreeNode<T> node, OnForeachListener foreachListener) { if (node != null && foreachListener != null) { inorder(node.left, foreachListener); foreachListener.foreach(node.data); inorder(node.right, foreachListener); } } /** * 后根遍历(递归) */ private void postorder(BinaryTreeNode<T> node, OnForeachListener foreachListener) { if (node != null && foreachListener != null) { postorder(node.left, foreachListener); postorder(node.right, foreachListener); foreachListener.foreach(node.data); } } /** * 层次遍历(非递归) */ private void levelorder(OnForeachListener foreachListener) { BinaryTreeNode<T> node = rootNode; LinkedList<BinaryTreeNode<T>> linkedList = new LinkedList<>(); while (node != null && foreachListener != null) { foreachListener.foreach(node.data); if (node.left != null) { linkedList.offer(node.left); } if (node.right != null) { linkedList.offer(node.right); } node = linkedList.poll(); } }
    /**
     * 返回树状图字符串(这里只是为了练习一下,真正的还是以广义表形式输出更妥) 
    */ 
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        BinaryTreeNode<T> node = rootNode;
        LinkedList<BinaryTreeNode<T>> linkedList = new LinkedList<>();
        int lastLevel = -1;
        while (node.level <= height) {
            final int margin = (int) (Math.pow(2, height - node.level) - 1);
            final int space = 2 * margin + 1;
            if (node.level != lastLevel) {
                for (int i = 0; i < margin; i++) {
                    builder.append(" ");
                }
            } else {
                for (int i = 0; i < space; i++) {
                    builder.append(" ");
                }
            }
            builder.append(node.data == null ? " " : node.data);
            lastLevel = node.level;
            if (node.left != null) {
                linkedList.offer(node.left);
            } else {
                linkedList.offer(new BinaryTreeNode<T>(null, node.level + 1));
            }

            if (node.right != null) {
                linkedList.offer(node.right);
            } else {
                linkedList.offer(new BinaryTreeNode<T>(null, node.level + 1));
            }

            if (linkedList.peek() != null && linkedList.peek().level != lastLevel) {
                builder.append("\n");
            }

            node = linkedList.poll();
        }

        return builder.toString();
    }

    /**
     * 
     * 获取树的元素总数
     * 
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 获取树的高度
     * 
     * @return
     */
    public int height() {
        return height;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 获取游标
     * 
     * @return
     */
    public Cursor<T> getCursor() {
        return cursor;
    }

    private static class BinaryTreeNode<T> {

        T data;
        BinaryTreeNode<T> parent;
        BinaryTreeNode<T> left;
        BinaryTreeNode<T> right;
        int level;

        public BinaryTreeNode(T data, int level) {
            super();
            this.data = data;
            this.level = level;
        }

        BinaryTreeNode(T data, BinaryTreeNode<T> parent, int level) {
            this.data = data;
            this.parent = parent;
            this.level = level;
        }
    }

    /**
     * 用node1 替换 node2;
     * 
     * @param node1
     * @param node2
     */
    private void repace(BinaryTreeNode<T> node1, BinaryTreeNode<T> node2) {
        // 修改node1的父亲、左、右孩子
        node1.parent = node2.parent;
        node1.left = node2.left;
        node1.right = node2.right;
        // 修改node2左、右孩子的父亲
        if (node2.left != null) {
            node2.left.parent = node1;
        }
        if (node2.right != null) {
            node2.right.parent = node1;
        }
        // 修改node2父亲的孩子
        if (Cursor.isLeftChild(node2)) {
            node2.parent.left = node1;
        }
        if (Cursor.isRightChild(node2)) {
            node2.parent.right = node1;
        }
        // 修改root
        if (node2 == rootNode) {
            rootNode = node1;
        }
    }

    // ----------------------------------------------------------------//

    /**
     * 指向某结点的游标,用于操作和访问元素。 <b>游标默认会指向最新操作的元素。
     * 
     * @author D.K
     * @date 2015年10月14日 下午9:20:47
     * @Description
     * @param <T>
     */
    public static class Cursor<T> {

        private BinaryTree<T> binaryTree;
        private BinaryTreeNode<T> node;

        public Cursor(Cursor<T> cursor) {
            this.binaryTree = cursor.binaryTree;
            this.node = cursor.node;
        }

        private Cursor(BinaryTree<T> binaryTree) {
            this.binaryTree = binaryTree;
        }

        /**
         * 获取当前指向的元素的值
         * 
         * @return
         */
        public T value() {
            return node.data;
        }

        /**
         * 设置是当前指向元素的值
         * 
         * @param t
         */
        public void value(T t) {
            node.data = t;
        }

        /**
         * 获取当前指向的元素在树中的层次
         * 
         * @return
         */
        public int level() {
            return node.level;
        }

        /**
         * 为当前指向的元素设置左孩子(如果有,则替换)
         * 
         * @param left
         */
        public Cursor<T> leftChild(T left) {
            BinaryTreeNode<T> leftNode = new BinaryTreeNode<T>(left, node.level + 1);
            if (node.left == null) {
                // 当前结点没有左孩子,直接添加
                binaryTree.size++;
                node.left = leftNode;
                leftNode.parent = node;
                binaryTree.height = leftNode.level > binaryTree.height ? leftNode.level : binaryTree.height;
            } else {
                // 当前结点有左孩子,替换
                binaryTree.repace(leftNode, node);
            }
            node = leftNode; // 移动游标
            return this;
        }

        /**
         * 为当前指向的元素设置右孩子(如果有,则替换)
         * 
         * @param right
         */
        public Cursor<T> rightChild(T right) {
            BinaryTreeNode<T> rightNode = new BinaryTreeNode<T>(right, node.level + 1);
            if (node.right == null) {
                // 当前结点没有右孩子,直接添加
                binaryTree.size++;
                node.right = rightNode;
                rightNode.parent = node;
                binaryTree.height = rightNode.level > binaryTree.height ? rightNode.level : binaryTree.height;
            } else {
                // 当前结点有左孩子,替换
                binaryTree.repace(rightNode, node);
            }
            node = rightNode; // 移动游标
            return this;
        }

        /**
         * 为当前指向的元素设置左右孩子
         * 
         * @param left
         * @param right
         * @return
         */
        public Cursor<T> child(T left, T right) {
            leftChild(left);
            binaryTree.move2Parent();
            rightChild(right);
            return this;
        }

        /**
         * 判断当前指向的元素是否为其父元素的左孩子
         * 
         * @return true:为左孩子;false:不为左孩子或当前指向元素为根元素
         */
        public boolean isLeftChild() {
            if (node.parent == null) {
                return false;
            }
            return node.parent.left == node;
        }

        private static boolean isLeftChild(BinaryTreeNode<?> node) {
            if (node.parent == null) {
                return false;
            }
            return node.parent.left == node;
        }

        /**
         * 判断当前指向的元素是否为其父元素的右孩子
         * 
         * @return true:为右孩子;false:不为右孩子或当前指向元素为根元素
         */
        public boolean isRightChild() {
            if (node == binaryTree.rootNode) {
                return false;
            }
            return node.parent.right == node;
        }

        private static boolean isRightChild(BinaryTreeNode<?> node) {
            if (node.parent == null) {
                return false;
            }
            return node.parent.right == node;
        }

    }

    public interface OnForeachListener {
        public void foreach(Object obj);
    }
}
3. 测试

下面进行测试。比如我们要构建如下图所示的树:

二叉树的友好实现

我们可以很容易的做到:

public static void main(String[] args) {
    // 构建一棵树
    BinaryTree<Integer> binaryTree = new BinaryTree<>();
    // cursor在操作完成后,默认会指向最后操作的元素。
    // 如当下面root(T t)操作完成后,Cursor就指向了root。
    Cursor<Integer> cursor = binaryTree.root(1);
    // 下面操作完成后, cursor会指向3这个元素。
    cursor.child(2, 3);
    cursor.child(5, 6);
    cursor.child(9, 0);
    binaryTree.move2ParentLeftNeighbor();
    cursor.leftChild(8);
    binaryTree.move2GrandparentLeftNeighbor();
    cursor.leftChild(4);
    cursor.rightChild(7);
}

我们再通过随机访问遍某个元素、遍历这棵树和调用toString方法,来验证树是否构建地正确:

public static void main(String[] args) {
    // 构建一棵树
    BinaryTree<Integer> binaryTree = new BinaryTree<>();
    // cursor在操作完成后,默认会指向最后操作的元素。
    // 如当下面root(T t)操作完成后,Cursor就指向了root。
    Cursor<Integer> cursor = binaryTree.root(1);
    // 下面操作完成后, cursor会指向3这个元素。
    cursor.child(2, 3);
    cursor.child(5, 6);
    cursor.child(9, 0);
    binaryTree.move2ParentLeftNeighbor();
    cursor.leftChild(8);
    binaryTree.move2GrandparentLeftNeighbor();
    cursor.leftChild(4);
    cursor.rightChild(7);
    // -------------------测试------------------
    // (1) 此时cursor指向的是7这个元素,我们访问它的祖父元素的右邻居的右孩子的左孩子(应该是9)。
    if (binaryTree.move2GrandparentRightNeighbor() && binaryTree.move2RightChild() && binaryTree.move2LeftChild()) {
        System.out.println("7的祖父元素的右邻居的右孩子的左孩子是:" + cursor.value());
    } else {
        System.out.println("不存在");
    }

    // (2) 遍历树
    // 先根遍历
    System.out.print("先根遍历的结果是:");
    binaryTree.foreach(BinaryTree.ORDER_TYPE_PREORDER, new OnForeachListener() {

        @Override
        public void foreach(Object obj) {
            System.out.print(obj);
        }
    });
    // 中根遍历
    System.out.print("\n中根遍历的结果是:");
    binaryTree.foreach(BinaryTree.ORDER_TYPE_INORDER, new OnForeachListener() {

        @Override
        public void foreach(Object obj) {
            System.out.print(obj);
        }
    });
    // 后根遍历
    System.out.print("\n后根遍历的结果是:");
    binaryTree.foreach(BinaryTree.ORDER_TYPE_POSTORDER, new OnForeachListener() {

        @Override
        public void foreach(Object obj) {
            System.out.print(obj);
        }
    });
    System.out.println();
    // toString
    System.out.println(binaryTree);
}

结果如下图:

二叉树的友好实现

4. 总结

    如上给出了二叉树的构建、插入、修改、遍历的操作,初步实现到这里,还有删除、查找等操作以后再补充。

    欢迎批评和指正。

相关文章:

  • 2021-08-26
  • 2021-12-02
  • 2022-02-22
  • 2021-06-07
  • 2022-12-23
  • 2021-08-14
猜你喜欢
  • 2021-12-02
相关资源
相似解决方案