From 9c7892c27c21877c502c7ccd964f089a9dcba7c5 Mon Sep 17 00:00:00 2001 From: Spiros Maggioros Date: Thu, 2 Jan 2025 22:23:40 +0200 Subject: [PATCH 1/4] Introducing binary search tree implementation --- dataStructures/binarySearchTree.zig | 241 ++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 dataStructures/binarySearchTree.zig diff --git a/dataStructures/binarySearchTree.zig b/dataStructures/binarySearchTree.zig new file mode 100644 index 0000000..be7fd66 --- /dev/null +++ b/dataStructures/binarySearchTree.zig @@ -0,0 +1,241 @@ +const std = @import("std"); +const print = std.debug.print; +const ArrayList = std.ArrayList; +const testing = std.testing; + +// Returns a binary search tree instance. +// Arguments: +// T: the type of the info(i.e. i32, i16, u32, etc...) +// Allocator: This is needed for the struct instance. In most cases, feel free +// to use std.heap.GeneralPurposeAllocator. +pub fn bst(comptime T: type) type { + return struct { + const Self = @This(); + + // This is the node struct. It holds: + // info: T + // right: A pointer to the right child + // left: A pointer to the left child + pub const node = struct { + info: T, + right: ?*node = null, + left: ?*node = null, + }; + + allocator: *std.mem.Allocator, + root: ?*node = null, + size: usize = 0, + + // Function to insert elements into the tree + // Runs in θ(logn)/O(n), uses the helper _insert private function + // Arguments: + // key: T - the key to be inserted into the tree + pub fn insert(self: *Self, key: T) !void { + self.root = try self._insert(self.root, key); + self.size += 1; + } + + // Function to remove elements from the tree + // Runs in θ(logn)/O(n), uses the helper _remove private function + // Arguments: + // key: T - the key to be removed from the tree + pub fn remove(self: *Self, key: T) !void { + if (self.root == null) { return; } + self.root = try self._remove(self.root, key); + self.size -= 1; + } + + // Function to search if a key exists in the tree + // Runs in θ(logn)/O(n), uses the helper _search private function + // Arguments: + // key: T - the key that will be searched + pub fn search(self: *Self, key: T) bool { + return _search(self.root, key); + } + + // Function that performs inorder traversal of the tree + pub fn inorder(self: *Self, path: *ArrayList(T)) !void { + if (self.root == null) { return; } + try self._inorder(self.root, path); + } + + // Function that performs preorder traversal of the tree + pub fn preorder(self: *Self, path: *ArrayList(T)) !void { + if (self.root == null) { return; } + try self._preorder(self.root, path); + } + + // Function that performs postorder traversal of the tree + pub fn postorder(self: *Self, path: *ArrayList(T)) !void { + if (self.root == null) { return; } + try self._postorder(self.root, path); + } + + // Function that destroys the allocated memory of the whole tree + // Uses the _destroy helper private function + pub fn destroy(self: *Self) void { + if (self.root == null) { return; } + self._destroy(self.root); + self.size = 0; + } + + // Function that generates a new node + // Arguments: + // key: T - The info of the node + fn new_node(self: *Self, key: T) !?*node { + const nn = try self.allocator.create(node); + nn.* = node { .info = key, .right = null, .left = null }; + return nn; + } + + fn _insert(self: *Self, root: ?*node, key: T) !?*node { + if(root == null) { + return try self.new_node(key); + } + else { + if (root.?.info < key) { + root.?.right = try self._insert(root.?.right, key); + } + else { + root.?.left = try self._insert(root.?.left, key); + } + } + + return root; + } + + fn _remove(self: *Self, root: ?*node, key: T) !?*node { + if (root == null) { + return root; + } + + if (root.?.info < key) { + root.?.right = try self._remove(root.?.right, key); + } + else if (root.?.info > key) { + root.?.left = try self._remove(root.?.left, key); + } + else { + if (root.?.left == null and root.?.right == null) { + self.allocator.destroy(root.?); + return null; + } + else if (root.?.left == null) { + const temp = root.?.right; + self.allocator.destroy(root.?); + return temp; + } + else if (root.?.right == null) { + const temp = root.?.left; + self.allocator.destroy(root.?); + return temp; + } + else { + var curr: ?*node = root.?.right; + while (curr.?.left != null) : (curr = curr.?.left) { } + root.?.info = curr.?.info; + root.?.right = try self._remove(root.?.right, curr.?.info); + } + } + + return root; + } + + fn _search(root: ?*node, key: T) bool { + var head: ?*node = root; + while (head) |curr| { + if (curr.info < key) { + head = curr.right; + } + else if (curr.info > key) { + head = curr.left; + } + else { + return true; + } + } + + return false; + } + + fn _inorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { + if (root != null) { + try self._inorder(root.?.left, path); + try path.append(root.?.info); + try self._inorder(root.?.right, path); + } + } + + fn _preorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { + if (root != null) { + try path.append(root.?.info); + try self._preorder(root.?.left, path); + try self._preorder(root.?.right, path); + } + } + + fn _postorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { + if (root != null) { + try self._postorder(root.?.left, path); + try self._postorder(root.?.right, path); + try path.append(root.?.info); + } + } + + fn _destroy(self: *Self, root: ?*node) void { + if(root != null) { + self._destroy(root.?.left); + self._destroy(root.?.right); + self.allocator.destroy(root.?); + } + } + }; +} + +test "Testing Binary Search Tree" { + var gpa = std.heap.GeneralPurposeAllocator(.{}) {}; + defer _ = gpa.deinit(); + var allocator = gpa.allocator(); + + var t = bst(i32) { .allocator = &allocator }; + defer t.destroy(); + + try t.insert(10); + try t.insert(5); + try t.insert(25); + try t.insert(3); + try t.insert(12); + try testing.expect(t.size == 5); + try testing.expect(t.search(10) == true); + try testing.expect(t.search(15) == false); + try t.insert(15); + try testing.expect(t.size == 6); + try testing.expect(t.search(15) == true); + try t.remove(10); + try testing.expect(t.size == 5); + try testing.expect(t.search(10) == false); + + var ino = ArrayList(i32).init(allocator); + defer ino.deinit(); + + const check_ino = [_]i32{3, 5, 12, 15, 25}; + try t.inorder(&ino); + try testing.expect(std.mem.eql(i32, ino.items, &check_ino)); + + var pre = ArrayList(i32).init(allocator); + defer pre.deinit(); + + const check_pre = [_]i32{12, 5, 3, 25, 15}; + try t.preorder(&pre); + + try testing.expect(std.mem.eql(i32, pre.items, &check_pre)); + + var post = ArrayList(i32).init(allocator); + defer post.deinit(); + + const check_post = [_]i32{3, 5, 15, 25, 12}; + try t.postorder(&post); + + try testing.expect(std.mem.eql(i32, post.items, &check_post)); +} + From 7b9c618f0eb5add71e0fb39e4ece1c2959fa2da4 Mon Sep 17 00:00:00 2001 From: Spiros Maggioros Date: Thu, 2 Jan 2025 22:46:52 +0200 Subject: [PATCH 2/4] Changed container name to match previous work --- dataStructures/binarySearchTree.zig | 74 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/dataStructures/binarySearchTree.zig b/dataStructures/binarySearchTree.zig index be7fd66..9c9683c 100644 --- a/dataStructures/binarySearchTree.zig +++ b/dataStructures/binarySearchTree.zig @@ -8,7 +8,7 @@ const testing = std.testing; // T: the type of the info(i.e. i32, i16, u32, etc...) // Allocator: This is needed for the struct instance. In most cases, feel free // to use std.heap.GeneralPurposeAllocator. -pub fn bst(comptime T: type) type { +pub fn BinarySearchTree(comptime T: type) type { return struct { const Self = @This(); @@ -40,7 +40,9 @@ pub fn bst(comptime T: type) type { // Arguments: // key: T - the key to be removed from the tree pub fn remove(self: *Self, key: T) !void { - if (self.root == null) { return; } + if (self.root == null) { + return; + } self.root = try self._remove(self.root, key); self.size -= 1; } @@ -55,26 +57,34 @@ pub fn bst(comptime T: type) type { // Function that performs inorder traversal of the tree pub fn inorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { return; } + if (self.root == null) { + return; + } try self._inorder(self.root, path); } // Function that performs preorder traversal of the tree pub fn preorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { return; } + if (self.root == null) { + return; + } try self._preorder(self.root, path); } // Function that performs postorder traversal of the tree pub fn postorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { return; } + if (self.root == null) { + return; + } try self._postorder(self.root, path); } // Function that destroys the allocated memory of the whole tree // Uses the _destroy helper private function pub fn destroy(self: *Self) void { - if (self.root == null) { return; } + if (self.root == null) { + return; + } self._destroy(self.root); self.size = 0; } @@ -84,19 +94,17 @@ pub fn bst(comptime T: type) type { // key: T - The info of the node fn new_node(self: *Self, key: T) !?*node { const nn = try self.allocator.create(node); - nn.* = node { .info = key, .right = null, .left = null }; + nn.* = node{ .info = key, .right = null, .left = null }; return nn; } fn _insert(self: *Self, root: ?*node, key: T) !?*node { - if(root == null) { + if (root == null) { return try self.new_node(key); - } - else { + } else { if (root.?.info < key) { root.?.right = try self._insert(root.?.right, key); - } - else { + } else { root.?.left = try self._insert(root.?.left, key); } } @@ -111,28 +119,23 @@ pub fn bst(comptime T: type) type { if (root.?.info < key) { root.?.right = try self._remove(root.?.right, key); - } - else if (root.?.info > key) { + } else if (root.?.info > key) { root.?.left = try self._remove(root.?.left, key); - } - else { + } else { if (root.?.left == null and root.?.right == null) { self.allocator.destroy(root.?); return null; - } - else if (root.?.left == null) { + } else if (root.?.left == null) { const temp = root.?.right; self.allocator.destroy(root.?); return temp; - } - else if (root.?.right == null) { + } else if (root.?.right == null) { const temp = root.?.left; self.allocator.destroy(root.?); return temp; - } - else { + } else { var curr: ?*node = root.?.right; - while (curr.?.left != null) : (curr = curr.?.left) { } + while (curr.?.left != null) : (curr = curr.?.left) {} root.?.info = curr.?.info; root.?.right = try self._remove(root.?.right, curr.?.info); } @@ -146,11 +149,9 @@ pub fn bst(comptime T: type) type { while (head) |curr| { if (curr.info < key) { head = curr.right; - } - else if (curr.info > key) { + } else if (curr.info > key) { head = curr.left; - } - else { + } else { return true; } } @@ -168,9 +169,9 @@ pub fn bst(comptime T: type) type { fn _preorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { if (root != null) { - try path.append(root.?.info); - try self._preorder(root.?.left, path); - try self._preorder(root.?.right, path); + try path.append(root.?.info); + try self._preorder(root.?.left, path); + try self._preorder(root.?.right, path); } } @@ -183,7 +184,7 @@ pub fn bst(comptime T: type) type { } fn _destroy(self: *Self, root: ?*node) void { - if(root != null) { + if (root != null) { self._destroy(root.?.left); self._destroy(root.?.right); self.allocator.destroy(root.?); @@ -193,11 +194,11 @@ pub fn bst(comptime T: type) type { } test "Testing Binary Search Tree" { - var gpa = std.heap.GeneralPurposeAllocator(.{}) {}; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); var allocator = gpa.allocator(); - var t = bst(i32) { .allocator = &allocator }; + var t = BinarySearchTree(i32){ .allocator = &allocator }; defer t.destroy(); try t.insert(10); @@ -218,14 +219,14 @@ test "Testing Binary Search Tree" { var ino = ArrayList(i32).init(allocator); defer ino.deinit(); - const check_ino = [_]i32{3, 5, 12, 15, 25}; + const check_ino = [_]i32{ 3, 5, 12, 15, 25 }; try t.inorder(&ino); try testing.expect(std.mem.eql(i32, ino.items, &check_ino)); var pre = ArrayList(i32).init(allocator); defer pre.deinit(); - const check_pre = [_]i32{12, 5, 3, 25, 15}; + const check_pre = [_]i32{ 12, 5, 3, 25, 15 }; try t.preorder(&pre); try testing.expect(std.mem.eql(i32, pre.items, &check_pre)); @@ -233,9 +234,8 @@ test "Testing Binary Search Tree" { var post = ArrayList(i32).init(allocator); defer post.deinit(); - const check_post = [_]i32{3, 5, 15, 25, 12}; + const check_post = [_]i32{ 3, 5, 15, 25, 12 }; try t.postorder(&post); try testing.expect(std.mem.eql(i32, post.items, &check_post)); } - From 9d37e606f241d6a998895b524c6b0201ec1109ea Mon Sep 17 00:00:00 2001 From: Spiros Maggioros Date: Thu, 2 Jan 2025 23:33:02 +0200 Subject: [PATCH 3/4] Introducing a complete doubly linked list implementation --- dataStructures/doublyLinkedList.zig | 226 ++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 dataStructures/doublyLinkedList.zig diff --git a/dataStructures/doublyLinkedList.zig b/dataStructures/doublyLinkedList.zig new file mode 100644 index 0000000..276a73c --- /dev/null +++ b/dataStructures/doublyLinkedList.zig @@ -0,0 +1,226 @@ +const std = @import("std"); +const print = std.debug.print; +const testing = std.testing; + +// Returns a doubly linked list instance. +// Arguments: +// T: the type of the info(i.e. i32, i16, u32, etc...) +// Allocator: This is needed for the struct instance. In most cases, feel free +// to use std.heap.GeneralPurposeAllocator +pub fn DoublyLinkedList(comptime T: type) type { + return struct { + const Self = @This(); + + // This is the node struct. It holds: + // info: T + // next: A pointer to the next element + // prev: A pointer to the previous element + pub const node = struct { + info: T, + next: ?*node = null, + prev: ?*node = null, + }; + + allocator: *std.mem.Allocator, + root: ?*node = null, + tail: ?*node = null, + size: usize = 0, + + // Function that inserts elements to the tail of the list + // Runs in O(1) + // Arguments: + // key: T - the key to be inserted to the list + pub fn push_back(self: *Self, key: T) !void { + const nn = try self.allocator.create(node); + nn.* = node{ .info = key, .next = null, .prev = self.tail }; + + if (self.tail != null) { + self.tail.?.next = nn; + } + if (self.root == null) { + self.root = nn; + } + + self.tail = nn; + self.size += 1; + } + + // Function that inserts elements to the front of the list + // Runs in O(1) + // Arguments: + // key: T - the key to be inserted to the list + pub fn push_front(self: *Self, key: T) !void { + const nn = try self.allocator.create(node); + nn.* = node{ .info = key, .next = self.root, .prev = null }; + + if (self.root != null) { + self.root.?.prev = nn; + } + if (self.tail == null) { + self.tail = nn; + } + + self.root = nn; + self.size += 1; + } + + // Function that removes the front of the list + // Runs in O(1) + pub fn pop_front(self: *Self) void { + if (self.root == null) { + return; + } + + const temp: *node = self.root.?; + defer self.allocator.destroy(temp); + + self.root = self.root.?.next; + self.size -= 1; + } + + // Function that removes the back of the list + // Runs in O(1) + pub fn pop_back(self: *Self) void { + if (self.root == null) { + return; + } + + const temp: *node = self.tail.?; + defer self.allocator.destroy(temp); + + self.tail = self.tail.?.prev; + + if (self.tail != null) { + self.tail.?.next = null; + } else { + self.root = null; + } + + self.size -= 1; + } + + // Function that returns true if the list is empty + pub fn empty(self: *Self) bool { + return (self.size == 0); + } + + // Function to search if a key exists in the list + // Runs in O(n) + // Arguments: + // key: T - the key that will be searched + pub fn search(self: *Self, key: T) bool { + if (self.root == null) { + return false; + } + + var head: ?*node = self.root; + while (head) |curr| { + if (curr.info == key) { + return true; + } + + head = curr.next; + } + + return false; + } + + // Function that removes elements from the list + // Runs in O(n) + // Arguments: + // key: T - the key to be removed from the list(if it exists) + pub fn remove(self: *Self, key: T) void { + if (self.root == null) { + return; + } + + var head: ?*node = self.root; + var prev: ?*node = null; + while (head) |curr| { + if (curr.info == key) { + const temp: *node = curr; + if (prev == null) { + self.root = self.root.?.next; + } else { + prev.?.next = curr.next; + } + + self.allocator.destroy(temp); + self.size -= 1; + return; + } + prev = curr; + head = curr.next.?; + } + } + + // Function that prints the list + pub fn printList(self: *Self) void { + if (self.root == null) { + return; + } + + var head: ?*node = self.root; + while (head) |curr| { + print("{} -> ", .{curr.info}); + head = curr.next; + } + print("\n", .{}); + } + + // Function that destroys the allocated memory of the whole list + pub fn destroy(self: *Self) void { + var head: ?*node = self.root; + + while (head) |curr| { + const next = curr.next; + self.allocator.destroy(curr); + head = next; + } + + self.root = null; + self.tail = null; + self.size = 0; + } + }; +} + +test "Testing Doubly Linked List" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + var allocator = gpa.allocator(); + + var list = DoublyLinkedList(i32){ .allocator = &allocator }; + defer list.destroy(); + + try list.push_front(10); + try list.push_front(20); + try list.push_front(30); + + try testing.expect(list.search(10) == true); + try testing.expect(list.search(30) == true); + + list.remove(20); + try testing.expect(list.search(20) == false); + + var list2 = DoublyLinkedList(i32){ .allocator = &allocator }; + defer list2.destroy(); + + inline for (0..4) |el| { + try list2.push_back(el); + } + + inline for (0..4) |el| { + try testing.expect(list2.search(el) == true); + } + + try testing.expect(list2.size == 4); + + list2.pop_front(); + try testing.expect(list2.search(0) == false); + + list2.pop_back(); + + try testing.expect(list2.size == 2); + try testing.expect(list2.search(3) == false); +} From 0092591fd307820a4424e3e5eada1916e145f57f Mon Sep 17 00:00:00 2001 From: Spiros Maggioros Date: Thu, 2 Jan 2025 23:33:55 +0200 Subject: [PATCH 4/4] Remove previous implemented stuff --- dataStructures/binarySearchTree.zig | 241 ---------------------------- 1 file changed, 241 deletions(-) delete mode 100644 dataStructures/binarySearchTree.zig diff --git a/dataStructures/binarySearchTree.zig b/dataStructures/binarySearchTree.zig deleted file mode 100644 index 9c9683c..0000000 --- a/dataStructures/binarySearchTree.zig +++ /dev/null @@ -1,241 +0,0 @@ -const std = @import("std"); -const print = std.debug.print; -const ArrayList = std.ArrayList; -const testing = std.testing; - -// Returns a binary search tree instance. -// Arguments: -// T: the type of the info(i.e. i32, i16, u32, etc...) -// Allocator: This is needed for the struct instance. In most cases, feel free -// to use std.heap.GeneralPurposeAllocator. -pub fn BinarySearchTree(comptime T: type) type { - return struct { - const Self = @This(); - - // This is the node struct. It holds: - // info: T - // right: A pointer to the right child - // left: A pointer to the left child - pub const node = struct { - info: T, - right: ?*node = null, - left: ?*node = null, - }; - - allocator: *std.mem.Allocator, - root: ?*node = null, - size: usize = 0, - - // Function to insert elements into the tree - // Runs in θ(logn)/O(n), uses the helper _insert private function - // Arguments: - // key: T - the key to be inserted into the tree - pub fn insert(self: *Self, key: T) !void { - self.root = try self._insert(self.root, key); - self.size += 1; - } - - // Function to remove elements from the tree - // Runs in θ(logn)/O(n), uses the helper _remove private function - // Arguments: - // key: T - the key to be removed from the tree - pub fn remove(self: *Self, key: T) !void { - if (self.root == null) { - return; - } - self.root = try self._remove(self.root, key); - self.size -= 1; - } - - // Function to search if a key exists in the tree - // Runs in θ(logn)/O(n), uses the helper _search private function - // Arguments: - // key: T - the key that will be searched - pub fn search(self: *Self, key: T) bool { - return _search(self.root, key); - } - - // Function that performs inorder traversal of the tree - pub fn inorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { - return; - } - try self._inorder(self.root, path); - } - - // Function that performs preorder traversal of the tree - pub fn preorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { - return; - } - try self._preorder(self.root, path); - } - - // Function that performs postorder traversal of the tree - pub fn postorder(self: *Self, path: *ArrayList(T)) !void { - if (self.root == null) { - return; - } - try self._postorder(self.root, path); - } - - // Function that destroys the allocated memory of the whole tree - // Uses the _destroy helper private function - pub fn destroy(self: *Self) void { - if (self.root == null) { - return; - } - self._destroy(self.root); - self.size = 0; - } - - // Function that generates a new node - // Arguments: - // key: T - The info of the node - fn new_node(self: *Self, key: T) !?*node { - const nn = try self.allocator.create(node); - nn.* = node{ .info = key, .right = null, .left = null }; - return nn; - } - - fn _insert(self: *Self, root: ?*node, key: T) !?*node { - if (root == null) { - return try self.new_node(key); - } else { - if (root.?.info < key) { - root.?.right = try self._insert(root.?.right, key); - } else { - root.?.left = try self._insert(root.?.left, key); - } - } - - return root; - } - - fn _remove(self: *Self, root: ?*node, key: T) !?*node { - if (root == null) { - return root; - } - - if (root.?.info < key) { - root.?.right = try self._remove(root.?.right, key); - } else if (root.?.info > key) { - root.?.left = try self._remove(root.?.left, key); - } else { - if (root.?.left == null and root.?.right == null) { - self.allocator.destroy(root.?); - return null; - } else if (root.?.left == null) { - const temp = root.?.right; - self.allocator.destroy(root.?); - return temp; - } else if (root.?.right == null) { - const temp = root.?.left; - self.allocator.destroy(root.?); - return temp; - } else { - var curr: ?*node = root.?.right; - while (curr.?.left != null) : (curr = curr.?.left) {} - root.?.info = curr.?.info; - root.?.right = try self._remove(root.?.right, curr.?.info); - } - } - - return root; - } - - fn _search(root: ?*node, key: T) bool { - var head: ?*node = root; - while (head) |curr| { - if (curr.info < key) { - head = curr.right; - } else if (curr.info > key) { - head = curr.left; - } else { - return true; - } - } - - return false; - } - - fn _inorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { - if (root != null) { - try self._inorder(root.?.left, path); - try path.append(root.?.info); - try self._inorder(root.?.right, path); - } - } - - fn _preorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { - if (root != null) { - try path.append(root.?.info); - try self._preorder(root.?.left, path); - try self._preorder(root.?.right, path); - } - } - - fn _postorder(self: *Self, root: ?*node, path: *ArrayList(T)) !void { - if (root != null) { - try self._postorder(root.?.left, path); - try self._postorder(root.?.right, path); - try path.append(root.?.info); - } - } - - fn _destroy(self: *Self, root: ?*node) void { - if (root != null) { - self._destroy(root.?.left); - self._destroy(root.?.right); - self.allocator.destroy(root.?); - } - } - }; -} - -test "Testing Binary Search Tree" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - var allocator = gpa.allocator(); - - var t = BinarySearchTree(i32){ .allocator = &allocator }; - defer t.destroy(); - - try t.insert(10); - try t.insert(5); - try t.insert(25); - try t.insert(3); - try t.insert(12); - try testing.expect(t.size == 5); - try testing.expect(t.search(10) == true); - try testing.expect(t.search(15) == false); - try t.insert(15); - try testing.expect(t.size == 6); - try testing.expect(t.search(15) == true); - try t.remove(10); - try testing.expect(t.size == 5); - try testing.expect(t.search(10) == false); - - var ino = ArrayList(i32).init(allocator); - defer ino.deinit(); - - const check_ino = [_]i32{ 3, 5, 12, 15, 25 }; - try t.inorder(&ino); - try testing.expect(std.mem.eql(i32, ino.items, &check_ino)); - - var pre = ArrayList(i32).init(allocator); - defer pre.deinit(); - - const check_pre = [_]i32{ 12, 5, 3, 25, 15 }; - try t.preorder(&pre); - - try testing.expect(std.mem.eql(i32, pre.items, &check_pre)); - - var post = ArrayList(i32).init(allocator); - defer post.deinit(); - - const check_post = [_]i32{ 3, 5, 15, 25, 12 }; - try t.postorder(&post); - - try testing.expect(std.mem.eql(i32, post.items, &check_post)); -}