1. Sequential storage: use an array to record all nodes of a binary tree.
public class ArrayBinTree<T> { private final int DEFAULT_SIZE = 8; // Array records all nodes of the tree private Object[] datas; // save the depth of the tree private int deep; private int arraySize; // Create binary tree with default depth public ArrayBinTree() { this.deep = DEFAULT_SIZE; this.arraySize = (int)Math.pow(2, deep) - 1; this.datas = new Object[arraySize]; } // Create a binary tree with the specified depth public ArrayBinTree(int deep) { this.deep = deep; this.arraySize = (int)Math.pow(2, deep) - 1; this.datas = new Object[arraySize]; } // Create a binary tree with the specified depth and root node public ArrayBinTree(int deep, T data) { this.deep = deep; this.arraySize = (int)Math.pow(2, deep) - 1; this.datas = new Object[arraySize]; dates[0] = date; } /** * Add child nodes to the specified node * @param index needs to add the parent node index of the child node * @param data the data of the new child node * @param left is the left node */ public void addNode(int index, T data, boolean left) { if (datas[index] == null) { throw new RuntimeException(index + "The node is empty, no child nodes can be added"); } if (2 * index + 1 >= arraySize) { throw new RuntimeException("The array at the bottom of the tree is full, and the tree is out of bounds"); } if (left) { datas[2 * index + 1] = data; } else { datas[2 * index + 2] = data; } } // Check if the binary tree is empty public boolean empty() { // Determine if the binary tree is empty based on the root element return datas[0] == null; } // return the root node public T root() { if (empty()) { throw new RuntimeException("The tree is empty, the root node cannot be returned"); } return (T)datas[0]; } // Returns the parent node of the specified node (non-root node) public T parent(int index) { if (index == 0) { throw new RuntimeException("The root node has no parent"); } return (T)datas[(index - 1) / 2]; } // Returns the left child node of the specified node (non-leaf), returns null when the left child node does not exist public T left(int index) { if (2 * index + 1 >= arraySize) { throw new RuntimeException(index + "The node is a leaf node and has no left child"); } return datas[index * 2 + 1] == null? null : (T)datas[index * 2 + 1]; } // return the depth of the binary tree public int deep(int index) { return deep; } // return the position of the specified node public int pos(T data) { // The loop is actually traversing by breadth to search for each node for (int i = 0; i < arraySize; i++) { if (datas[i] == data) { return i; } } return -1; } public String toString() { return java.util.Arrays.toString(datas); } }
2. Binary linked list storage: each node retains a left and rigth fields, which point to its left and right child nodes respectively.
public class TwoLinkBinTree<E> { public static class TreeNode { private Object data; private TreeNode left; private 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; // Create binary tree with default constructor public TwoLinkBinTree() { this.root = new TreeNode(); } // Create a binary tree with the specified root element public TwoLinkBinTree(E data) { this.root = new TreeNode(data); } /** * Add child nodes to the specified node * @param parent the index of the parent node to which the child node needs to be added * @param data the data of the new child node * @param left is the left node * @return the new node */ public TreeNode addNode(TreeNode parent, E data, boolean left) { if (parent == null) { throw new RuntimeException(parent + "The node is empty, cannot add child nodes"); } if (left && parent.left != null) { throw new RuntimeException(parent + "The node already has a left node, so the left node cannot be added"); } if (!left && parent.right != null) { throw new RuntimeException(parent + "The node already has a right node, the right node cannot be added"); } TreeNode newNode = new TreeNode(data); if (left) { parent.left = newNode; } else { parent.right = newNode; } return newNode; } // Check if the binary tree is empty public boolean empty() { // Determine if the binary tree is empty based on the root element return root.data == null; } // return the root node public TreeNode root() { if (empty()) { throw new RuntimeException("The tree is empty, the root node cannot be returned"); } return root; } // Returns the parent node of the specified node (non-root node) public E parent(TreeNode node) { // For the binary linked list storage method, if you want to access the parent node of the specified node, you must traverse the binary tree return null; } // Returns the left child node of the specified node (non-leaf), returns null when the left child node does not exist public E leftChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "node is empty, no left child"); } return parent.left == null ? null : (E)parent.left.data; } // Returns the right child of the specified node (non-leaf). Returns null when the right child node does not exist public E rightChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "node is empty, no right child"); } return parent.right == null ? null : (E)parent.right.data; } // depth of binary tree public int deep() { // Get the depth of the tree deep(root); } // recursive method: the depth of each subtree is the maximum depth of all subtrees + 1 private int deep(TreeNode node) { if (node == null) { return 0; } if (node.right == null && node.left == null) { return 1; } else { int leftDeep = deep(node.left); int rightDeep = deep(node.right); int max = leftDeep > rightDeep? leftDeep : rightDeep; return max + 1; } } }
3. Three-forked linked list storage: each node retains a left, right, parent domain, pointing to its left, right child nodes and parent nodes respectively.
public class ThreeLinkBinTree<E> { public static class TreeNode { private Object data; private TreeNode parent; private TreeNode left; private TreeNode right; public TreeNode() { } public TreeNode(Object data) { this.data = data; } public TreeNode(Object data, TreeNode parent, TreeNode left, TreeNode right) { this.data = data; this.parent = parent; this.left = left; this.right = right; } } private TreeNode root; // Create binary tree with default constructor public ThreeLinkBinTree() { root = new TreeNode(); } // Create a binary tree with the specified root element public ThreeLinkBinTree(E data) { root = new TreeNode(data); } /** * Add child nodes to the specified node * @param parent the index of the parent node to which the child node needs to be added * @param data the data of the new child node * @param left is the left node * @return the new node */ public TreeNode addNode(TreeNode parent, E data, boolean left) { if (parent == null) { throw new RuntimeException(parent + "The node is empty, cannot add child nodes"); } if (left && parent.left != null) { throw new RuntimeException(parent + "The left node of the node is not empty, the left child node cannot be added"); } if (!left && parent.right != null) { throw new RuntimeException(parent + "The right node of the node is not empty, the right child node cannot be added"); } TreeNode newNode = new TreeNode(data); if (left) { parent.left = newNode; } else { parent.right = newNode; } newNode.parent = parent; return newNode; } // Check if the binary tree is empty public boolean empty() { // Determine if the binary tree is empty based on the root element return root.data == null; } // return the root node public TreeNode root() { if (empty()) { throw new RuntimeException("The root node is empty"); } return root; } // Returns the parent node of the specified node (non-root node) public E parent(TreeNode node) { return (E)node.parent.data; } // Returns the left child of the specified node (non-leaf). Returns null when the left child node does not exist public E leftChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "node is empty, no left child"); } return parent.left == null ? null:(E)parent.left.data; } // Returns the right child of the specified node (non-leaf). Returns null when the right child node does not exist public E rightChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "node is empty, no left child"); } return parent.right == null ? null : (E)parent.right.data; } // return the depth of the binary tree public int deep() { // Get the depth of the tree deep(root); } // recursive method: the depth of each subtree is the maximum depth of all subtrees + 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; return max + 1; } } }
public class BinTreeTest { public static void main(String[] args) { ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根"); binTree.addNode(0, "The second level right child node", false); binTree.addNode(2, "The third layer right child node", false); binTree.addNode(6, "Fourth layer right child node", false); System.out.println("[Sequential storage] Binary tree: " + binTree.toString()); TwoLinkBinTree<String> binTree2 = new TwoLinkBinTree<String>("根节点"); TwoLinkBinTree.TreeNode tn1 = binTree2.addNode(binTree2.root(), "Second layer left node", true); TwoLinkBinTree.TreeNode tn2 = binTree2.addNode(binTree2.root(), "Second layer right node", false); TwoLinkBinTree.TreeNode tn3 = binTree2.addNode(tn2, "third-level left node", true); TwoLinkBinTree.TreeNode tn4 = binTree2.addNode(tn2, "third-level right node", false); TwoLinkBinTree.TreeNode tn5 = binTree2.addNode(tn3, "left node of the fourth layer", true); System.out.println("tn2's left child node: " + binTree2.leftChild(tn2)); System.out.println("tn2's right child node: " + binTree2.rightChild(tn2)); System.out.println("[binary linked list storage] tree depth: " + binTree2.deep()); ThreeLinkBinTree<String> binTree3 = new ThreeLinkBinTree<String>("根节点"); ThreeLinkBinTree.TreeNode ttn1 = binTree3.addNode(binTree3.root(), "Second layer left node", true); ThreeLinkBinTree.TreeNode ttn2 = binTree3.addNode(binTree3.root(), "Second layer right node", false); ThreeLinkBinTree.TreeNode ttn3 = binTree3.addNode(ttn2, "third-level left node", true); ThreeLinkBinTree.TreeNode ttn4 = binTree3.addNode(ttn2, "The third layer right node", false); ThreeLinkBinTree.TreeNode ttn5 = binTree3.addNode(ttn3, "left node of the fourth layer", true); System.out.println("tn2's left child node: " + binTree3.leftChild(ttn2)); System.out.println("tn2's right child node: " + binTree3.rightChild(ttn2)); System.out.println("tn2's parent and child nodes: " + binTree3.parent(ttn2)); System.out.println("[Trinical linked list storage] tree depth: " + binTree3.deep()); } }