From a391ecf04fe7b3bf38f79d8ce5abf149e111de5f Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 7 Dec 2017 23:37:09 +0100 Subject: [PATCH] BAEL-1339 - Implementing a binary tree in Java --- .../java/com/baeldung/tree/BinaryTree.java | 217 ++++++++++++++++++ .../com/baeldung/tree/BinaryTreeTest.java | 141 ++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/tree/BinaryTree.java create mode 100644 core-java/src/test/java/com/baeldung/tree/BinaryTreeTest.java diff --git a/core-java/src/main/java/com/baeldung/tree/BinaryTree.java b/core-java/src/main/java/com/baeldung/tree/BinaryTree.java new file mode 100644 index 0000000000..3c5f5f4e10 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/tree/BinaryTree.java @@ -0,0 +1,217 @@ +package com.baeldung.tree; + +import java.util.LinkedList; +import java.util.Queue; + +public class BinaryTree { + + Node root; + + public void add(int value) { + + Node newNode = new Node(value); + + if (root == null) { + root = newNode; + return; + } + + Node parent = root; + Node current = root; + + while (true) { + + if (newNode.value < parent.value) { + current = parent.left; + + if (current == null) { + parent.left = newNode; + break; + } + } else { + current = parent.right; + + if (current == null) { + parent.right = newNode; + break; + } + } + + parent = current; + } + + } + + public boolean isEmpty() { + return root == null; + } + + public boolean containsNode(int value) { + + Node current = root; + + while (current != null) { + + if (value == current.value) { + return true; + } + + if (value < current.value) { + current = current.left; + } else { + current = current.right; + } + + } + + return false; + } + + public void delete(int value) { + + Node current = root; + Node parent = root; + Node nodeToDelete = null; + boolean isLeftChild = false; + + while (nodeToDelete == null && current != null) { + + if (value == current.value) { + nodeToDelete = current; + } else if (value < current.value) { + parent = current; + current = current.left; + isLeftChild = true; + } else { + parent = current; + current = current.right; + isLeftChild = false; + } + + } + + if (nodeToDelete == null) { + return; + } + + // Case 1: no children + if (nodeToDelete.left == null && nodeToDelete.right == null) { + if (nodeToDelete == root) { + root = null; + } else if (isLeftChild) { + parent.left = null; + } else { + parent.right = null; + } + } + // Case 2: only 1 child + else if (nodeToDelete.right == null) { + if (nodeToDelete == root) { + root = nodeToDelete.left; + } else if (isLeftChild) { + parent.left = nodeToDelete.left; + } else { + parent.right = nodeToDelete.left; + } + } else if (nodeToDelete.left == null) { + if (nodeToDelete == root) { + root = nodeToDelete.right; + } else if (isLeftChild) { + parent.left = nodeToDelete.right; + } else { + parent.right = nodeToDelete.right; + } + } + // Case 3: 2 children + else if (nodeToDelete.left != null && nodeToDelete.right != null) { + Node replacement = findReplacement(nodeToDelete); + if (nodeToDelete == root) { + root = replacement; + } else if (isLeftChild) { + parent.left = replacement; + } else { + parent.right = replacement; + } + } + + } + + private Node findReplacement(Node nodeToDelete) { + + Node replacement = nodeToDelete; + Node parentReplacement = nodeToDelete; + Node current = nodeToDelete.right; + + while (current != null) { + parentReplacement = replacement; + replacement = current; + current = current.left; + } + + if (replacement != nodeToDelete.right) { + parentReplacement.left = replacement.right; + replacement.right = nodeToDelete.right; + } + + replacement.left = nodeToDelete.left; + + return replacement; + } + + public void traverseInOrder(Node node) { + if (node != null) { + traverseInOrder(node.left); + System.out.print(" " + node.value); + traverseInOrder(node.right); + } + } + + public void traversePreOrder(Node node) { + if (node != null) { + System.out.print(" " + node.value); + traversePreOrder(node.left); + traversePreOrder(node.right); + } + } + + public void traversePostOrder(Node node) { + if (node != null) { + traversePostOrder(node.left); + traversePostOrder(node.right); + + System.out.print(" " + node.value); + } + } + + public void traverseLevelOrder() { + Queue nodes = new LinkedList<>(); + nodes.add(root); + + while (!nodes.isEmpty()) { + + Node node = nodes.remove(); + + System.out.print(" " + node.value); + + if (node.left != null) { + nodes.add(node.left); + } + + if (node.left != null) { + nodes.add(node.right); + } + } + } + + class Node { + int value; + Node left; + Node right; + + Node(int value) { + this.value = value; + right = null; + left = null; + } + } +} diff --git a/core-java/src/test/java/com/baeldung/tree/BinaryTreeTest.java b/core-java/src/test/java/com/baeldung/tree/BinaryTreeTest.java new file mode 100644 index 0000000000..df0f3ba62d --- /dev/null +++ b/core-java/src/test/java/com/baeldung/tree/BinaryTreeTest.java @@ -0,0 +1,141 @@ +package com.baeldung.tree; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class BinaryTreeTest { + + @Test + public void givenABinaryTree_WhenAddElements_ThenTreeNotEmpty() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + assertTrue(!bt.isEmpty()); + } + + @Test + public void givenABinaryTree_WhenAddElements_ThenTreeContainsThoseElements() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + assertTrue(bt.containsNode(6)); + assertTrue(bt.containsNode(4)); + assertTrue(bt.containsNode(8)); + assertTrue(bt.containsNode(3)); + assertTrue(bt.containsNode(5)); + assertTrue(bt.containsNode(7)); + assertTrue(bt.containsNode(9)); + + assertFalse(bt.containsNode(1)); + assertFalse(bt.containsNode(10)); + } + + @Test + public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + assertTrue(bt.containsNode(9)); + bt.delete(9); + assertFalse(bt.containsNode(9)); + + assertTrue(bt.containsNode(6)); + bt.delete(6); + assertFalse(bt.containsNode(6)); + + assertTrue(bt.containsNode(4)); + bt.delete(4); + assertFalse(bt.containsNode(4)); + } + + @Test + public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + bt.traverseInOrder(bt.root); + } + + @Test + public void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + bt.traversePreOrder(bt.root); + } + + @Test + public void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + bt.traversePostOrder(bt.root); + } + + @Test + public void givenABinaryTree_WhenTraversingLevelOrder_ThenPrintValues() { + + BinaryTree bt = new BinaryTree(); + + bt.add(6); + bt.add(4); + bt.add(8); + bt.add(3); + bt.add(5); + bt.add(7); + bt.add(9); + + bt.traverseLevelOrder(); + } + +}