Skip to content

Commit 35554ea

Browse files
committed
Add test for ThreadedBinaryTree
1 parent ccab31a commit 35554ea

File tree

2 files changed

+122
-56
lines changed

2 files changed

+122
-56
lines changed

lib/trees/threaded_binary_tree.dart

+83-56
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class ThreadedBinaryNode<V extends Comparable>
1616

1717
ThreadedBinaryNode(this.value,
1818
{this.leftIsThread = true, this.rightIsThread = true});
19-
}
2019

21-
enum _DeleteCase { twoChildren, oneChild, childless }
20+
ThreadedBinaryNode.root(this.value);
21+
}
2222

2323
/// A [BinaryTree] is threaded by making all [right] pointers that would
2424
/// normally be null point to the in-order successor of the node
@@ -28,8 +28,27 @@ class ThreadedBinaryTree<V extends Comparable>
2828
extends BinaryTreeADT<ThreadedBinaryNode, V> {
2929
ThreadedBinaryNode root;
3030

31+
/// Creates an empty Threaded Binary tree.
32+
ThreadedBinaryTree();
33+
34+
/// Creates a Threaded Binary tree with all the values of [list].
35+
ThreadedBinaryTree.fromList(List<V> list) {
36+
for (var value in list) {
37+
add(value);
38+
}
39+
}
40+
41+
/// Creates a new Threaded Binary tree with a single [value].
42+
ThreadedBinaryTree.withSingleValue(V value)
43+
: root = ThreadedBinaryNode.root(value);
44+
3145
@override
3246
void add(V value) {
47+
if (isEmpty) {
48+
root = ThreadedBinaryNode.root(value);
49+
return;
50+
}
51+
3352
ThreadedBinaryNode parent, node = root;
3453
var isPresent = false;
3554

@@ -41,12 +60,12 @@ class ThreadedBinaryTree<V extends Comparable>
4160

4261
parent = node;
4362
if (node.value.compareTo(value) > 0) {
44-
if (!node.leftIsThread) {
63+
if (!(node.leftIsThread ?? true)) {
4564
node = node.left;
4665
} else {
4766
break;
4867
}
49-
} else if (!node.rightIsThread) {
68+
} else if (!(node.rightIsThread ?? true)) {
5069
node = node.right;
5170
} else {
5271
break;
@@ -56,16 +75,22 @@ class ThreadedBinaryTree<V extends Comparable>
5675
if (!isPresent) {
5776
var newNode = ThreadedBinaryNode(value);
5877

59-
if (parent == null) {
60-
root = newNode;
61-
} else if (parent.value.compareTo(value) > 0) {
78+
if (parent.value.compareTo(value) > 0) {
6279
newNode.left = parent.left;
6380
newNode.right = parent;
81+
82+
// Parent was the leftmost node of the tree.
83+
newNode.leftIsThread = parent.leftIsThread ?? null;
84+
6485
parent.leftIsThread = false;
6586
parent.left = newNode;
6687
} else {
6788
newNode.left = parent;
6889
newNode.right = parent.right;
90+
91+
// Parent was the rightmost node of the tree.
92+
newNode.rightIsThread = parent.rightIsThread ?? null;
93+
6994
parent.rightIsThread = false;
7095
parent.right = newNode;
7196
}
@@ -114,6 +139,48 @@ class ThreadedBinaryTree<V extends Comparable>
114139
}
115140
}
116141

142+
@override
143+
List<V> inOrder() {
144+
var result = <V>[];
145+
if (isEmpty) return result;
146+
147+
var node = root;
148+
while (node.leftIsThread != null) {
149+
node = node.left;
150+
}
151+
152+
while (node != null) {
153+
result.add(node.value);
154+
node = _inOrderSuccessor(node);
155+
}
156+
return result;
157+
}
158+
159+
@override
160+
List<V> preOrder() {
161+
var result = <V>[];
162+
if (isEmpty) return result;
163+
164+
var node = root;
165+
while (node != null) {
166+
result.add(node.value);
167+
if (!(node.leftIsThread ?? true)) {
168+
node = node.left;
169+
} else if (!(node.rightIsThread ?? true)) {
170+
node = node.right;
171+
} else {
172+
while (node != null && (node.rightIsThread ?? false)) {
173+
node = node.right;
174+
}
175+
176+
if (node != null) {
177+
node = node.right;
178+
}
179+
}
180+
}
181+
return result;
182+
}
183+
117184
void _delete(ThreadedBinaryNode parent, ThreadedBinaryNode node,
118185
_DeleteCase deleteCase) {
119186
switch (deleteCase) {
@@ -172,50 +239,21 @@ class ThreadedBinaryTree<V extends Comparable>
172239
}
173240
}
174241

175-
@override
176-
List<V> inOrder() {
177-
var result = <V>[];
178-
if (isEmpty) return result;
179-
180-
var node = root;
181-
while (!node.leftIsThread) {
242+
ThreadedBinaryNode _inOrderPredecessor(ThreadedBinaryNode node) {
243+
if (node.leftIsThread ?? true) {
244+
return node.left;
245+
} else {
182246
node = node.left;
183-
}
184-
185-
while (node.rightIsThread) {
186-
result.add(node.value);
187-
node = _inOrderSuccessor(node);
188-
}
189-
return result;
190-
}
191247

192-
@override
193-
List<V> preOrder() {
194-
var result = <V>[];
195-
if (isEmpty) return result;
196-
197-
var node = root;
198-
while (node != null) {
199-
result.add(node.value);
200-
if (!node.leftIsThread) {
201-
node = node.left;
202-
} else if (!node.rightIsThread) {
248+
while (!node.rightIsThread) {
203249
node = node.right;
204-
} else {
205-
while (node != null && node.rightIsThread) {
206-
node = node.right;
207-
}
208-
209-
if (node != null) {
210-
node = node.right;
211-
}
212250
}
251+
return node;
213252
}
214-
return result;
215253
}
216254

217255
ThreadedBinaryNode _inOrderSuccessor(ThreadedBinaryNode node) {
218-
if (node.rightIsThread) {
256+
if (node.rightIsThread ?? true) {
219257
return node.right;
220258
} else {
221259
node = node.right;
@@ -226,17 +264,6 @@ class ThreadedBinaryTree<V extends Comparable>
226264
return node;
227265
}
228266
}
229-
230-
ThreadedBinaryNode _inOrderPredecessor(ThreadedBinaryNode node) {
231-
if (node.leftIsThread) {
232-
return node.left;
233-
} else {
234-
node = node.left;
235-
236-
while (!node.rightIsThread) {
237-
node = node.right;
238-
}
239-
return node;
240-
}
241-
}
242267
}
268+
269+
enum _DeleteCase { twoChildren, oneChild, childless }
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:algorithms/trees/threaded_binary_tree.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
ThreadedBinaryTree<String> empty, singleNode, multipleNodes;
6+
List<ThreadedBinaryTree> treeList;
7+
8+
setUp(() {
9+
empty = ThreadedBinaryTree();
10+
singleNode = ThreadedBinaryTree.withSingleValue('@');
11+
multipleNodes = ThreadedBinaryTree.fromList(
12+
['f', 'b', 'g', 'a', 'd', 'i', 'c', 'e', 'h']);
13+
treeList = [singleNode, multipleNodes];
14+
});
15+
16+
group('Traversal', () {
17+
test('Pre-order', () {
18+
expect(empty.preOrder(), <String>[]);
19+
expect(singleNode.preOrder(), <String>['@']);
20+
expect(multipleNodes.preOrder(),
21+
equals(<String>['f', 'b', 'a', 'd', 'c', 'e', 'g', 'i', 'h']));
22+
});
23+
24+
// Results in stack overflow.
25+
test('Post-order', () {
26+
expect(empty.postOrder(), <String>[]);
27+
expect(singleNode.postOrder(), <String>['@']);
28+
expect(multipleNodes.postOrder(),
29+
equals(<String>['a', 'c', 'e', 'd', 'b', 'h', 'i', 'g', 'f']));
30+
});
31+
32+
test('In-order', () {
33+
expect(empty.inOrder(), <String>[]);
34+
expect(singleNode.inOrder(), <String>['@']);
35+
expect(multipleNodes.inOrder(),
36+
equals(<String>['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']));
37+
});
38+
});
39+
}

0 commit comments

Comments
 (0)