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

 

posted @ 2017-05-01 14:25  远近啊  阅读(5006)  评论(1编辑  收藏  举报