Add examples for Zig language (#242)
* add zig examples * improved zig binary search This commit improves the binary search code in zig. The function has been made generic and the logic has been cleaned up a bit. The code has been updated to work with zig versions >= 0.9 * simplify zig selection sort This commit simplifies the logic of the zig selection sort. It now swaps in place the elements of the array instead of creating another array. This avoids allocating heap memory. The code has also been upgraded to zig version 0.9.1 * make zig recursion examples generic This commit modifies the zig examples for the recursion chapter to be generic. It also updates the code to zig version 0.9.1 * update chapter 4 examples This commit updates the zig examples in chapter 4. In particular examples have been made generic where possible. The code has been updated to zig version 0.9.1 * update zig hash table examples This commit updates the examples for the chapter 5 about hash tables. Some improvements have been done (using a set instead of a map). The code has been updated to zig version 0.9.1 * update breadth first search zig example This commit updates the zig example for the breadth first search algorithm. It adds a unit test and updates the code to zig version 0.9.1 * revamp zig dijkstra example * add comments in dijkstra zig * fix zig greedy algorithm * add test for zig dijkstra * add test for zig greedy algorithm * improve zig chapter 9 exercise This commit improves the zig exercise to comput the longest common subsequence. A main function has been added and the allocator code has been extracted from the `subsequence` function.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,6 +27,7 @@ highlights/node_modules
|
||||
highlights/atom-language-perl6/
|
||||
.DS_store
|
||||
highlights/package-lock.json
|
||||
zig-cache
|
||||
|
||||
# IDE specific
|
||||
.scala_dependencies
|
||||
@@ -41,4 +42,4 @@ highlights/package-lock.json
|
||||
/.env
|
||||
atlassian-ide-plugin.xml
|
||||
__pycache__
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
36
01_introduction_to_algorithms/zig/binary-search.zig
Normal file
36
01_introduction_to_algorithms/zig/binary-search.zig
Normal file
@@ -0,0 +1,36 @@
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
const my_list = &[_]i8{ 1, 3, 5, 7, 9 };
|
||||
|
||||
print("{?}\n", .{binarySearch(i8, my_list, 3)});
|
||||
print("{?}\n", .{binarySearch(i8, my_list, -1)});
|
||||
}
|
||||
|
||||
fn binarySearch(comptime T: type, list: []const T, item: T) ?usize {
|
||||
var low: i32 = 0;
|
||||
var high: i32 = @intCast(i32, list.len) - 1;
|
||||
|
||||
return while (low <= high) {
|
||||
var mid = @divTrunc((low + high), 2);
|
||||
var m = @intCast(usize, mid);
|
||||
var guess = list[m];
|
||||
if (guess == item) break m;
|
||||
if (guess > item) {
|
||||
high = mid - 1;
|
||||
} else low = mid + 1;
|
||||
} else null;
|
||||
}
|
||||
|
||||
test "binarySearch" {
|
||||
const my_list = &[_]i8{ 1, 3, 5, 7, 9 };
|
||||
|
||||
var i = binarySearch(i8, my_list, 3);
|
||||
try expect(i != null);
|
||||
try expect(i.? == 1);
|
||||
|
||||
i = binarySearch(i8, my_list, -1);
|
||||
try expect(i == null);
|
||||
}
|
||||
35
02_selection_sort/zig/selection_sort.zig
Normal file
35
02_selection_sort/zig/selection_sort.zig
Normal file
@@ -0,0 +1,35 @@
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
pub fn main() !void {
|
||||
var s = [_]i32{ 5, 3, 6, 2, 10 };
|
||||
|
||||
selectionSort(i32, s[0..]);
|
||||
print("{d}\n", .{s});
|
||||
}
|
||||
|
||||
fn selectionSort(comptime T: type, list: []T) void {
|
||||
for (list) |_, i| {
|
||||
var j = i + 1;
|
||||
while (j < list.len) : (j += 1) {
|
||||
if (list[i] > list[j]) {
|
||||
// swap
|
||||
var tmp = list[i];
|
||||
list[i] = list[j];
|
||||
list[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "selectionSort" {
|
||||
var s = [_]i32{ 5, 3, 6, 2, 10 };
|
||||
const exp = [_]i32{ 2, 3, 5, 6, 10 };
|
||||
|
||||
selectionSort(i32, s[0..]);
|
||||
|
||||
try expect(s.len == exp.len);
|
||||
for (s) |e, i|
|
||||
try expect(e == exp[i]);
|
||||
}
|
||||
13
03_recursion/zig/01_countdown.zig
Normal file
13
03_recursion/zig/01_countdown.zig
Normal file
@@ -0,0 +1,13 @@
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
fn countdown(comptime T: type, i: T) void {
|
||||
print("{} ", .{i});
|
||||
if (i <= 0) {
|
||||
print("\n", .{});
|
||||
return;
|
||||
} else countdown(T, i - 1);
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
countdown(u32, 5);
|
||||
}
|
||||
20
03_recursion/zig/02_greet.zig
Normal file
20
03_recursion/zig/02_greet.zig
Normal file
@@ -0,0 +1,20 @@
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
pub fn main() void {
|
||||
greet("adit");
|
||||
}
|
||||
|
||||
fn bye() void {
|
||||
print("ok bye!\n", .{});
|
||||
}
|
||||
|
||||
fn greet(name: []const u8) void {
|
||||
print("hello, {s}!\n", .{name});
|
||||
greet2(name);
|
||||
print("getting ready to say bye...\n", .{});
|
||||
bye();
|
||||
}
|
||||
|
||||
fn greet2(name: []const u8) void {
|
||||
print("how are you, {s}?\n", .{name});
|
||||
}
|
||||
11
03_recursion/zig/03_factorial.zig
Normal file
11
03_recursion/zig/03_factorial.zig
Normal file
@@ -0,0 +1,11 @@
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
fn fact(comptime T: type, x: T) T {
|
||||
if (x == 1) {
|
||||
return x;
|
||||
} else return x * fact(T, x - 1);
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
print("{}\n", .{fact(i32, 5)});
|
||||
}
|
||||
40
03_recursion/zig/04_count.zig
Normal file
40
03_recursion/zig/04_count.zig
Normal file
@@ -0,0 +1,40 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
var arr = [_]i32{ 4, 3, 2, 1 };
|
||||
print("{}\n", .{count(i32, arr[0..])});
|
||||
}
|
||||
|
||||
fn count(comptime T: type, arr: []T) T {
|
||||
if (arr.len == 0) {
|
||||
return 0;
|
||||
} else return 1 + count(T, arr[1..]);
|
||||
}
|
||||
|
||||
test "count" {
|
||||
var arr0 = [_]i32{};
|
||||
var arr1 = [_]i32{42};
|
||||
var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
var tests = [_]struct {
|
||||
arr: []i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &arr0,
|
||||
.exp = 0,
|
||||
},
|
||||
.{
|
||||
.arr = &arr1,
|
||||
.exp = 1,
|
||||
},
|
||||
.{
|
||||
.arr = &arr2,
|
||||
.exp = 9,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(count(@TypeOf(t.exp), t.arr) == t.exp);
|
||||
}
|
||||
}
|
||||
59
03_recursion/zig/05_binary_search_recursive.zig
Normal file
59
03_recursion/zig/05_binary_search_recursive.zig
Normal file
@@ -0,0 +1,59 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
print("{}\n", .{binarySearch(i32, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2)});
|
||||
}
|
||||
|
||||
fn binarySearch(comptime T: type, arr: []const T, target: T) bool {
|
||||
switch (arr.len) {
|
||||
0 => return false,
|
||||
1 => return arr[0] == target,
|
||||
else => {
|
||||
const mid = arr.len / 2;
|
||||
if (arr[mid] > target) {
|
||||
return binarySearch(T, arr[0..mid], target);
|
||||
} else {
|
||||
return binarySearch(T, arr[mid..], target);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test "binary search recursive" {
|
||||
const tests = [_]struct {
|
||||
arr: []const i32,
|
||||
target: i32,
|
||||
exp: bool,
|
||||
}{
|
||||
.{
|
||||
.arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.target = 7,
|
||||
.exp = true,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.target = 42,
|
||||
.exp = false,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{42},
|
||||
.target = 42,
|
||||
.exp = true,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{1},
|
||||
.target = 42,
|
||||
.exp = false,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{},
|
||||
.target = 42,
|
||||
.exp = false,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(binarySearch(@TypeOf(t.target), t.arr, t.target) == t.exp);
|
||||
}
|
||||
}
|
||||
47
03_recursion/zig/06_find_max.zig
Normal file
47
03_recursion/zig/06_find_max.zig
Normal file
@@ -0,0 +1,47 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })});
|
||||
}
|
||||
|
||||
fn findMax(comptime T: type, arr: []const T) T {
|
||||
switch (arr.len) {
|
||||
0 => return 0,
|
||||
1 => return arr[0],
|
||||
else => {
|
||||
const x = findMax(T, arr[1..]);
|
||||
if (arr[0] > x) {
|
||||
return arr[0];
|
||||
} else return x;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test "find max" {
|
||||
const tests = [_]struct {
|
||||
arr: []const i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &[_]i32{ 1, 2, 3, 4 },
|
||||
.exp = 4,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{ 8, 42, 3, 1 },
|
||||
.exp = 42,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{42},
|
||||
.exp = 42,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{},
|
||||
.exp = 0,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp);
|
||||
}
|
||||
}
|
||||
38
03_recursion/zig/07_sum_array.zig
Normal file
38
03_recursion/zig/07_sum_array.zig
Normal file
@@ -0,0 +1,38 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
print("{}\n", .{sumArray(i32, &[_]i32{ 1, 2, 3, 4 })});
|
||||
}
|
||||
|
||||
fn sumArray(comptime T: type, arr: []const T) T {
|
||||
switch (arr.len) {
|
||||
0 => return 0,
|
||||
1 => return arr[0],
|
||||
else => return arr[0] + sumArray(T, arr[1..]),
|
||||
}
|
||||
}
|
||||
|
||||
test "sum array" {
|
||||
const tests = [_]struct {
|
||||
arr: []const i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &[_]i32{ 1, 2, 3, 4 },
|
||||
.exp = 10,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{42},
|
||||
.exp = 42,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{},
|
||||
.exp = 0,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(sumArray(@TypeOf(t.exp), t.arr) == t.exp);
|
||||
}
|
||||
}
|
||||
38
04_quicksort/zig/01_loop_sum.zig
Normal file
38
04_quicksort/zig/01_loop_sum.zig
Normal file
@@ -0,0 +1,38 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
var arr = [_]i32{ 1, 2, 3, 4 };
|
||||
print("{}\n", .{sum(i32, &arr)});
|
||||
}
|
||||
|
||||
fn sum(comptime T: type, arr: []T) T {
|
||||
var total: T = 0;
|
||||
for (arr) |x| {
|
||||
total += x;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
test "sum" {
|
||||
var arr0 = [_]i32{ 1, 2, 3, 4 };
|
||||
var arr1 = [_]i32{};
|
||||
var tests = [_]struct {
|
||||
arr: []i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &arr0,
|
||||
.exp = 10,
|
||||
},
|
||||
.{
|
||||
.arr = &arr1,
|
||||
.exp = 0,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
var n = sum(@TypeOf(t.exp), t.arr);
|
||||
try expect(n == t.exp);
|
||||
}
|
||||
}
|
||||
37
04_quicksort/zig/02_recursive_sum.zig
Normal file
37
04_quicksort/zig/02_recursive_sum.zig
Normal file
@@ -0,0 +1,37 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
var list = [_]i32{ 1, 2, 3, 4 };
|
||||
print("{}\n", .{sum(i32, &list)});
|
||||
}
|
||||
|
||||
fn sum(comptime T: type, list: []T) T {
|
||||
if (list.len == 0) {
|
||||
return 0;
|
||||
}
|
||||
return list[0] + sum(T, list[1..]);
|
||||
}
|
||||
|
||||
test "sum" {
|
||||
var arr0 = [_]i32{ 1, 2, 3, 4 };
|
||||
var arr1 = [_]i32{};
|
||||
var tests = [_]struct {
|
||||
arr: []i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &arr0,
|
||||
.exp = 10,
|
||||
},
|
||||
.{
|
||||
.arr = &arr1,
|
||||
.exp = 0,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
var n = sum(@TypeOf(t.exp), t.arr);
|
||||
try expect(n == t.exp);
|
||||
}
|
||||
}
|
||||
40
04_quicksort/zig/03_recursive_count.zig
Normal file
40
04_quicksort/zig/03_recursive_count.zig
Normal file
@@ -0,0 +1,40 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
var arr = [_]i32{ 4, 3, 2, 1 };
|
||||
print("{}\n", .{count(i32, arr[0..])});
|
||||
}
|
||||
|
||||
fn count(comptime T: type, arr: []T) T {
|
||||
if (arr.len == 0) {
|
||||
return 0;
|
||||
} else return 1 + count(T, arr[1..]);
|
||||
}
|
||||
|
||||
test "count" {
|
||||
var arr0 = [_]i32{};
|
||||
var arr1 = [_]i32{42};
|
||||
var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
var tests = [_]struct {
|
||||
arr: []i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &arr0,
|
||||
.exp = 0,
|
||||
},
|
||||
.{
|
||||
.arr = &arr1,
|
||||
.exp = 1,
|
||||
},
|
||||
.{
|
||||
.arr = &arr2,
|
||||
.exp = 9,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(count(@TypeOf(t.exp), t.arr) == t.exp);
|
||||
}
|
||||
}
|
||||
47
04_quicksort/zig/04_recursive_max.zig
Normal file
47
04_quicksort/zig/04_recursive_max.zig
Normal file
@@ -0,0 +1,47 @@
|
||||
const print = @import("std").debug.print;
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
pub fn main() void {
|
||||
print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })});
|
||||
}
|
||||
|
||||
fn findMax(comptime T: type, arr: []const T) T {
|
||||
switch (arr.len) {
|
||||
0 => return 0,
|
||||
1 => return arr[0],
|
||||
else => {
|
||||
const x = findMax(T, arr[1..]);
|
||||
if (arr[0] > x) {
|
||||
return arr[0];
|
||||
} else return x;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test "find max" {
|
||||
const tests = [_]struct {
|
||||
arr: []const i32,
|
||||
exp: i32,
|
||||
}{
|
||||
.{
|
||||
.arr = &[_]i32{ 1, 2, 3, 4 },
|
||||
.exp = 4,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{ 8, 42, 3, 1 },
|
||||
.exp = 42,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{42},
|
||||
.exp = 42,
|
||||
},
|
||||
.{
|
||||
.arr = &[_]i32{},
|
||||
.exp = 0,
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp);
|
||||
}
|
||||
}
|
||||
79
04_quicksort/zig/05_quicksort.zig
Normal file
79
04_quicksort/zig/05_quicksort.zig
Normal file
@@ -0,0 +1,79 @@
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
const expect = std.testing.expect;
|
||||
const heap = std.heap;
|
||||
const mem = std.mem;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var s = [_]u8{ 5, 3, 6, 2, 10 };
|
||||
|
||||
print("{d}\n", .{try quicksort(u8, arena.allocator(), &s)});
|
||||
}
|
||||
|
||||
fn quicksort(comptime T: type, allocator: mem.Allocator, s: []const T) anyerror![]const T {
|
||||
// base case, arrays with 0 or 1 element are already "sorted"
|
||||
if (s.len < 2) {
|
||||
return s;
|
||||
}
|
||||
|
||||
var lower = std.ArrayList(T).init(allocator);
|
||||
var higher = std.ArrayList(T).init(allocator);
|
||||
|
||||
const pivot = s[0];
|
||||
for (s[1..]) |item| {
|
||||
if (item <= pivot) {
|
||||
try lower.append(item);
|
||||
} else {
|
||||
try higher.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
var low = try quicksort(T, allocator, lower.items);
|
||||
var high = try quicksort(T, allocator, higher.items);
|
||||
|
||||
var res = std.ArrayList(T).init(allocator);
|
||||
try res.appendSlice(low);
|
||||
try res.append(pivot);
|
||||
try res.appendSlice(high);
|
||||
|
||||
return res.items;
|
||||
}
|
||||
|
||||
test "quicksort" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
const tests = [_]struct {
|
||||
s: []const u8,
|
||||
exp: []const u8,
|
||||
}{
|
||||
.{
|
||||
.s = &[_]u8{},
|
||||
.exp = &[_]u8{},
|
||||
},
|
||||
.{
|
||||
.s = &[_]u8{42},
|
||||
.exp = &[_]u8{42},
|
||||
},
|
||||
.{
|
||||
.s = &[_]u8{ 3, 2, 1 },
|
||||
.exp = &[_]u8{ 1, 2, 3 },
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
var res = try quicksort(u8, arena.allocator(), t.s);
|
||||
try expect(res.len == t.exp.len);
|
||||
for (res) |e, i|
|
||||
try expect(e == t.exp[i]);
|
||||
}
|
||||
}
|
||||
86
04_quicksort/zig/06_quicksort_parallel.zig
Normal file
86
04_quicksort/zig/06_quicksort_parallel.zig
Normal file
@@ -0,0 +1,86 @@
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
const expect = std.testing.expect;
|
||||
const heap = std.heap;
|
||||
const mem = std.mem;
|
||||
|
||||
pub const io_mode = .evented;
|
||||
|
||||
pub const Error = error{OutOfMemory};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var s = [_]u8{ 5, 3, 6, 2, 10 };
|
||||
|
||||
print("{d}\n", .{try quicksort(arena.allocator(), &s)});
|
||||
}
|
||||
|
||||
// NOTE: this async version cannot be generic because allocating a frame for a
|
||||
// generic function is not trivial.
|
||||
fn quicksort(allocator: mem.Allocator, s: []const u8) Error![]const u8 {
|
||||
if (s.len < 2) {
|
||||
return s;
|
||||
}
|
||||
|
||||
var lower = std.ArrayList(u8).init(allocator);
|
||||
var higher = std.ArrayList(u8).init(allocator);
|
||||
|
||||
const pivot = s[0];
|
||||
for (s[1..]) |item| {
|
||||
if (item <= pivot) {
|
||||
try lower.append(item);
|
||||
} else {
|
||||
try higher.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
const low_frame = try allocator.create(@Frame(quicksort));
|
||||
low_frame.* = async quicksort(allocator, lower.items);
|
||||
var high = try quicksort(allocator, higher.items);
|
||||
var low = try await low_frame;
|
||||
|
||||
var res = std.ArrayList(u8).init(allocator);
|
||||
try res.appendSlice(low);
|
||||
try res.append(pivot);
|
||||
try res.appendSlice(high);
|
||||
|
||||
return res.items;
|
||||
}
|
||||
|
||||
test "quicksort" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
const tests = [_]struct {
|
||||
s: []const u8,
|
||||
exp: []const u8,
|
||||
}{
|
||||
.{
|
||||
.s = &[_]u8{},
|
||||
.exp = &[_]u8{},
|
||||
},
|
||||
.{
|
||||
.s = &[_]u8{42},
|
||||
.exp = &[_]u8{42},
|
||||
},
|
||||
.{
|
||||
.s = &[_]u8{ 3, 2, 1 },
|
||||
.exp = &[_]u8{ 1, 2, 3 },
|
||||
},
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
var res = try quicksort(arena.allocator(), t.s);
|
||||
try expect(res.len == t.exp.len);
|
||||
for (res) |e, i|
|
||||
try expect(e == t.exp[i]);
|
||||
}
|
||||
}
|
||||
22
05_hash_tables/zig/check_voter.zig
Normal file
22
05_hash_tables/zig/check_voter.zig
Normal file
@@ -0,0 +1,22 @@
|
||||
const std = @import("std");
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
|
||||
var map = std.StringHashMap(void).init(gpa.allocator());
|
||||
defer map.deinit();
|
||||
|
||||
try checkVoter(&map, "tom");
|
||||
try checkVoter(&map, "mike");
|
||||
try checkVoter(&map, "mike");
|
||||
}
|
||||
|
||||
fn checkVoter(voted: *std.StringHashMap(void), name: []const u8) !void {
|
||||
if (voted.contains(name)) {
|
||||
std.debug.print("kick them out!\n", .{});
|
||||
} else {
|
||||
try voted.put(name, {});
|
||||
std.debug.print("let them vote!\n", .{});
|
||||
}
|
||||
}
|
||||
19
05_hash_tables/zig/price_of_groceries.zig
Normal file
19
05_hash_tables/zig/price_of_groceries.zig
Normal file
@@ -0,0 +1,19 @@
|
||||
const std = @import("std");
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
|
||||
var map = std.StringHashMap(f32).init(gpa.allocator());
|
||||
defer map.deinit();
|
||||
|
||||
try map.put("apple", 0.67);
|
||||
try map.put("milk", 1.49);
|
||||
try map.put("avocado", 1.49);
|
||||
|
||||
var iterator = map.iterator();
|
||||
|
||||
while (iterator.next()) |entry| {
|
||||
std.debug.print("{s}: {d:.2}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
|
||||
}
|
||||
}
|
||||
114
06_breadth-first_search/zig/breadth_first_search.zig
Normal file
114
06_breadth-first_search/zig/breadth_first_search.zig
Normal file
@@ -0,0 +1,114 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
|
||||
var graph = std.StringHashMap([][]const u8).init(gpa.allocator());
|
||||
defer graph.deinit();
|
||||
|
||||
var you = [_][]const u8{ "alice", "bob", "claire" };
|
||||
var bob = [_][]const u8{ "anuj", "peggy" };
|
||||
var alice = [_][]const u8{"peggy"};
|
||||
var claire = [_][]const u8{ "thom", "jonny" };
|
||||
var anuj = [_][]const u8{};
|
||||
var peggy = [_][]const u8{};
|
||||
var thom = [_][]const u8{};
|
||||
var jonny = [_][]const u8{};
|
||||
|
||||
try graph.put("you", &you);
|
||||
try graph.put("bob", &bob);
|
||||
try graph.put("alice", &alice);
|
||||
try graph.put("claire", &claire);
|
||||
try graph.put("anuj", &anuj);
|
||||
try graph.put("peggy", &peggy);
|
||||
try graph.put("thom", &thom);
|
||||
try graph.put("jonny", &jonny);
|
||||
|
||||
try search(gpa.allocator(), &graph, "you");
|
||||
}
|
||||
|
||||
fn search(
|
||||
allocator: mem.Allocator,
|
||||
graph: *std.StringHashMap([][]const u8),
|
||||
name: []const u8,
|
||||
) !void {
|
||||
var arena = heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
var searched = std.BufSet.init(arena.allocator());
|
||||
const Q = std.TailQueue([]const u8);
|
||||
var queue = Q{};
|
||||
|
||||
var name_edges = graph.get(name);
|
||||
if (name_edges) |edges| {
|
||||
var nodes = try arena.allocator().alloc(Q.Node, edges.len);
|
||||
var i: usize = 0;
|
||||
while (i < edges.len) : (i += 1) {
|
||||
nodes[i].data = edges[i];
|
||||
}
|
||||
for (nodes) |*node| {
|
||||
queue.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.len > 0) {
|
||||
var first = queue.popFirst();
|
||||
if (first) |person| {
|
||||
if (!searched.contains(person.data)) {
|
||||
if (personIsSeller(person.data)) {
|
||||
std.debug.print("{s} is a mango seller!\n", .{person.data});
|
||||
return;
|
||||
} else {
|
||||
var ee = graph.get(person.data);
|
||||
if (ee) |edges| {
|
||||
var nodes = try arena.allocator().alloc(Q.Node, edges.len);
|
||||
var i: usize = 0;
|
||||
while (i < edges.len) : (i += 1) {
|
||||
nodes[i].data = edges[i];
|
||||
}
|
||||
for (nodes) |*node| {
|
||||
queue.append(node);
|
||||
}
|
||||
}
|
||||
try searched.insert(person.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn personIsSeller(name: []const u8) bool {
|
||||
return name[name.len - 1] == 'm';
|
||||
}
|
||||
|
||||
test "search" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
|
||||
var graph = std.StringHashMap([][]const u8).init(gpa.allocator());
|
||||
defer {
|
||||
graph.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
var you = [_][]const u8{ "alice", "bob", "claire" };
|
||||
var bob = [_][]const u8{ "anuj", "peggy" };
|
||||
var alice = [_][]const u8{"peggy"};
|
||||
var claire = [_][]const u8{ "thom", "jonny" };
|
||||
var anuj = [_][]const u8{};
|
||||
var peggy = [_][]const u8{};
|
||||
var thom = [_][]const u8{};
|
||||
var jonny = [_][]const u8{};
|
||||
|
||||
try graph.put("you", &you);
|
||||
try graph.put("bob", &bob);
|
||||
try graph.put("alice", &alice);
|
||||
try graph.put("claire", &claire);
|
||||
try graph.put("anuj", &anuj);
|
||||
try graph.put("peggy", &peggy);
|
||||
try graph.put("thom", &thom);
|
||||
try graph.put("jonny", &jonny);
|
||||
|
||||
try search(gpa.allocator(), &graph, "you");
|
||||
}
|
||||
161
07_dijkstras_algorithm/zig/dijkstras_algorithm.zig
Normal file
161
07_dijkstras_algorithm/zig/dijkstras_algorithm.zig
Normal file
@@ -0,0 +1,161 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator());
|
||||
|
||||
var start = std.StringHashMap(f32).init(arena.allocator());
|
||||
try start.put("a", 6);
|
||||
try start.put("b", 2);
|
||||
try graph.put("start", &start);
|
||||
|
||||
var a = std.StringHashMap(f32).init(arena.allocator());
|
||||
try a.put("finish", 1);
|
||||
try graph.put("a", &a);
|
||||
|
||||
var b = std.StringHashMap(f32).init(arena.allocator());
|
||||
try b.put("a", 3);
|
||||
try b.put("finish", 5);
|
||||
try graph.put("b", &b);
|
||||
|
||||
var fin = std.StringHashMap(f32).init(arena.allocator());
|
||||
try graph.put("finish", &fin);
|
||||
|
||||
var result = try dijkstra(arena.allocator(), &graph, "start", "finish");
|
||||
|
||||
std.debug.print("Cost from the start to each node:\n", .{});
|
||||
var costs_it = result.costs.iterator();
|
||||
while (costs_it.next()) |cost| {
|
||||
std.debug.print("{s}: {d} ", .{ cost.key_ptr.*, cost.value_ptr.* });
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("Path from start to finish:\n", .{});
|
||||
var path_it = result.path.iterator();
|
||||
while (path_it.next()) |parent| {
|
||||
std.debug.print("{s} = {?s}\n", .{ parent.key_ptr.*, parent.value_ptr.* });
|
||||
}
|
||||
}
|
||||
|
||||
/// this struct is needed because coercing an anonymous struct literal to an
|
||||
/// error union is not supported by zig yet. Once this is fixed (with the
|
||||
/// self-hosted compiler, see https://github.com/ziglang/zig/issues/11443), the
|
||||
/// dijkstra function could just return:
|
||||
/// ```zig
|
||||
/// return {
|
||||
/// .costs = costs,
|
||||
/// .path = parents,
|
||||
/// };
|
||||
/// ```
|
||||
const dijkstraResult = struct {
|
||||
costs: std.StringHashMap(f32),
|
||||
path: std.StringHashMap(?[]const u8),
|
||||
};
|
||||
|
||||
/// applies the dijkstra algorithm on the provided graph using
|
||||
/// the provided start anf finish nodes.
|
||||
fn dijkstra(
|
||||
allocator: mem.Allocator,
|
||||
graph: *std.StringHashMap(*std.StringHashMap(f32)),
|
||||
start: []const u8,
|
||||
finish: []const u8,
|
||||
) !dijkstraResult {
|
||||
var costs = std.StringHashMap(f32).init(allocator);
|
||||
var parents = std.StringHashMap(?[]const u8).init(allocator);
|
||||
try costs.put(finish, std.math.inf_f32);
|
||||
try parents.put(finish, null);
|
||||
|
||||
// initialize costs and parents maps for the nodes having start as parent
|
||||
var start_graph = graph.get(start);
|
||||
if (start_graph) |sg| {
|
||||
var it = sg.iterator();
|
||||
while (it.next()) |elem| {
|
||||
try costs.put(elem.key_ptr.*, elem.value_ptr.*);
|
||||
try parents.put(elem.key_ptr.*, start);
|
||||
}
|
||||
}
|
||||
|
||||
var processed = std.BufSet.init(allocator);
|
||||
|
||||
var n = findCheapestNode(&costs, &processed);
|
||||
while (n) |node| : (n = findCheapestNode(&costs, &processed)) {
|
||||
var cost = costs.get(node).?;
|
||||
var neighbors = graph.get(node);
|
||||
if (neighbors) |nbors| {
|
||||
var it = nbors.iterator();
|
||||
while (it.next()) |neighbor| {
|
||||
var new_cost = cost + neighbor.value_ptr.*;
|
||||
if (costs.get(neighbor.key_ptr.*).? > new_cost) {
|
||||
// update maps if we found a cheaper path
|
||||
try costs.put(neighbor.key_ptr.*, new_cost);
|
||||
try parents.put(neighbor.key_ptr.*, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
try processed.insert(node);
|
||||
}
|
||||
|
||||
return dijkstraResult{
|
||||
.costs = costs,
|
||||
.path = parents,
|
||||
};
|
||||
}
|
||||
|
||||
/// finds the cheapest node among the not yet processed ones.
|
||||
fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]const u8 {
|
||||
var lowest_cost = std.math.inf_f32;
|
||||
var lowest_cost_node: ?[]const u8 = null;
|
||||
|
||||
var it = costs.iterator();
|
||||
while (it.next()) |node| {
|
||||
if (node.value_ptr.* < lowest_cost and !processed.contains(node.key_ptr.*)) {
|
||||
lowest_cost = node.value_ptr.*;
|
||||
lowest_cost_node = node.key_ptr.*;
|
||||
}
|
||||
}
|
||||
|
||||
return lowest_cost_node;
|
||||
}
|
||||
|
||||
test "dijkstra" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator());
|
||||
|
||||
var start = std.StringHashMap(f32).init(arena.allocator());
|
||||
try start.put("a", 6);
|
||||
try start.put("b", 2);
|
||||
try graph.put("start", &start);
|
||||
|
||||
var a = std.StringHashMap(f32).init(arena.allocator());
|
||||
try a.put("finish", 1);
|
||||
try graph.put("a", &a);
|
||||
|
||||
var b = std.StringHashMap(f32).init(arena.allocator());
|
||||
try b.put("a", 3);
|
||||
try b.put("finish", 5);
|
||||
try graph.put("b", &b);
|
||||
|
||||
var fin = std.StringHashMap(f32).init(arena.allocator());
|
||||
try graph.put("finish", &fin);
|
||||
|
||||
var result = try dijkstra(arena.allocator(), &graph, "start", "finish");
|
||||
|
||||
try std.testing.expectEqual(result.costs.get("a").?, 5);
|
||||
try std.testing.expectEqual(result.costs.get("b").?, 2);
|
||||
try std.testing.expectEqual(result.costs.get("finish").?, 6);
|
||||
try std.testing.expectEqual(result.path.get("b").?, "start");
|
||||
try std.testing.expectEqual(result.path.get("a").?, "b");
|
||||
try std.testing.expectEqual(result.path.get("finish").?, "a");
|
||||
}
|
||||
158
08_greedy_algorithms/zig/set_covering.zig
Normal file
158
08_greedy_algorithms/zig/set_covering.zig
Normal file
@@ -0,0 +1,158 @@
|
||||
const std = @import("std");
|
||||
const heap = std.heap;
|
||||
const mem = std.mem;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" };
|
||||
var states_needed = std.BufSet.init(arena.allocator());
|
||||
for (states_needed_array) |sn| {
|
||||
try states_needed.insert(sn);
|
||||
}
|
||||
|
||||
var stations = std.StringHashMap(*std.BufSet).init(arena.allocator());
|
||||
|
||||
var kone = std.BufSet.init(arena.allocator());
|
||||
try kone.insert("id");
|
||||
try kone.insert("nv");
|
||||
try kone.insert("ut");
|
||||
try stations.put("kone", &kone);
|
||||
|
||||
var ktwo = std.BufSet.init(arena.allocator());
|
||||
try ktwo.insert("wa");
|
||||
try ktwo.insert("id");
|
||||
try ktwo.insert("mt");
|
||||
try stations.put("ktwo", &ktwo);
|
||||
|
||||
var kthree = std.BufSet.init(arena.allocator());
|
||||
try kthree.insert("or");
|
||||
try kthree.insert("nv");
|
||||
try kthree.insert("ca");
|
||||
try stations.put("kthree", &kthree);
|
||||
|
||||
var kfour = std.BufSet.init(arena.allocator());
|
||||
try kfour.insert("nv");
|
||||
try kfour.insert("ut");
|
||||
try stations.put("kfour", &kfour);
|
||||
|
||||
var kfive = std.BufSet.init(arena.allocator());
|
||||
try kfive.insert("ca");
|
||||
try kfive.insert("az");
|
||||
try stations.put("kfive", &kfive);
|
||||
|
||||
var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed);
|
||||
|
||||
for (stations_covering) |sc| {
|
||||
std.debug.print("{s}\n", .{sc});
|
||||
}
|
||||
}
|
||||
|
||||
fn setCovering(allocator: mem.Allocator, stations: *std.StringHashMap(*std.BufSet), states_needed: *std.BufSet) ![][]const u8 {
|
||||
var final_stations = std.BufSet.init(allocator);
|
||||
|
||||
while (states_needed.count() > 0) {
|
||||
var best_station: []const u8 = undefined;
|
||||
var states_covered: [][]const u8 = &[_][]const u8{};
|
||||
|
||||
var it = stations.iterator();
|
||||
while (it.next()) |station| {
|
||||
var covered = &std.ArrayList([]const u8).init(allocator);
|
||||
try intersect(states_needed, station.value_ptr.*, covered);
|
||||
if (covered.items.len > states_covered.len) {
|
||||
best_station = station.key_ptr.*;
|
||||
states_covered = covered.items;
|
||||
} else covered.deinit();
|
||||
}
|
||||
|
||||
difference(states_needed, states_covered);
|
||||
try final_stations.insert(best_station);
|
||||
}
|
||||
|
||||
var final_array = std.ArrayList([]const u8).init(allocator);
|
||||
var i = final_stations.iterator();
|
||||
while (i.next()) |key| {
|
||||
try final_array.append(key.*);
|
||||
}
|
||||
|
||||
return final_array.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn intersect(left: *std.BufSet, right: *std.BufSet, intersection: *std.ArrayList([]const u8)) !void {
|
||||
var l_it = left.iterator();
|
||||
var r_it = right.iterator();
|
||||
while (l_it.next()) |l| {
|
||||
while (r_it.next()) |r| {
|
||||
if (std.mem.eql(u8, l.*, r.*)) {
|
||||
try intersection.append(l.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn difference(lessening: *std.BufSet, subtracting: [][]const u8) void {
|
||||
var less_it = lessening.iterator();
|
||||
|
||||
while (less_it.next()) |less| {
|
||||
for (subtracting) |sub| {
|
||||
if (std.mem.eql(u8, less.*, sub)) {
|
||||
lessening.remove(less.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "setCovering" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" };
|
||||
var states_needed = std.BufSet.init(arena.allocator());
|
||||
for (states_needed_array) |sn| {
|
||||
try states_needed.insert(sn);
|
||||
}
|
||||
|
||||
var stations = std.StringHashMap(*std.BufSet).init(arena.allocator());
|
||||
|
||||
var kone = std.BufSet.init(arena.allocator());
|
||||
try kone.insert("id");
|
||||
try kone.insert("nv");
|
||||
try kone.insert("ut");
|
||||
try stations.put("kone", &kone);
|
||||
|
||||
var ktwo = std.BufSet.init(arena.allocator());
|
||||
try ktwo.insert("wa");
|
||||
try ktwo.insert("id");
|
||||
try ktwo.insert("mt");
|
||||
try stations.put("ktwo", &ktwo);
|
||||
|
||||
var kthree = std.BufSet.init(arena.allocator());
|
||||
try kthree.insert("or");
|
||||
try kthree.insert("nv");
|
||||
try kthree.insert("ca");
|
||||
try stations.put("kthree", &kthree);
|
||||
|
||||
var kfour = std.BufSet.init(arena.allocator());
|
||||
try kfour.insert("nv");
|
||||
try kfour.insert("ut");
|
||||
try stations.put("kfour", &kfour);
|
||||
|
||||
var kfive = std.BufSet.init(arena.allocator());
|
||||
try kfive.insert("ca");
|
||||
try kfive.insert("az");
|
||||
try stations.put("kfive", &kfive);
|
||||
|
||||
var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed);
|
||||
|
||||
var expectedStations = &[_][]const u8{ "kone", "ktwo", "kfive", "kthree" };
|
||||
for (stations_covering) |sc, i| {
|
||||
try std.testing.expectEqualStrings(expectedStations[i], sc);
|
||||
}
|
||||
}
|
||||
63
09_dynamic_programming/zig/longest_common_subsequence.zig
Normal file
63
09_dynamic_programming/zig/longest_common_subsequence.zig
Normal file
@@ -0,0 +1,63 @@
|
||||
const std = @import("std");
|
||||
const heap = std.heap;
|
||||
const math = std.math;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var n = try subsequence(arena.allocator(), "fish", "fosh");
|
||||
std.debug.print("{d}\n", .{n});
|
||||
}
|
||||
|
||||
fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !u32 {
|
||||
var grid = try allocator.alloc([]u32, a.len + 1);
|
||||
|
||||
for (grid) |*row| {
|
||||
row.* = try allocator.alloc(u32, b.len + 1);
|
||||
for (row.*) |*cell| {
|
||||
cell.* = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var i: usize = 1;
|
||||
while (i <= a.len) : (i += 1) {
|
||||
var j: usize = 1;
|
||||
while (j <= b.len) : (j += 1) {
|
||||
if (a[i - 1] == b[j - 1]) {
|
||||
grid[i][j] = grid[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
grid[i][j] = math.max(grid[i][j - 1], grid[i - 1][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return grid[a.len][b.len];
|
||||
}
|
||||
|
||||
test "subsequence" {
|
||||
var tests = [_]struct {
|
||||
a: []const u8,
|
||||
b: []const u8,
|
||||
exp: u32,
|
||||
}{
|
||||
.{ .a = "abc", .b = "abcd", .exp = 3 },
|
||||
.{ .a = "pera", .b = "mela", .exp = 2 },
|
||||
.{ .a = "banana", .b = "kiwi", .exp = 0 },
|
||||
};
|
||||
|
||||
for (tests) |t| {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
var n = try subsequence(arena.allocator(), t.a, t.b);
|
||||
try expect(n == t.exp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user