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
如果文章对你有所帮助的话,请点个推荐或者关注吧。也希望你能够养成分享的习惯,从而去帮助其他人。