你好,游客 登录 注册 搜索
背景:
阅读新闻

Java中二叉树存储结构实现

[日期:2017-05-17] 来源:Linux社区  作者:Dylansuns [字体: ]

一、二叉树

二叉树指的是每个节点最多只能有两个子树的有序树。通常左边的子树被称为“左子树”(left subtree),右边的子树被称为右子树。

二叉树的每个节点最多只有2棵子树,二叉树的子树次序不能颠倒。

二、顺序存储二叉树的实现

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class ArrayBinTree<T> {

    // 使用数组来记录该树的所有节点
    private Object[] datas;
    private int DEFAULT_DEEP = 8;
    // 保存该树的深度
    private int deep;
    private int arraySize;

    // 以默认的深度创建二叉树
    public ArrayBinTree() {
        this.deep = DEFAULT_DEEP;
        this.arraySize = (int) (Math.pow(2, deep) - 1);
        datas = new Object[arraySize];
    }

    // 以指定深度创建二叉树
    public ArrayBinTree(int deep) {
        this.deep = deep;
        this.arraySize = (int) Math.pow(2, deep) - 1;
        datas = new Object[arraySize];
    }

    // 以指定深度、指定节点创建二叉树
    public ArrayBinTree(int deep, T data) {
        this.deep = deep;
        this.arraySize = (int) Math.pow(2, deep) - 1;
        datas = new Object[arraySize];
        datas[0] = data;
    }

    /**
    * 为指定节点添加子节点
    *
    * @param index 需要添加子节点的父节点的索引
    * @param data  新子节点的数据
    * @param left  是否为左节点
    */
    public void add(int index, T data, boolean left) {
        if (datas[index] == null) {
            throw new RuntimeException(index + "处节点为空,无法添加子节点");
        }
        if (2 * index + 1 >= arraySize) {
            throw new RuntimeException("树底层的数组已满,树越界异常");
        }
        // 添加左子节点
        if (left) {
            datas[2 * index + 1] = data;
        } else {
            datas[2 * index + 2] = data;
        }
    }

    // 判断二叉树是否为空
    public boolean empty() {
        // 根据根元素判断二叉树是否为空
        return datas[0] == null;
    }

    // 返回根节点
    public T root() {
        return (T) datas[0];
    }

    // 返回指定节点(非根结点)的父节点
    public T parent(int index) {
        return (T) datas[(index - 1) / 2];
    }

    // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
    public T left(int index) {
        if (2 * index + 1 >= arraySize) {
            throw new RuntimeException("该节点为叶子节点,无子节点");
        }
        return (T) datas[index * 2 + 1];
    }

    // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
    public T right(int index) {
        if (2 * index + 1 >= arraySize) {
            throw new RuntimeException("该节点为叶子节点,无子节点");
        }
        return (T) datas[index * 2 + 2];
    }

    // 返回该二叉树的深度
    public int deep(int index) {
        return deep;
    }

    // 返回指定节点的位置
    public int pos(T data) {
        // 该循环实际上就是按广度遍历来搜索每个节点
        for (int i = 0; i < arraySize; i++) {
            if (datas[i].equals(data)) {
                return i;
            }

        }
        return -1;
    }

    public String toString() {
        return java.util.Arrays.toString(datas);
    }

}

测试类:

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class ArrayBinTreeTest {

    public static void main(String[] args) {

        ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根");
        binTree.add(0, "第二层右子节点", false);
        binTree.add(2, "第三层右子节点", false);
        binTree.add(6, "第四层右子节点", false);
        System.out.println(binTree);
       
    }

}

程序输出:

[根, null, 第二层右子节点, null, null, null, 第三层右子节点, null, null, null, null, null, null, null, 第四层右子节点]

三、二叉树的二叉链表存储

二叉链表存储的思想是让每个节点都能“记住”它的左、右两个子节点。为每个节点增加left、right两个指针,分别引用该节点的左、右两个子节点。

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class TwoLinkBinTree<E> {

    public static class TreeNode {

        Object data;
        TreeNode left;
        TreeNode right;

        public TreeNode() {

        }

        public TreeNode(Object data) {
            this.data = data;
        }

        public TreeNode(Object data, TreeNode left, TreeNode right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }

    }

    private TreeNode root;

    // 以默认的构造器创建二叉树
    public TwoLinkBinTree() {
        this.root = new TreeNode();
    }

    // 以指定根元素创建二叉树
    public TwoLinkBinTree(E data) {
        this.root = new TreeNode(data);
    }

    /**
    * 为指定节点添加子节点
    *
    * @param parent 需要添加子节点的父节点的索引
    * @param data  新子节点的数据
    * @param isLeft 是否为左节点
    * @return 新增的节点
    */
    public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {

        if (parent == null) {
            throw new RuntimeException(parent + "节点为null, 无法添加子节点");
        }
        if (isLeft && parent.left != null) {
            throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
        }
        if (!isLeft && parent.right != null) {
            throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
        }

        TreeNode newNode = new TreeNode(data);
        if (isLeft) {
            // 让父节点的left引用指向新节点
            parent.left = newNode;
        } else {
            // 让父节点的left引用指向新节点
            parent.right = newNode;
        }
        return newNode;
    }

    // 判断二叉树是否为空
    public boolean empty() {
        // 根据元素判断二叉树是否为空
        return root.data == null;
    }

    // 返回根节点
    public TreeNode root() {
        if (empty()) {
            throw new RuntimeException("树为空,无法访问根节点");
        }
        return root;
    }

    // 返回指定节点(非根节点)的父节点
    public E parent(TreeNode node) {
        // 对于二叉树链表存储法,如果要访问指定节点的父节点必须遍历二叉树
        return null;
    }

    // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
    public E leftChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "节点为null,无法添加子节点");
        }
        return parent.left == null ? null : (E) parent.left.data;
    }

    // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
    public E rightChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "节点为null,无法添加子节点");
        }
        return parent.right == null ? null : (E) parent.right.data;
    }

    // 返回该二叉树的深度
    public int deep() {
        // 获取该树的深度
        return deep(root);
    }

    // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
    private int deep(TreeNode node) {
        if (node == null) {
            return 0;
        }
        // 没有子树
        if (node.left == null && node.right == null) {
            return 1;
        } else {
            int leftDeep = deep(node.left);
            int rightDeep = deep(node.right);
            // 记录其所有左、右子树中较大的深度
            int max = leftDeep > rightDeep ? leftDeep : rightDeep;
            // 返回其左右子树中较大的深度 + 1
            return max + 1;
        }

    }

}

测试类:

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class TwoLinkBinTreeTest {

    public static void main(String[] args) {

        TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根节点");
        // 依次添加节点
        TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
        TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
        TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
        TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
        TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true);

        System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
        System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
        System.out.println(binTree.deep());

    }

}

程序输出:

tn2的左子节点:第三层左节点
tn2的右子节点:第三层右节点
4

四、二叉树的三叉链表存储

三叉链表存储方式是对二叉链表的一种改进,通过为树节点增加一个parent引用,可以让每个节点都能非常方便的访问其父节点,三叉链表存储的二叉树即可方便地向下访问节点,也可方便地向上访问节点。

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class ThreeLinkBinTree<E> {

    public static class TreeNode {

        Object data;
        TreeNode left;
        TreeNode right;
        TreeNode parent;

        public TreeNode() {

        }

        public TreeNode(Object data) {
            this.data = data;
        }

        public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent) {
            this.data = data;
            this.left = left;
            this.right = right;
            this.parent = parent;
        }

    }

    private TreeNode root;

    // 以默认的构造器创建二叉树
    public ThreeLinkBinTree() {
        this.root = new TreeNode();
    }

    // 以指定根元素创建二叉树
    public ThreeLinkBinTree(E data) {
        this.root = new TreeNode(data);
    }

    /**
    * 为指定节点添加子节点
    *
    * @param parent 需要添加子节点的父节点的索引
    * @param data  新子节点的数据
    * @param isLeft 是否为左节点
    * @return 新增的节点
    */
    public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {

        if (parent == null) {
            throw new RuntimeException(parent + "节点为null, 无法添加子节点");
        }
        if (isLeft && parent.left != null) {
            throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
        }
        if (!isLeft && parent.right != null) {
            throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
        }

        TreeNode newNode = new TreeNode(data);
        if (isLeft) {
            // 让父节点的left引用指向新节点
            parent.left = newNode;
        } else {
            // 让父节点的left引用指向新节点
            parent.right = newNode;
        }
        // 让新节点的parent引用到parent节点
        newNode.parent = parent;
        return newNode;
    }

    // 判断二叉树是否为空
    public boolean empty() {
        // 根据元素判断二叉树是否为空
        return root.data == null;
    }

    // 返回根节点
    public TreeNode root() {
        if (empty()) {
            throw new RuntimeException("树为空,无法访问根节点");
        }
        return root;
    }

    // 返回指定节点(非根节点)的父节点
    public E parent(TreeNode node) {
        if (node == null) {
            throw new RuntimeException("节点为null,无法访问其父节点");
        }
        return (E) node.parent.data;
    }

    // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
    public E leftChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "节点为null,无法添加子节点");
        }
        return parent.left == null ? null : (E) parent.left.data;
    }

    // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
    public E rightChild(TreeNode parent) {
        if (parent == null) {
            throw new RuntimeException(parent + "节点为null,无法添加子节点");
        }
        return parent.right == null ? null : (E) parent.right.data;
    }

    // 返回该二叉树的深度
    public int deep() {
        // 获取该树的深度
        return deep(root);
    }

    // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
    private int deep(TreeNode node) {
        if (node == null) {
            return 0;
        }
        // 没有子树
        if (node.left == null && node.right == null) {
            return 1;
        } else {
            int leftDeep = deep(node.left);
            int rightDeep = deep(node.right);
            // 记录其所有左、右子树中较大的深度
            int max = leftDeep > rightDeep ? leftDeep : rightDeep;
            // 返回其左右子树中较大的深度 + 1
            return max + 1;
        }

    }

}

测试类:

package com.ietree.basic.datastructure.tree.binarytree;

/**
 * Created by ietree
 * 2017/5/1
 */
public class ThreeLinkBinTreeTest {

    public static void main(String[] args) {

        ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree<String>("根节点");
        // 依次添加节点
        ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
        ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
        ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
        ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
        ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true);

        System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
        System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
        System.out.println(binTree.deep());

    }

}

程序输出:

tn2的左子节点:第三层左节点
tn2的右子节点:第三层右节点
4

本文永久更新链接地址http://www.linuxidc.com/Linux/2017-05/143887.htm

linux
相关资讯       Java二叉树  二叉树存储结构 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款