BAEL-7410: Finding Parent of a Node in a Binary Tree (#15736)
* adding the parent method. wrapping up structure of tree * wrapping up recursive solution with edge cases. tests passing * refactor parent function for clarity * renaming Test class to suffix UnitTest * adding iterative version tests. adding parent keeper tree and tests * final adjustments * adding review suggestions * fix requested changes * Revert "fix requested changes" This reverts commit e52d3e6531668f99c415939c195bb4bbdd349bae. * reverting bad commit * adding variable for notFoundMesage * fixing package names. fix test names
This commit is contained in:
parent
0141c95811
commit
c39267bbf9
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<TreeNode> 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user