Skip to content

Commit e43878b

Browse files
committed
Add ThreadedBinaryTree with in-order traversal and tests
1 parent 1e78a3f commit e43878b

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Threaded binary tree implementation that supports insertion and
8+
* in-order traversal without recursion or stack by using threads.
9+
*
10+
* <p>In this implementation, a node's null left/right pointers are used
11+
* to point to the in-order predecessor/successor respectively. Two flags
12+
* indicate whether left/right pointers are real children or threads.
13+
*
14+
* @see <a href="https://en.wikipedia.org/wiki/Threaded_binary_tree">Wikipedia:
15+
* Threaded binary tree</a>
16+
*/
17+
public final class ThreadedBinaryTree {
18+
19+
private Node root;
20+
21+
private static final class Node {
22+
int value;
23+
Node left;
24+
Node right;
25+
boolean leftIsThread;
26+
boolean rightIsThread;
27+
28+
Node(int value) {
29+
this.value = value;
30+
this.left = null;
31+
this.right = null;
32+
this.leftIsThread = false;
33+
this.rightIsThread = false;
34+
}
35+
}
36+
37+
public ThreadedBinaryTree() {
38+
this.root = null;
39+
}
40+
41+
/**
42+
* Inserts a value into the threaded binary tree. Duplicate values are inserted
43+
* to the right subtree (consistent deterministic rule).
44+
*
45+
* @param value the integer value to insert
46+
*/
47+
public void insert(int value) {
48+
Node newNode = new Node(value);
49+
if (root == null) {
50+
root = newNode;
51+
return;
52+
}
53+
54+
Node current = root;
55+
Node parent = null;
56+
while (current != null) {
57+
parent = current;
58+
if (value < current.value) {
59+
if (!current.leftIsThread && current.left != null) {
60+
current = current.left;
61+
} else {
62+
break;
63+
}
64+
} else { // value >= current.value
65+
if (!current.rightIsThread && current.right != null) {
66+
current = current.right;
67+
} else {
68+
break;
69+
}
70+
}
71+
}
72+
73+
if (value < parent.value) {
74+
// attach newNode as left child
75+
newNode.left = parent.left;
76+
newNode.leftIsThread = parent.leftIsThread;
77+
newNode.right = parent;
78+
newNode.rightIsThread = true;
79+
80+
parent.left = newNode;
81+
parent.leftIsThread = false;
82+
} else {
83+
// attach newNode as right child
84+
newNode.right = parent.right;
85+
newNode.rightIsThread = parent.rightIsThread;
86+
newNode.left = parent;
87+
newNode.leftIsThread = true;
88+
89+
parent.right = newNode;
90+
parent.rightIsThread = false;
91+
}
92+
}
93+
94+
/**
95+
* Returns the in-order traversal of the tree as a list of integers.
96+
* Traversal is done without recursion or an explicit stack by following threads.
97+
*
98+
* @return list containing the in-order sequence of node values
99+
*/
100+
public List<Integer> inorderTraversal() {
101+
List<Integer> result = new ArrayList<>();
102+
Node current = root;
103+
if (current == null) {
104+
return result;
105+
}
106+
107+
// Move to the leftmost node
108+
while (current.left != null && !current.leftIsThread) {
109+
current = current.left;
110+
}
111+
112+
while (current != null) {
113+
result.add(current.value);
114+
115+
// If right pointer is a thread, follow it
116+
if (current.rightIsThread) {
117+
current = current.right;
118+
} else {
119+
// Move to leftmost node in right subtree
120+
current = current.right;
121+
while (current != null && !current.leftIsThread && current.left != null) {
122+
current = current.left;
123+
}
124+
}
125+
}
126+
127+
return result;
128+
}
129+
130+
/**
131+
* Helper: checks whether the tree is empty.
132+
*
133+
* @return true if tree has no nodes
134+
*/
135+
public boolean isEmpty() {
136+
return root == null;
137+
}
138+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.thealgorithms.datastructures.trees;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.List;
6+
import org.junit.jupiter.api.Test;
7+
8+
/**
9+
* Basic tests for ThreadedBinaryTree inorder traversal.
10+
*/
11+
public class ThreadedBinaryTreeTest {
12+
13+
@Test
14+
public void testInorderTraversalSimple() {
15+
ThreadedBinaryTree tree = new ThreadedBinaryTree();
16+
tree.insert(50);
17+
tree.insert(30);
18+
tree.insert(70);
19+
tree.insert(20);
20+
tree.insert(40);
21+
tree.insert(60);
22+
tree.insert(80);
23+
24+
List<Integer> expected = List.of(20, 30, 40, 50, 60, 70, 80);
25+
List<Integer> actual = tree.inorderTraversal();
26+
27+
assertEquals(expected, actual);
28+
}
29+
30+
@Test
31+
public void testInorderWithDuplicates() {
32+
ThreadedBinaryTree tree = new ThreadedBinaryTree();
33+
tree.insert(5);
34+
tree.insert(3);
35+
tree.insert(7);
36+
tree.insert(7); // duplicate
37+
tree.insert(2);
38+
39+
List<Integer> expected = List.of(2, 3, 5, 7, 7);
40+
List<Integer> actual = tree.inorderTraversal();
41+
42+
assertEquals(expected, actual);
43+
}
44+
}

0 commit comments

Comments
 (0)