diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/ParentKeeperTreeNode.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/ParentKeeperTreeNode.java new file mode 100644 index 0000000000..2badd4c8ef --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/ParentKeeperTreeNode.java @@ -0,0 +1,54 @@ +package com.baeldung.algorithms.parentnodebinarytree; + +import java.util.Objects; + +public class ParentKeeperTreeNode { + + int value; + ParentKeeperTreeNode parent; + ParentKeeperTreeNode left; + ParentKeeperTreeNode right; + + public ParentKeeperTreeNode(int value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ParentKeeperTreeNode treeNode = (ParentKeeperTreeNode) o; + return value == treeNode.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + public void insert(int value) { + insert(this, value); + } + + private void insert(ParentKeeperTreeNode currentNode, final int value) { + if (currentNode.left == null && value < currentNode.value) { + currentNode.left = new ParentKeeperTreeNode(value); + currentNode.left.parent = currentNode; + return; + } + + if (currentNode.right == null && value > currentNode.value) { + currentNode.right = new ParentKeeperTreeNode(value); + currentNode.right.parent = currentNode; + return; + } + + if (value > currentNode.value) { + insert(currentNode.right, value); + } + + if (value < currentNode.value) { + insert(currentNode.left, value); + } + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/TreeNode.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/TreeNode.java new file mode 100644 index 0000000000..c12be08d09 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/parentnodebinarytree/TreeNode.java @@ -0,0 +1,107 @@ +package com.baeldung.algorithms.parentnodebinarytree; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.NoSuchElementException; +import java.util.Objects; + +import static java.lang.String.format; + +public class TreeNode { + int value; + TreeNode left; + TreeNode right; + + public TreeNode(int value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TreeNode treeNode = (TreeNode) o; + return value == treeNode.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + public void insert(int value) { + insert(this, value); + } + + private void insert(TreeNode currentNode, final int value) { + if (currentNode.left == null && value < currentNode.value) { + currentNode.left = new TreeNode(value); + return; + } + + if (currentNode.right == null && value > currentNode.value) { + currentNode.right = new TreeNode(value); + return; + } + + if (value > currentNode.value) { + insert(currentNode.right, value); + } + + if (value < currentNode.value) { + insert(currentNode.left, value); + } + } + + public TreeNode parent(int target) throws NoSuchElementException { + return parent(this, new TreeNode(target)); + } + + private TreeNode parent(TreeNode current, TreeNode target) throws NoSuchElementException { + if (target.equals(current) || current == null) { + throw new NoSuchElementException(format("No parent node found for 'target.value=%s' " + + "The target is not in the tree or the target is the topmost root node.", + target.value)); + } + + if (target.equals(current.left) || target.equals(current.right)) { + return current; + } + + return parent(target.value < current.value ? current.left : current.right, target); + } + + public TreeNode iterativeParent(int target) { + return iterativeParent(this, new TreeNode(target)); + } + + private TreeNode iterativeParent(TreeNode current, TreeNode target) { + Deque parentCandidates = new LinkedList<>(); + + String notFoundMessage = format("No parent node found for 'target.value=%s' " + + "The target is not in the tree or the target is the topmost root node.", + target.value); + + if (target.equals(current)) { + throw new NoSuchElementException(notFoundMessage); + } + + while (current != null || !parentCandidates.isEmpty()) { + + while (current != null) { + parentCandidates.addFirst(current); + current = current.left; + } + + current = parentCandidates.pollFirst(); + + if (target.equals(current.left) || target.equals(current.right)) { + return current; + } + + current = current.right; + } + + throw new NoSuchElementException(notFoundMessage); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/parentnodebinarytree/BinaryTreeParentNodeFinderUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/parentnodebinarytree/BinaryTreeParentNodeFinderUnitTest.java new file mode 100644 index 0000000000..d3f0ec7997 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/parentnodebinarytree/BinaryTreeParentNodeFinderUnitTest.java @@ -0,0 +1,83 @@ +package com.baeldung.algorithms.parentnodebinarytree; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.*; + +class BinaryTreeParentNodeFinderUnitTest { + + private TreeNode subject; + + @BeforeEach + void setUp() { + subject = new TreeNode(8); + subject.insert(5); + subject.insert(12); + subject.insert(3); + subject.insert(7); + subject.insert(1); + subject.insert(4); + subject.insert(11); + subject.insert(14); + subject.insert(13); + subject.insert(16); + } + + @Test + void givenBinaryTree_whenFindParentNode_thenReturnCorrectParentNode() { + assertEquals(8, subject.parent(5).value); + assertEquals(5, subject.parent(3).value); + assertEquals(5, subject.parent(7).value); + assertEquals(3, subject.parent(4).value); + assertEquals(3, subject.parent(1).value); + assertEquals(8, subject.parent(12).value); + assertEquals(12, subject.parent(14).value); + assertEquals(12, subject.parent(11).value); + assertEquals(14, subject.parent(16).value); + assertEquals(14, subject.parent(13).value); + assertThrows(NoSuchElementException.class, () -> subject.parent(1231)); + assertThrows(NoSuchElementException.class, () -> subject.parent(8)); + } + + @Test + void givenBinaryTree_whenFindParentNodeIteratively_thenReturnCorrectParentNode() { + assertEquals(8, subject.iterativeParent(5).value); + assertEquals(5, subject.iterativeParent(3).value); + assertEquals(5, subject.iterativeParent(7).value); + assertEquals(3, subject.iterativeParent(4).value); + assertEquals(3, subject.iterativeParent(1).value); + assertEquals(8, subject.iterativeParent(12).value); + assertEquals(12, subject.iterativeParent(14).value); + assertEquals(12, subject.iterativeParent(11).value); + assertEquals(14, subject.iterativeParent(16).value); + assertEquals(14, subject.iterativeParent(13).value); + assertThrows(NoSuchElementException.class, () -> subject.iterativeParent(1231)); + assertThrows(NoSuchElementException.class, () -> subject.iterativeParent(8)); + } + + @Test + void givenParentKeeperBinaryTree_whenGetParent_thenReturnCorrectParent() { + ParentKeeperTreeNode subject = new ParentKeeperTreeNode(8); + subject.insert(5); + subject.insert(12); + subject.insert(3); + subject.insert(7); + subject.insert(1); + subject.insert(4); + subject.insert(11); + subject.insert(14); + subject.insert(13); + subject.insert(16); + + assertNull(subject.parent); + assertEquals(8, subject.left.parent.value); + assertEquals(8, subject.right.parent.value); + assertEquals(5, subject.left.left.parent.value); + assertEquals(5, subject.left.right.parent.value); + + // tests for other nodes + } +} \ No newline at end of file