From 427adbd874ca730f8170aa5e70e9e8250413af7a Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 17:05:00 +0800 Subject: [PATCH 1/6] Add boundary traversal of binary tree Both time complexity and space complexity are O(n) --- .../trees/BoundaryTraversal.java | 163 ++++++++++++++++++ .../trees/BoundaryTraversalTest.java | 111 ++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java new file mode 100644 index 000000000000..a071a80634a5 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -0,0 +1,163 @@ +package com.thealgorithms.datastructures.trees; + +import java.util.*; + +/**BoundaryTraversal + * + * Start with the Root: + * Add the root node to the boundary list. + * Traverse the Left Boundary (Excluding Leaf Nodes): + * Move down the left side of the tree, adding each non-leaf node to the boundary list. + * If a node has a left child, go left; otherwise, go right. + * Visit All Leaf Nodes: + * Traverse the tree and add all leaf nodes to the boundary list, from left to right. + * Traverse the Right Boundary (Excluding Leaf Nodes) in Reverse Order: + * Move up the right side of the tree, adding each non-leaf node to a temporary list. + * If a node has a right child, go right; otherwise, go left. + * Reverse the temporary list and add it to the boundary list. + * Combine and Output: + * The final boundary list contains the root, left boundary, leaf nodes, and reversed right boundary in that order. + */ +public final class BoundaryTraversal { + private BoundaryTraversal() {} + + // Main function for boundary traversal, returns a list of boundary nodes in order + public static List boundaryTraversal(BinaryTree.Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + + // Add root node if it's not a leaf node + if (!isLeaf(root)) { + result.add(root.data); + } + + // Add left boundary + addLeftBoundary(root, result); + + // Add leaf nodes + addLeaves(root, result); + + // Add right boundary + addRightBoundary(root, result); + + return result; + } + + // Adds the left boundary, including nodes that have no left child but have a right child + private static void addLeftBoundary(BinaryTree.Node node, List result) { + BinaryTree.Node cur = node.left; + + // If there is no left child but there is a right child, treat the right child as part of the left boundary + if (cur == null && node.right != null) { + cur = node.right; + } + + while (cur != null) { + if (!isLeaf(cur)) { + result.add(cur.data); // Add non-leaf nodes to result + } + if (cur.left != null) { + cur = cur.left; // Move to the left child + } else if (cur.right != null) { + cur = cur.right; // If left child is null, move to the right child + } else { + break; // Stop if there are no children + } + } + } + + // Adds leaf nodes (nodes without children) + private static void addLeaves(BinaryTree.Node node, List result) { + if (node == null) { + return; + } + if (isLeaf(node)) { + result.add(node.data); // Add leaf node + } else { + addLeaves(node.left, result); // Recur for left subtree + addLeaves(node.right, result); // Recur for right subtree + } + } + + // Adds the right boundary, excluding leaf nodes + private static void addRightBoundary(BinaryTree.Node node, List result) { + BinaryTree.Node cur = node.right; + List temp = new ArrayList<>(); + + // If no right boundary is present and there is no left subtree, skip + if (cur != null && node.left == null) { + return; + } + while (cur != null) { + if (!isLeaf(cur)) { + temp.add(cur.data); // Store non-leaf nodes temporarily + } + if (cur.right != null) { + cur = cur.right; // Move to the right child + } else if (cur.left != null) { + cur = cur.left; // If right child is null, move to the left child + } else { + break; // Stop if there are no children + } + } + + // Add the right boundary nodes in reverse order + for (int i = temp.size() - 1; i >= 0; i--) { + result.add(temp.get(i)); + } + } + + // Checks if a node is a leaf node + private static boolean isLeaf(BinaryTree.Node node) { + return (node.left == null && node.right == null); + } + + // Iterative boundary traversal + public static List iterativeBoundaryTraversal(BinaryTree.Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + + // Add root node if it's not a leaf node + if (!isLeaf(root)) { + result.add(root.data); + } + + // Handle the left boundary + BinaryTree.Node cur = root.left; + if (cur == null && root.right != null) { + cur = root.right; + } + while (cur != null) { + if (!isLeaf(cur)) { + result.add(cur.data); // Add non-leaf nodes to result + } + cur = (cur.left != null) ? cur.left : cur.right; // Prioritize left child, move to right if left is null + } + + // Add leaf nodes + addLeaves(root, result); + + // Handle the right boundary using a stack (reverse order) + cur = root.right; + Deque stack = new LinkedList<>(); + if (cur != null && root.left == null) { + return result; + } + while (cur != null) { + if (!isLeaf(cur)) { + stack.push(cur.data); // Temporarily store right boundary nodes in a stack + } + cur = (cur.right != null) ? cur.right : cur.left; // Prioritize right child, move to left if right is null + } + + // Add the right boundary nodes from the stack to maintain the correct order + while (!stack.isEmpty()) { + result.add(stack.pop()); + } + return result; + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java new file mode 100644 index 000000000000..5c4222eba372 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -0,0 +1,111 @@ +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * + */ +public class BoundaryTraversalTest { + + + @Test + public void testNullRoot() { + assertEquals(Collections.emptyList(), BoundaryTraversal.boundaryTraversal(null)); + assertEquals(Collections.emptyList(), BoundaryTraversal.iterativeBoundaryTraversal(null)); + } + + @Test + public void testSingleNodeTree() { + final BinaryTree.Node root = new BinaryTree.Node(1); + + List expected = List.of(1); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 + + */ + @Test + public void testCompleteBinaryTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + 1, 2, 3, 4, 5, 6, 7 + }); + + List expected = List.of(1, 2, 4, 5, 6, 7, 3); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / \ + 2 7 + / \ + 3 8 + \ / + 4 9 + / \ + 5 6 + / \ + 10 11 + */ + @Test + public void testBoundaryTraversal() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 + }); + + List expected = List.of(1, 2, 3, 4, 5, 6, 10, 11, 9, 8, 7); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 1 + / + 2 + / + 3 + / + 4 + */ + @Test + public void testLeftSkewedTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1,2,null,3,null,4,null}); + + List expected = List.of(1,2,3,4); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + /* + 5 + \ + 6 + \ + 7 + \ + 8 + */ + @Test + public void testRightSkewedTree() { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5,null,6,null,7,null,8}); + + List expected = List.of(5, 6, 7,8); + + assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); + assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); + } + + +} From c04a8d2efa5005f7929df9da2e8e3018a66e12c7 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 18:14:00 +0800 Subject: [PATCH 2/6] format modification --- .../trees/BoundaryTraversal.java | 15 ++++++++----- .../trees/BoundaryTraversalTest.java | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index a071a80634a5..ade5232a8b2f 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -1,9 +1,13 @@ package com.thealgorithms.datastructures.trees; -import java.util.*; - -/**BoundaryTraversal - * +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +/** + * BoundaryTraversal + *

* Start with the Root: * Add the root node to the boundary list. * Traverse the Left Boundary (Excluding Leaf Nodes): @@ -19,7 +23,8 @@ * The final boundary list contains the root, left boundary, leaf nodes, and reversed right boundary in that order. */ public final class BoundaryTraversal { - private BoundaryTraversal() {} + private BoundaryTraversal() { + } // Main function for boundary traversal, returns a list of boundary nodes in order public static List boundaryTraversal(BinaryTree.Node root) { diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 5c4222eba372..49a047e6c5dc 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -1,10 +1,11 @@ package com.thealgorithms.datastructures.trees; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.List; -import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * @@ -27,6 +28,7 @@ public void testSingleNodeTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / \ @@ -37,7 +39,7 @@ public void testSingleNodeTree() { */ @Test public void testCompleteBinaryTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ 1, 2, 3, 4, 5, 6, 7 }); @@ -46,6 +48,7 @@ public void testCompleteBinaryTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / \ @@ -61,7 +64,7 @@ public void testCompleteBinaryTree() { */ @Test public void testBoundaryTraversal() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] { + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 }); @@ -70,6 +73,7 @@ public void testBoundaryTraversal() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 1 / @@ -81,13 +85,14 @@ public void testBoundaryTraversal() { */ @Test public void testLeftSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1,2,null,3,null,4,null}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{1, 2, null, 3, null, 4, null}); - List expected = List.of(1,2,3,4); + List expected = List.of(1, 2, 3, 4); assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } + /* 5 \ @@ -99,9 +104,9 @@ public void testLeftSkewedTree() { */ @Test public void testRightSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5,null,6,null,7,null,8}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{5, null, 6, null, 7, null, 8}); - List expected = List.of(5, 6, 7,8); + List expected = List.of(5, 6, 7, 8); assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); From 7bbcc8b32a046eb35c4ed405256759a38f34d0ed Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 19:22:31 +0800 Subject: [PATCH 3/6] Update BoundaryTraversal.java --- .../thealgorithms/datastructures/trees/BoundaryTraversal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index ade5232a8b2f..eb09f900d6a4 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -165,4 +165,4 @@ public static List iterativeBoundaryTraversal(BinaryTree.Node root) { } return result; } -} \ No newline at end of file +} From e5129585fe865a90a99a6a9585f64e3fdc1610d8 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 19:28:59 +0800 Subject: [PATCH 4/6] Update BoundaryTraversal.java --- .../thealgorithms/datastructures/trees/BoundaryTraversal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java index eb09f900d6a4..9a79902cc598 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java @@ -116,7 +116,7 @@ private static void addRightBoundary(BinaryTree.Node node, List result) // Checks if a node is a leaf node private static boolean isLeaf(BinaryTree.Node node) { - return (node.left == null && node.right == null); + return node.left == null && node.right == null; } // Iterative boundary traversal From f01eed065684cd678d62deca057b02b0e71f913d Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 22:42:53 +0800 Subject: [PATCH 5/6] Update BoundaryTraversalTest.java --- .../trees/BoundaryTraversalTest.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 49a047e6c5dc..7b7f9a316f73 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -1,11 +1,11 @@ package com.thealgorithms.datastructures.trees; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Collections; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @@ -39,9 +39,7 @@ public void testSingleNodeTree() { */ @Test public void testCompleteBinaryTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ - 1, 2, 3, 4, 5, 6, 7 - }); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 3, 4, 5, 6, 7}); List expected = List.of(1, 2, 4, 5, 6, 7, 3); @@ -64,9 +62,7 @@ public void testCompleteBinaryTree() { */ @Test public void testBoundaryTraversal() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{ - 1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11 - }); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11}); List expected = List.of(1, 2, 3, 4, 5, 6, 10, 11, 9, 8, 7); @@ -85,7 +81,7 @@ public void testBoundaryTraversal() { */ @Test public void testLeftSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{1, 2, null, 3, null, 4, null}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, null, 3, null, 4, null}); List expected = List.of(1, 2, 3, 4); @@ -104,7 +100,7 @@ public void testLeftSkewedTree() { */ @Test public void testRightSkewedTree() { - final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[]{5, null, 6, null, 7, null, 8}); + final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5, null, 6, null, 7, null, 8}); List expected = List.of(5, 6, 7, 8); From f25a77a25add933f17a81ecd3b492f0295d696d9 Mon Sep 17 00:00:00 2001 From: xuyang471 <2621860014@qq.com> Date: Tue, 8 Oct 2024 22:45:17 +0800 Subject: [PATCH 6/6] Update BoundaryTraversalTest.java --- .../datastructures/trees/BoundaryTraversalTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java index 7b7f9a316f73..515dac88ce09 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java @@ -4,7 +4,6 @@ import java.util.Collections; import java.util.List; - import org.junit.jupiter.api.Test; /** @@ -12,7 +11,6 @@ */ public class BoundaryTraversalTest { - @Test public void testNullRoot() { assertEquals(Collections.emptyList(), BoundaryTraversal.boundaryTraversal(null)); @@ -107,6 +105,4 @@ public void testRightSkewedTree() { assertEquals(expected, BoundaryTraversal.boundaryTraversal(root)); assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root)); } - - }