Skip to content

Commit fe4fa6c

Browse files
GabenoobCopilot
andauthored
Add queue data structure implementation with tests (#33)
* Add queue data structure implementation with tests * Update dataStructures/queue.zig Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 0a0da29 commit fe4fa6c

4 files changed

Lines changed: 133 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Every project is managed by the `build.zig` file.
1919
│ ├── doublyLinkedList.zig
2020
│ ├── linkedList.zig
2121
│ ├── lruCache.zig
22+
│ ├── queue.zig
2223
│ ├── stack.zig
2324
│ └── trie.zig
2425
├── dynamicProgramming

build.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ pub fn build(b: *std.Build) void {
109109
.name = "stack.zig",
110110
.category = "dataStructures",
111111
});
112+
if (std.mem.eql(u8, op, "ds/queue"))
113+
buildAlgorithm(b, .{
114+
.optimize = optimize,
115+
.target = target,
116+
.name = "queue.zig",
117+
.category = "dataStructures",
118+
});
112119

113120
// Dynamic Programming algorithms
114121
if (std.mem.eql(u8, op, "dp/coinChange"))

dataStructures/queue.zig

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
const std = @import("std");
2+
const testing = std.testing;
3+
4+
const errors = error{EmptyList};
5+
6+
// Returns a queue instance.
7+
// Arguments:
8+
// T: the type of the info(i.e. i32, i16, u8, etc...)
9+
// Allocator: This is needed for the struct instance. In most cases,
10+
// feel free to use std.heap.GeneralPurposeAllocator
11+
pub fn queue(comptime T: type) type {
12+
return struct {
13+
const Self = @This();
14+
15+
// This is the node struct. It holds:
16+
// info: T
17+
// next: A pointer to the next element
18+
// prev: A pointer to the previous element
19+
pub const node = struct {
20+
info: T,
21+
next: ?*node = null,
22+
prev: ?*node = null,
23+
};
24+
25+
allocator: std.mem.Allocator,
26+
head: ?*node = null,
27+
tail: ?*node = null,
28+
size: usize = 0,
29+
30+
// Function that inserts elements to the queue (enqueue)
31+
// Runs in O(1)
32+
// Arguments:
33+
// key: T - the key to be inserted to the queue
34+
pub fn push(self: *Self, key: T) !void {
35+
const nn = try self.allocator.create(node);
36+
nn.* = node{ .info = key };
37+
38+
if (self.tail == null) {
39+
self.head = nn;
40+
self.tail = nn;
41+
} else {
42+
self.tail.?.next = nn;
43+
nn.prev = self.tail;
44+
self.tail = nn;
45+
}
46+
self.size += 1;
47+
}
48+
49+
// Function that returns the front of the queue
50+
// Runs in O(1)
51+
// Returns an EmptyList error if the list is empty
52+
pub fn front(self: *Self) errors!T {
53+
return if (self.head != null) self.head.?.info else errors.EmptyList;
54+
}
55+
56+
// Function that removes the front of the queue (dequeue)
57+
// Runs in O(1)
58+
// Returns an EmptyList error if the list is empty
59+
pub fn pop(self: *Self) errors!void {
60+
if (self.head == null) {
61+
return errors.EmptyList;
62+
}
63+
64+
const curr: *node = self.head.?;
65+
defer self.allocator.destroy(curr);
66+
67+
self.head = self.head.?.next;
68+
if (self.head == null) {
69+
self.tail = null;
70+
} else {
71+
self.head.?.prev = null;
72+
}
73+
self.size -= 1;
74+
}
75+
76+
// Function that destroys the allocated memory of the whole queue
77+
pub fn destroy(self: *Self) !void {
78+
while (self.size != 0) : (try self.pop()) {}
79+
}
80+
};
81+
}
82+
83+
test "Testing insertion/popping in queue" {
84+
const allocator = std.testing.allocator;
85+
86+
var q = queue(i32){ .allocator = allocator };
87+
88+
try q.push(10);
89+
try q.push(20);
90+
try q.push(30);
91+
try testing.expect(try q.front() == 10);
92+
try testing.expect(q.size == 3);
93+
try q.pop();
94+
try testing.expect(try q.front() == 20);
95+
try testing.expect(q.size == 2);
96+
try q.pop();
97+
try testing.expect(try q.front() == 30);
98+
try testing.expect(q.size == 1);
99+
try q.pop();
100+
q.pop() catch |err| {
101+
try testing.expect(err == errors.EmptyList);
102+
return;
103+
};
104+
try testing.expect(q.size == 0);
105+
try q.destroy();
106+
}
107+
108+
test "Testing other formats" {
109+
const allocator = std.testing.allocator;
110+
111+
var q = queue(u8){ .allocator = allocator };
112+
113+
try q.push('a');
114+
try q.push('b');
115+
try q.push('c');
116+
117+
try testing.expect(try q.front() == 'a');
118+
try q.pop();
119+
try testing.expect(try q.front() == 'b');
120+
try q.push('w');
121+
try testing.expect(try q.front() == 'b');
122+
123+
try q.destroy();
124+
}

runall.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn main() !void {
2020
try runTest(allocator, "ds/doublylinkedlist");
2121
try runTest(allocator, "ds/lrucache");
2222
try runTest(allocator, "ds/stack");
23+
try runTest(allocator, "ds/queue");
2324

2425
// Dynamic Programming
2526
try runTest(allocator, "dp/coinChange");

0 commit comments

Comments
 (0)