zoukankan      html  css  js  c++  java
  • Java中二叉树存储结构实现

    一、二叉树

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

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

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

      1 package com.ietree.basic.datastructure.tree.binarytree;
      2 
      3 /**
      4  * Created by ietree
      5  * 2017/5/1
      6  */
      7 public class ArrayBinTree<T> {
      8 
      9     // 使用数组来记录该树的所有节点
     10     private Object[] datas;
     11     private int DEFAULT_DEEP = 8;
     12     // 保存该树的深度
     13     private int deep;
     14     private int arraySize;
     15 
     16     // 以默认的深度创建二叉树
     17     public ArrayBinTree() {
     18         this.deep = DEFAULT_DEEP;
     19         this.arraySize = (int) (Math.pow(2, deep) - 1);
     20         datas = new Object[arraySize];
     21     }
     22 
     23     // 以指定深度创建二叉树
     24     public ArrayBinTree(int deep) {
     25         this.deep = deep;
     26         this.arraySize = (int) Math.pow(2, deep) - 1;
     27         datas = new Object[arraySize];
     28     }
     29 
     30     // 以指定深度、指定节点创建二叉树
     31     public ArrayBinTree(int deep, T data) {
     32         this.deep = deep;
     33         this.arraySize = (int) Math.pow(2, deep) - 1;
     34         datas = new Object[arraySize];
     35         datas[0] = data;
     36     }
     37 
     38     /**
     39      * 为指定节点添加子节点
     40      *
     41      * @param index 需要添加子节点的父节点的索引
     42      * @param data  新子节点的数据
     43      * @param left  是否为左节点
     44      */
     45     public void add(int index, T data, boolean left) {
     46         if (datas[index] == null) {
     47             throw new RuntimeException(index + "处节点为空,无法添加子节点");
     48         }
     49         if (2 * index + 1 >= arraySize) {
     50             throw new RuntimeException("树底层的数组已满,树越界异常");
     51         }
     52         // 添加左子节点
     53         if (left) {
     54             datas[2 * index + 1] = data;
     55         } else {
     56             datas[2 * index + 2] = data;
     57         }
     58     }
     59 
     60     // 判断二叉树是否为空
     61     public boolean empty() {
     62         // 根据根元素判断二叉树是否为空
     63         return datas[0] == null;
     64     }
     65 
     66     // 返回根节点
     67     public T root() {
     68         return (T) datas[0];
     69     }
     70 
     71     // 返回指定节点(非根结点)的父节点
     72     public T parent(int index) {
     73         return (T) datas[(index - 1) / 2];
     74     }
     75 
     76     // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
     77     public T left(int index) {
     78         if (2 * index + 1 >= arraySize) {
     79             throw new RuntimeException("该节点为叶子节点,无子节点");
     80         }
     81         return (T) datas[index * 2 + 1];
     82     }
     83 
     84     // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
     85     public T right(int index) {
     86         if (2 * index + 1 >= arraySize) {
     87             throw new RuntimeException("该节点为叶子节点,无子节点");
     88         }
     89         return (T) datas[index * 2 + 2];
     90     }
     91 
     92     // 返回该二叉树的深度
     93     public int deep(int index) {
     94         return deep;
     95     }
     96 
     97     // 返回指定节点的位置
     98     public int pos(T data) {
     99         // 该循环实际上就是按广度遍历来搜索每个节点
    100         for (int i = 0; i < arraySize; i++) {
    101             if (datas[i].equals(data)) {
    102                 return i;
    103             }
    104 
    105         }
    106         return -1;
    107     }
    108 
    109     public String toString() {
    110         return java.util.Arrays.toString(datas);
    111     }
    112 
    113 }

    测试类:

     1 package com.ietree.basic.datastructure.tree.binarytree;
     2 
     3 /**
     4  * Created by ietree
     5  * 2017/5/1
     6  */
     7 public class ArrayBinTreeTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根");
    12         binTree.add(0, "第二层右子节点", false);
    13         binTree.add(2, "第三层右子节点", false);
    14         binTree.add(6, "第四层右子节点", false);
    15         System.out.println(binTree);
    16         
    17     }
    18 
    19 }

    程序输出:

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

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

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

      1 package com.ietree.basic.datastructure.tree.binarytree;
      2 
      3 /**
      4  * Created by ietree
      5  * 2017/5/1
      6  */
      7 public class TwoLinkBinTree<E> {
      8 
      9     public static class TreeNode {
     10 
     11         Object data;
     12         TreeNode left;
     13         TreeNode right;
     14 
     15         public TreeNode() {
     16 
     17         }
     18 
     19         public TreeNode(Object data) {
     20             this.data = data;
     21         }
     22 
     23         public TreeNode(Object data, TreeNode left, TreeNode right) {
     24             this.data = data;
     25             this.left = left;
     26             this.right = right;
     27         }
     28 
     29     }
     30 
     31     private TreeNode root;
     32 
     33     // 以默认的构造器创建二叉树
     34     public TwoLinkBinTree() {
     35         this.root = new TreeNode();
     36     }
     37 
     38     // 以指定根元素创建二叉树
     39     public TwoLinkBinTree(E data) {
     40         this.root = new TreeNode(data);
     41     }
     42 
     43     /**
     44      * 为指定节点添加子节点
     45      *
     46      * @param parent 需要添加子节点的父节点的索引
     47      * @param data   新子节点的数据
     48      * @param isLeft 是否为左节点
     49      * @return 新增的节点
     50      */
     51     public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {
     52 
     53         if (parent == null) {
     54             throw new RuntimeException(parent + "节点为null, 无法添加子节点");
     55         }
     56         if (isLeft && parent.left != null) {
     57             throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
     58         }
     59         if (!isLeft && parent.right != null) {
     60             throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
     61         }
     62 
     63         TreeNode newNode = new TreeNode(data);
     64         if (isLeft) {
     65             // 让父节点的left引用指向新节点
     66             parent.left = newNode;
     67         } else {
     68             // 让父节点的left引用指向新节点
     69             parent.right = newNode;
     70         }
     71         return newNode;
     72     }
     73 
     74     // 判断二叉树是否为空
     75     public boolean empty() {
     76         // 根据元素判断二叉树是否为空
     77         return root.data == null;
     78     }
     79 
     80     // 返回根节点
     81     public TreeNode root() {
     82         if (empty()) {
     83             throw new RuntimeException("树为空,无法访问根节点");
     84         }
     85         return root;
     86     }
     87 
     88     // 返回指定节点(非根节点)的父节点
     89     public E parent(TreeNode node) {
     90         // 对于二叉树链表存储法,如果要访问指定节点的父节点必须遍历二叉树
     91         return null;
     92     }
     93 
     94     // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
     95     public E leftChild(TreeNode parent) {
     96         if (parent == null) {
     97             throw new RuntimeException(parent + "节点为null,无法添加子节点");
     98         }
     99         return parent.left == null ? null : (E) parent.left.data;
    100     }
    101 
    102     // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
    103     public E rightChild(TreeNode parent) {
    104         if (parent == null) {
    105             throw new RuntimeException(parent + "节点为null,无法添加子节点");
    106         }
    107         return parent.right == null ? null : (E) parent.right.data;
    108     }
    109 
    110     // 返回该二叉树的深度
    111     public int deep() {
    112         // 获取该树的深度
    113         return deep(root);
    114     }
    115 
    116     // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
    117     private int deep(TreeNode node) {
    118         if (node == null) {
    119             return 0;
    120         }
    121         // 没有子树
    122         if (node.left == null && node.right == null) {
    123             return 1;
    124         } else {
    125             int leftDeep = deep(node.left);
    126             int rightDeep = deep(node.right);
    127             // 记录其所有左、右子树中较大的深度
    128             int max = leftDeep > rightDeep ? leftDeep : rightDeep;
    129             // 返回其左右子树中较大的深度 + 1
    130             return max + 1;
    131         }
    132 
    133     }
    134 
    135 }

    测试类:

     1 package com.ietree.basic.datastructure.tree.binarytree;
     2 
     3 /**
     4  * Created by ietree
     5  * 2017/5/1
     6  */
     7 public class TwoLinkBinTreeTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根节点");
    12         // 依次添加节点
    13         TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
    14         TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
    15         TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
    16         TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
    17         TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true);
    18 
    19         System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
    20         System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
    21         System.out.println(binTree.deep());
    22 
    23     }
    24 
    25 }

    程序输出:

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

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

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

      1 package com.ietree.basic.datastructure.tree.binarytree;
      2 
      3 /**
      4  * Created by ietree
      5  * 2017/5/1
      6  */
      7 public class ThreeLinkBinTree<E> {
      8 
      9     public static class TreeNode {
     10 
     11         Object data;
     12         TreeNode left;
     13         TreeNode right;
     14         TreeNode parent;
     15 
     16         public TreeNode() {
     17 
     18         }
     19 
     20         public TreeNode(Object data) {
     21             this.data = data;
     22         }
     23 
     24         public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent) {
     25             this.data = data;
     26             this.left = left;
     27             this.right = right;
     28             this.parent = parent;
     29         }
     30 
     31     }
     32 
     33     private TreeNode root;
     34 
     35     // 以默认的构造器创建二叉树
     36     public ThreeLinkBinTree() {
     37         this.root = new TreeNode();
     38     }
     39 
     40     // 以指定根元素创建二叉树
     41     public ThreeLinkBinTree(E data) {
     42         this.root = new TreeNode(data);
     43     }
     44 
     45     /**
     46      * 为指定节点添加子节点
     47      *
     48      * @param parent 需要添加子节点的父节点的索引
     49      * @param data   新子节点的数据
     50      * @param isLeft 是否为左节点
     51      * @return 新增的节点
     52      */
     53     public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {
     54 
     55         if (parent == null) {
     56             throw new RuntimeException(parent + "节点为null, 无法添加子节点");
     57         }
     58         if (isLeft && parent.left != null) {
     59             throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
     60         }
     61         if (!isLeft && parent.right != null) {
     62             throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
     63         }
     64 
     65         TreeNode newNode = new TreeNode(data);
     66         if (isLeft) {
     67             // 让父节点的left引用指向新节点
     68             parent.left = newNode;
     69         } else {
     70             // 让父节点的left引用指向新节点
     71             parent.right = newNode;
     72         }
     73         // 让新节点的parent引用到parent节点
     74         newNode.parent = parent;
     75         return newNode;
     76     }
     77 
     78     // 判断二叉树是否为空
     79     public boolean empty() {
     80         // 根据元素判断二叉树是否为空
     81         return root.data == null;
     82     }
     83 
     84     // 返回根节点
     85     public TreeNode root() {
     86         if (empty()) {
     87             throw new RuntimeException("树为空,无法访问根节点");
     88         }
     89         return root;
     90     }
     91 
     92     // 返回指定节点(非根节点)的父节点
     93     public E parent(TreeNode node) {
     94         if (node == null) {
     95             throw new RuntimeException("节点为null,无法访问其父节点");
     96         }
     97         return (E) node.parent.data;
     98     }
     99 
    100     // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
    101     public E leftChild(TreeNode parent) {
    102         if (parent == null) {
    103             throw new RuntimeException(parent + "节点为null,无法添加子节点");
    104         }
    105         return parent.left == null ? null : (E) parent.left.data;
    106     }
    107 
    108     // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
    109     public E rightChild(TreeNode parent) {
    110         if (parent == null) {
    111             throw new RuntimeException(parent + "节点为null,无法添加子节点");
    112         }
    113         return parent.right == null ? null : (E) parent.right.data;
    114     }
    115 
    116     // 返回该二叉树的深度
    117     public int deep() {
    118         // 获取该树的深度
    119         return deep(root);
    120     }
    121 
    122     // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
    123     private int deep(TreeNode node) {
    124         if (node == null) {
    125             return 0;
    126         }
    127         // 没有子树
    128         if (node.left == null && node.right == null) {
    129             return 1;
    130         } else {
    131             int leftDeep = deep(node.left);
    132             int rightDeep = deep(node.right);
    133             // 记录其所有左、右子树中较大的深度
    134             int max = leftDeep > rightDeep ? leftDeep : rightDeep;
    135             // 返回其左右子树中较大的深度 + 1
    136             return max + 1;
    137         }
    138 
    139     }
    140 
    141 }

    测试类:

     1 package com.ietree.basic.datastructure.tree.binarytree;
     2 
     3 /**
     4  * Created by ietree
     5  * 2017/5/1
     6  */
     7 public class ThreeLinkBinTreeTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree<String>("根节点");
    12         // 依次添加节点
    13         ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
    14         ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
    15         ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
    16         ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
    17         ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true);
    18 
    19         System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
    20         System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
    21         System.out.println(binTree.deep());
    22 
    23     }
    24 
    25 }

    程序输出:

    tn2的左子节点:第三层左节点
    tn2的右子节点:第三层右节点
    4
  • 相关阅读:
    SQL语句导入导出大全
    数据库连接大全
    数据库关键字过滤问题
    HttpHandler
    asp代码的一个do。。。wile循环代码
    vs .net 2005 的Global.asax 在哪添加
    asp.net项目ckeditor+ckfinder实现图片上传
    CKEditor+CKFinder的图片上传配置
    asp实现统计访问量的代码
    asp.net绘统计图
  • 原文地址:https://www.cnblogs.com/Dylansuns/p/6791852.html
Copyright © 2011-2022 走看看