Skip to content

Commit 3e0eec6

Browse files
binary search tree implementation updated (#15)
* Updated Binary Search Tree data structure - Now the new BST function has more methods
1 parent dd1a5c2 commit 3e0eec6

File tree

1 file changed

+258
-57
lines changed

1 file changed

+258
-57
lines changed

search/binarySearchTree.zig

+258-57
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,283 @@
11
const std = @import("std");
2-
const expect = std.testing.expect;
2+
const print = std.debug.print;
3+
const ArrayList = std.ArrayList;
4+
const testing = std.testing;
35

4-
fn Node(comptime T: type) type {
6+
// Returns a binary search tree instance.
7+
// Arguments:
8+
// T: the type of the info(i.e. i32, i16, u32, etc...)
9+
// Allocator: This is needed for the struct instance. In most cases, feel free
10+
// to use std.heap.GeneralPurposeAllocator.
11+
pub fn BinarySearchTree(comptime T: type) type {
512
return struct {
6-
value: T,
7-
parent: ?*Node(T) = null,
8-
left: ?*Node(T) = null,
9-
right: ?*Node(T) = null,
10-
};
11-
}
13+
const Self = @This();
1214

13-
fn Tree(comptime T: type) type {
14-
return struct {
15-
root: ?*Node(T) = null,
15+
// This is the node struct. It holds:
16+
// info: T
17+
// right: A pointer to the right child
18+
// left: A pointer to the left child
19+
pub const node = struct {
20+
info: T,
21+
right: ?*node = null,
22+
left: ?*node = null,
23+
};
1624

17-
pub fn search(node: ?*Node(T), value: T) ?*Node(T) {
18-
if (node == null or node.?.value == value) {
19-
return node;
25+
allocator: *std.mem.Allocator,
26+
root: ?*node = null,
27+
size: usize = 0,
28+
29+
// Function to insert elements into the tree
30+
// Runs in θ(logn)/O(n), uses the helper _insert private function
31+
// Arguments:
32+
// key: T - the key to be inserted into the tree
33+
pub fn insert(self: *Self, key: T) !void {
34+
self.root = try self._insert(self.root, key);
35+
self.size += 1;
36+
}
37+
38+
// Function to remove elements from the tree
39+
// Runs in θ(logn)/O(n), uses the helper _remove private function
40+
// Arguments:
41+
// key: T - the key to be removed from the tree
42+
pub fn remove(self: *Self, key: T) !void {
43+
if (self.root == null) {
44+
return;
2045
}
21-
if (value < node.?.value) {
22-
return search(node.?.left, value);
23-
} else {
24-
return search(node.?.right, value);
46+
self.root = try self._remove(self.root, key);
47+
self.size -= 1;
48+
}
49+
50+
// Function to search if a key exists in the tree
51+
// Runs in θ(logn)/O(n), uses the helper _search private function
52+
// Arguments:
53+
// key: T - the key that will be searched
54+
pub fn search(self: *Self, key: T) bool {
55+
return _search(self.root, key);
56+
}
57+
58+
// Function that performs inorder traversal of the tree
59+
pub fn inorder(self: *Self, path: *ArrayList(T)) !void {
60+
if (self.root == null) {
61+
return;
62+
}
63+
try self._inorder(self.root, path);
64+
}
65+
66+
// Function that performs preorder traversal of the tree
67+
pub fn preorder(self: *Self, path: *ArrayList(T)) !void {
68+
if (self.root == null) {
69+
return;
70+
}
71+
try self._preorder(self.root, path);
72+
}
73+
74+
// Function that performs postorder traversal of the tree
75+
pub fn postorder(self: *Self, path: *ArrayList(T)) !void {
76+
if (self.root == null) {
77+
return;
2578
}
79+
try self._postorder(self.root, path);
2680
}
2781

28-
pub fn insert(self: *Tree(T), z: *Node(T)) void {
29-
var y: ?*Node(T) = null;
30-
var x = self.root;
31-
while (x) |node| {
32-
y = node;
33-
if (z.value < node.value) {
34-
x = node.left;
82+
// Function that destroys the allocated memory of the whole tree
83+
// Uses the _destroy helper private function
84+
pub fn destroy(self: *Self) void {
85+
if (self.root == null) {
86+
return;
87+
}
88+
self._destroy(self.root);
89+
self.size = 0;
90+
}
91+
92+
// Function that generates a new node
93+
// Arguments:
94+
// key: T - The info of the node
95+
fn new_node(self: *Self, key: T) !?*node {
96+
const nn = try self.allocator.create(node);
97+
nn.* = node{ .info = key, .right = null, .left = null };
98+
return nn;
99+
}
100+
101+
fn _insert(self: *Self, root: ?*node, key: T) !?*node {
102+
if (root == null) {
103+
return try self.new_node(key);
104+
} else {
105+
if (root.?.info < key) {
106+
root.?.right = try self._insert(root.?.right, key);
35107
} else {
36-
x = node.right;
108+
root.?.left = try self._insert(root.?.left, key);
37109
}
38110
}
39-
z.parent = y;
40-
if (y == null) {
41-
self.root = z;
42-
} else if (z.value < y.?.value) {
43-
y.?.left = z;
111+
112+
return root;
113+
}
114+
115+
fn _remove(self: *Self, root: ?*node, key: T) !?*node {
116+
if (root == null) {
117+
return root;
118+
}
119+
120+
if (root.?.info < key) {
121+
root.?.right = try self._remove(root.?.right, key);
122+
} else if (root.?.info > key) {
123+
root.?.left = try self._remove(root.?.left, key);
44124
} else {
45-
y.?.right = z;
125+
if (root.?.left == null and root.?.right == null) {
126+
self.allocator.destroy(root.?);
127+
return null;
128+
} else if (root.?.left == null) {
129+
const temp = root.?.right;
130+
self.allocator.destroy(root.?);
131+
return temp;
132+
} else if (root.?.right == null) {
133+
const temp = root.?.left;
134+
self.allocator.destroy(root.?);
135+
return temp;
136+
} else {
137+
var curr: ?*node = root.?.right;
138+
while (curr.?.left != null) : (curr = curr.?.left) {}
139+
root.?.info = curr.?.info;
140+
root.?.right = try self._remove(root.?.right, curr.?.info);
141+
}
142+
}
143+
144+
return root;
145+
}
146+
147+
fn _search(root: ?*node, key: T) bool {
148+
var head: ?*node = root;
149+
while (head) |curr| {
150+
if (curr.info < key) {
151+
head = curr.right;
152+
} else if (curr.info > key) {
153+
head = curr.left;
154+
} else {
155+
return true;
156+
}
157+
}
158+
159+
return false;
160+
}
161+
162+
fn _inorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void {
163+
if (root != null) {
164+
try self._inorder(root.?.left, path);
165+
try path.append(root.?.info);
166+
try self._inorder(root.?.right, path);
167+
}
168+
}
169+
170+
fn _preorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void {
171+
if (root != null) {
172+
try path.append(root.?.info);
173+
try self._preorder(root.?.left, path);
174+
try self._preorder(root.?.right, path);
175+
}
176+
}
177+
178+
fn _postorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void {
179+
if (root != null) {
180+
try self._postorder(root.?.left, path);
181+
try self._postorder(root.?.right, path);
182+
try path.append(root.?.info);
183+
}
184+
}
185+
186+
fn _destroy(self: *Self, root: ?*node) void {
187+
if (root != null) {
188+
self._destroy(root.?.left);
189+
self._destroy(root.?.right);
190+
self.allocator.destroy(root.?);
46191
}
47192
}
48193
};
49194
}
50195

51-
test "search empty tree" {
52-
const tree = Tree(i32){};
53-
const result = Tree(i32).search(tree.root, 3);
54-
try expect(result == null);
196+
test "Testing insertion" {
197+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
198+
defer _ = gpa.deinit();
199+
var allocator = gpa.allocator();
200+
201+
var t = BinarySearchTree(i32){ .allocator = &allocator };
202+
defer t.destroy();
203+
204+
try t.insert(10);
205+
try t.insert(5);
206+
try t.insert(25);
207+
try t.insert(3);
208+
try t.insert(12);
209+
try testing.expect(t.size == 5);
210+
try testing.expect(t.search(10) == true);
211+
try testing.expect(t.search(15) == false);
55212
}
56213

57-
test "search an existing element" {
58-
var tree = Tree(i32){};
59-
var node = Node(i32){ .value = 3 };
60-
tree.insert(&node);
61-
const result = Tree(i32).search(tree.root, 3);
62-
try expect(result.? == &node);
214+
test "Testing bst removal" {
215+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
216+
defer _ = gpa.deinit();
217+
var allocator = gpa.allocator();
218+
219+
var t = BinarySearchTree(i32){ .allocator = &allocator };
220+
defer t.destroy();
221+
222+
try t.insert(10);
223+
try t.insert(5);
224+
try t.insert(3);
225+
try t.insert(15);
226+
try testing.expect(t.size == 4);
227+
try testing.expect(t.search(15) == true);
228+
try t.remove(10);
229+
try testing.expect(t.size == 3);
230+
try testing.expect(t.search(10) == false);
63231
}
64232

65-
test "search non-existent element" {
66-
var tree = Tree(i32){};
67-
var node = Node(i32){ .value = 3 };
68-
tree.insert(&node);
69-
const result = Tree(i32).search(tree.root, 4);
70-
try expect(result == null);
233+
test "Testing traversal methods" {
234+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
235+
defer _ = gpa.deinit();
236+
var allocator = gpa.allocator();
237+
238+
var t = BinarySearchTree(i32){ .allocator = &allocator };
239+
defer t.destroy();
240+
241+
try t.insert(5);
242+
try t.insert(25);
243+
try t.insert(3);
244+
try t.insert(12);
245+
try t.insert(15);
246+
247+
var ino = ArrayList(i32).init(allocator);
248+
defer ino.deinit();
249+
250+
const check_ino = [_]i32{ 3, 5, 12, 15, 25 };
251+
try t.inorder(&ino);
252+
try testing.expect(std.mem.eql(i32, ino.items, &check_ino));
253+
254+
var pre = ArrayList(i32).init(allocator);
255+
defer pre.deinit();
256+
257+
const check_pre = [_]i32{ 5, 3, 25, 12, 15 };
258+
try t.preorder(&pre);
259+
260+
try testing.expect(std.mem.eql(i32, pre.items, &check_pre));
261+
262+
var post = ArrayList(i32).init(allocator);
263+
defer post.deinit();
264+
265+
const check_post = [_]i32{ 3, 15, 12, 25, 5 };
266+
try t.postorder(&post);
267+
268+
try testing.expect(std.mem.eql(i32, post.items, &check_post));
71269
}
72270

73-
test "search for an element with multiple nodes" {
74-
var tree = Tree(i32){};
75-
const values = [_]i32{ 15, 18, 17, 6, 7, 20, 3, 13, 2, 4, 9 };
76-
for (values) |v| {
77-
var node = Node(i32){ .value = v };
78-
tree.insert(&node);
79-
}
80-
const result = Tree(i32).search(tree.root, 9);
81-
try expect(result.?.value == 9);
271+
test "Testing operations on empty trees" {
272+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
273+
defer _ = gpa.deinit();
274+
var allocator = gpa.allocator();
275+
276+
var t = BinarySearchTree(i32){ .allocator = &allocator };
277+
defer t.destroy();
278+
279+
try testing.expect(t.size == 0);
280+
try testing.expect(t.search(10) == false);
281+
try t.remove(10);
282+
try testing.expect(t.search(10) == false);
82283
}

0 commit comments

Comments
 (0)