Skip to content

Commit 5146e18

Browse files
authored
Merge pull request #36 from happy-san/threadedBinaryTree
Threaded binary tree
2 parents 1065206 + 03173f7 commit 5146e18

9 files changed

+492
-5
lines changed

lib/trees/binary_tree_adt.dart lib/trees/adt/binary_tree_adt.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import './tree_adt.dart';
1+
import 'tree_adt.dart';
22

33
/// Declares members of a binary node.
44
abstract class BinaryNodeADT<N extends BinaryNodeADT<N, V>,
File renamed without changes.

lib/trees/avl_tree.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @dart=2.9
2-
import './binary_tree_adt.dart';
2+
import 'adt/binary_tree_adt.dart';
33
import 'binary_search_tree.dart';
44
import 'binary_tree.dart';
55

lib/trees/binary_search_tree.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @dart=2.9
2-
import './binary_tree_adt.dart';
2+
import 'adt/binary_tree_adt.dart';
33
import 'binary_tree.dart';
44

55
/// Hierarchical data structure of individual [BinaryNode]s.

lib/trees/binary_tree.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @dart=2.9
2-
import 'binary_tree_adt.dart';
2+
import 'adt/binary_tree_adt.dart';
33

44
/// A binary node has at most two children, which are referred to as the
55
/// [left] child and the [right] child.

lib/trees/red_black_tree.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @dart=2.9
2-
import './binary_tree_adt.dart';
2+
import 'adt/binary_tree_adt.dart';
33
import 'binary_search_tree.dart';
44
import 'binary_tree.dart';
55

lib/trees/threaded_binary_tree.dart

+289
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
import 'adt/binary_tree_adt.dart';
2+
//import 'binary_tree.dart';
3+
4+
/// Data structure similar to [BinaryNode], differs in having two boolean values
5+
/// [leftIsThread] and [rightIsThread] to determine whether [left] and [right]
6+
/// are threads or point to a child instead.
7+
class ThreadedBinaryNode<V extends Comparable>
8+
extends BinaryNodeADT<ThreadedBinaryNode<V>, V> {
9+
V? value;
10+
11+
/// Stores if [left] is a thread.
12+
bool? leftIsThread;
13+
14+
/// Stores if [right] is a thread.
15+
bool? rightIsThread;
16+
17+
/// Creates a node with [value] and marks [left] and [right] to be threads.
18+
ThreadedBinaryNode(this.value,
19+
{this.leftIsThread = true, this.rightIsThread = true});
20+
21+
/// Creates a root node with [value].
22+
ThreadedBinaryNode.root(this.value);
23+
}
24+
25+
/// A [BinaryTree] is threaded by making all [right] pointers that would
26+
/// normally be null point to the in-order successor of the node
27+
/// (if it exists), and all [left] pointers that would normally be null point
28+
/// to the in-order predecessor of the node.
29+
class ThreadedBinaryTree<V extends Comparable>
30+
extends BinaryTreeADT<ThreadedBinaryNode<V>, V> {
31+
ThreadedBinaryNode<V>? root;
32+
33+
/// Creates an empty Threaded Binary tree.
34+
ThreadedBinaryTree();
35+
36+
/// Creates a Threaded Binary tree with all the values of [list].
37+
ThreadedBinaryTree.fromList(List<V> list) {
38+
for (var value in list) {
39+
add(value);
40+
}
41+
}
42+
43+
/// Creates a new Threaded Binary tree with a single [value].
44+
ThreadedBinaryTree.withSingleValue(V value)
45+
: root = ThreadedBinaryNode.root(value);
46+
47+
@override
48+
void add(V value) {
49+
if (isEmpty) {
50+
root = ThreadedBinaryNode.root(value);
51+
return;
52+
}
53+
54+
late ThreadedBinaryNode<V> parent;
55+
var node = root, isPresent = false;
56+
57+
while (node != null) {
58+
if (node.value!.compareTo(value) == 0) {
59+
isPresent = true;
60+
break;
61+
}
62+
63+
parent = node;
64+
if (node.value!.compareTo(value) > 0) {
65+
if (!(node.leftIsThread ?? true)) {
66+
node = node.left;
67+
} else {
68+
break;
69+
}
70+
} else if (!(node.rightIsThread ?? true)) {
71+
node = node.right;
72+
} else {
73+
break;
74+
}
75+
}
76+
77+
if (!isPresent) {
78+
var newNode = ThreadedBinaryNode(value);
79+
80+
if (parent.value!.compareTo(value) > 0) {
81+
newNode.left = parent.left;
82+
newNode.right = parent;
83+
84+
// Parent was the leftmost node of the tree.
85+
newNode.leftIsThread = parent.leftIsThread ?? null;
86+
87+
parent.leftIsThread = false;
88+
parent.left = newNode;
89+
} else {
90+
newNode.left = parent;
91+
newNode.right = parent.right;
92+
93+
// Parent was the rightmost node of the tree.
94+
newNode.rightIsThread = parent.rightIsThread ?? null;
95+
96+
parent.rightIsThread = false;
97+
parent.right = newNode;
98+
}
99+
}
100+
}
101+
102+
@override
103+
bool contains(V value) => inOrder().contains(value);
104+
105+
@override
106+
void delete(V value) {
107+
ThreadedBinaryNode<V>? parent;
108+
var node = root, isPresent = false;
109+
110+
while (node != null) {
111+
if (node.value!.compareTo(value) == 0) {
112+
isPresent = true;
113+
break;
114+
}
115+
116+
parent = node;
117+
if (node.value!.compareTo(value) > 0) {
118+
if (!(node.leftIsThread ?? true)) {
119+
node = node.left;
120+
} else {
121+
break;
122+
}
123+
} else if (!(node.rightIsThread ?? true)) {
124+
node = node.right;
125+
} else {
126+
break;
127+
}
128+
}
129+
130+
if (isPresent) {
131+
if (!(node!.leftIsThread ?? true) && !(node.rightIsThread ?? true)) {
132+
// Node has 2 children.
133+
_delete(parent, node, _DeleteCase.twoChildren);
134+
} else if (!(node.leftIsThread ?? true)) {
135+
// Node has only a left child.
136+
_delete(parent, node, _DeleteCase.oneChild);
137+
} else if (!(node.rightIsThread ?? true)) {
138+
// Node has only a right child.
139+
_delete(parent, node, _DeleteCase.oneChild);
140+
} else {
141+
// Node is childless.
142+
_delete(parent, node, _DeleteCase.childless);
143+
}
144+
}
145+
}
146+
147+
@override
148+
List<V> inOrder() {
149+
var result = <V>[];
150+
if (isEmpty) return result;
151+
152+
var node = root;
153+
while (node!.leftIsThread != null) {
154+
node = node.left;
155+
}
156+
157+
while (node != null) {
158+
result.add(node.value!);
159+
node = _inOrderSuccessor(node);
160+
}
161+
return result;
162+
}
163+
164+
@override
165+
List<V> postOrder() {
166+
var result = <V>[];
167+
_postOrder(root, result);
168+
return result;
169+
}
170+
171+
@override
172+
List<V> preOrder() {
173+
var result = <V>[];
174+
if (isEmpty) return result;
175+
176+
var node = root;
177+
while (node != null) {
178+
result.add(node.value!);
179+
if (!(node.leftIsThread ?? true)) {
180+
node = node.left;
181+
} else if (!(node.rightIsThread ?? true)) {
182+
node = node.right;
183+
} else {
184+
while (node != null && (node.rightIsThread ?? false)) {
185+
node = node.right;
186+
}
187+
188+
if (node != null) {
189+
node = node.right;
190+
}
191+
}
192+
}
193+
return result;
194+
}
195+
196+
void _delete(ThreadedBinaryNode<V>? parent, ThreadedBinaryNode<V> node,
197+
_DeleteCase deleteCase) {
198+
switch (deleteCase) {
199+
case _DeleteCase.childless:
200+
if (parent == null) {
201+
nullify();
202+
} else if (node == parent.left) {
203+
parent.leftIsThread = node.leftIsThread == null ? null : true;
204+
parent.left = node.left;
205+
} else {
206+
parent.rightIsThread = node.rightIsThread == null ? null : true;
207+
parent.right = node.right;
208+
}
209+
break;
210+
211+
case _DeleteCase.oneChild:
212+
var child = (node.leftIsThread ?? true) ? node.right : node.left;
213+
214+
if (parent == null) {
215+
root = child;
216+
} else if (node == parent.left) {
217+
parent.left = child;
218+
} else {
219+
parent.right = child;
220+
}
221+
222+
var successor = _inOrderSuccessor(node);
223+
var predecessor = _inOrderPredecessor(node);
224+
if (!(node.leftIsThread ?? true)) {
225+
predecessor!.right = successor;
226+
predecessor.rightIsThread = successor == null ? null : true;
227+
} else {
228+
if (!(node.rightIsThread ?? true)) {
229+
successor!.left = predecessor;
230+
successor.leftIsThread = predecessor == null ? null : true;
231+
}
232+
}
233+
break;
234+
235+
case _DeleteCase.twoChildren:
236+
var successor = node.right!, parentSuccessor = node;
237+
238+
while (!successor.leftIsThread!) {
239+
parentSuccessor = successor;
240+
successor = successor.left!;
241+
}
242+
243+
node.value = successor.value;
244+
245+
if (successor.leftIsThread! && (successor.rightIsThread ?? true)) {
246+
_delete(parentSuccessor, successor, _DeleteCase.childless);
247+
} else {
248+
_delete(parentSuccessor, successor, _DeleteCase.oneChild);
249+
}
250+
break;
251+
}
252+
}
253+
254+
ThreadedBinaryNode<V>? _inOrderPredecessor(ThreadedBinaryNode<V> node) {
255+
if (node.leftIsThread ?? true) {
256+
return node.left;
257+
} else {
258+
node = node.left!;
259+
260+
while (!node.rightIsThread!) {
261+
node = node.right!;
262+
}
263+
return node;
264+
}
265+
}
266+
267+
ThreadedBinaryNode<V>? _inOrderSuccessor(ThreadedBinaryNode<V> node) {
268+
if (node.rightIsThread ?? true) {
269+
return node.right;
270+
} else {
271+
node = node.right!;
272+
273+
while (!node.leftIsThread!) {
274+
node = node.left!;
275+
}
276+
return node;
277+
}
278+
}
279+
280+
void _postOrder(ThreadedBinaryNode<V>? node, List<V> list) {
281+
if (node == null) return;
282+
283+
if (!(node.leftIsThread ?? false)) _postOrder(node.left, list);
284+
if (!(node.rightIsThread ?? false)) _postOrder(node.right, list);
285+
list.add(node.value!);
286+
}
287+
}
288+
289+
enum _DeleteCase { twoChildren, oneChild, childless }

test/trees/red_black_tree_test.dart

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ void main() {
8585
});
8686
});
8787

88+
// TODO: Use isTrue, isFalse and equals().
8889
test('Add node', () {
8990
var test = RedBlackTree();
9091
var list = test.inOrder();

0 commit comments

Comments
 (0)