Skip to content
This repository has been archived by the owner on Dec 13, 2024. It is now read-only.

Commit

Permalink
feat(zig): basic zig support
Browse files Browse the repository at this point in the history
  • Loading branch information
storopoli committed Oct 6, 2024
1 parent a1fba77 commit 8d95d6b
Show file tree
Hide file tree
Showing 32 changed files with 849 additions and 101 deletions.
7 changes: 3 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
{
"name": "Graphs and Algorithmic Complexity",
"image": "mcr.microsoft.com/devcontainers/base:alpine",

"postCreateCommand": "sudo apk update && sudo apk add just typst gdb",

"postCreateCommand": "sudo apk update && sudo apk add just typst gdb zig",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"vadimcn.vscode-lldb",
"ziglang.vscode-zig",
"myriad-dreamin.tinymist"
]
}
}
}
}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@

# C++
*.out
*.exe
*.exe

# Output
output/
32 changes: 0 additions & 32 deletions code/01-graphs-adjacency-list.c

This file was deleted.

57 changes: 0 additions & 57 deletions code/01-graphs-adjacency-matrix.c

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
139 changes: 139 additions & 0 deletions code/zig/01-graphs-eulerian_path.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const std = @import("std");
const print = std.debug.print;

/// Number of vertices in the graph
const N = 5;
/// Maximum length of the path
const MAX_PATH_LENGTH = 20;

/// Find Eulerian Path in a graph
///
/// # Parameters
///
/// - `graph`: Adjacency matrix of the graph
fn findPath(graph: *[N][N]i32) void {
var numofadj: [N]i32 = [_]i32{0} ** N;
var stack: [N]i32 = [_]i32{0} ** N;
var path: [MAX_PATH_LENGTH]i32 = [_]i32{0} ** MAX_PATH_LENGTH;
var top: usize = 0;
var path_length: usize = 0;

// Find out number of edges each vertex has
for (0..N) |i| {
for (0..N) |j| {
numofadj[i] += graph.*[i][j];
}
}

// Find out how many vertices have an odd number of edges
var startpoint: usize = 0;
var numofodd: i32 = 0;
var idx_i: usize = N;
while (idx_i > 0) : (idx_i -= 1) {
const idx = idx_i - 1;
if (@mod(numofadj[idx], 2) == 1) {
numofodd += 1;
startpoint = idx;
}
}

// If the number of vertices with odd number of edges is greater than two, return "No Solution".
if (numofodd > 2) {
print("No Solution\n", .{});
return;
}

// Initialize empty stack and path; take the starting current as discussed
var cur: usize = startpoint;

// Loop will run until there is an element in the stack or current vertex has some neighbor.
while (top > 0 or numofadj[cur] > 0) {
// If current node has no neighbors, add it to path and pop stack; set new current to the popped element
if (numofadj[cur] == 0) {
path[path_length] = @intCast(cur);
path_length += 1;
if (top > 0) {
top -= 1;
cur = @intCast(stack[top]);
} else {
break;
}
}
// If the current vertex has at least one neighbor, add the current vertex to stack,
// remove the edge between them, and set the current to its neighbor.
else {
for (0..N) |j| {
if (graph.*[cur][j] == 1) {
stack[top] = @intCast(cur);
top += 1;
graph.*[cur][j] = 0;
graph.*[j][cur] = 0;
numofadj[cur] -= 1;
numofadj[j] -= 1;
cur = j;
break;
}
}
}
}

// Add the last vertex to the path
path[path_length] = @intCast(cur);
path_length += 1;

// Print the path
var idx: usize = path_length;
while (idx > 0) : (idx -= 1) {
print("{d} -> ", .{path[idx - 1]});
}
print("\n", .{});
}

/// Main function
pub fn main() !void {
// Test case 1:
// 0 --- 1
// | | \
// | 2--3
// 4
var graph1: [N][N]i32 = .{
.{ 0, 1, 0, 0, 1 },
.{ 1, 0, 1, 1, 0 },
.{ 0, 1, 0, 1, 0 },
.{ 0, 1, 1, 0, 0 },
.{ 1, 0, 0, 0, 0 },
};

print("Test Case 1:\n", .{});
findPath(&graph1);

// Test case 2:
// 0 -- 1 -- 2
// /| / \ | \
// 3--4 5
var graph2: [N][N]i32 = .{
.{ 0, 1, 0, 1, 1 },
.{ 1, 0, 1, 0, 1 },
.{ 0, 1, 0, 1, 1 },
.{ 1, 0, 1, 0, 0 },
.{ 1, 1, 1, 0, 0 },
};

print("Test Case 2:\n", .{});
findPath(&graph2);

// Test case 3:
// 0 --- 1
// /|\ |\
// 2 4---5 3
var graph3: [N][N]i32 = .{
.{ 0, 1, 1, 0, 1 },
.{ 1, 0, 0, 1, 1 },
.{ 1, 0, 0, 1, 0 },
.{ 0, 1, 1, 0, 1 },
.{ 1, 1, 0, 1, 0 },
};

print("Test Case 3:\n", .{});
findPath(&graph3);
}
120 changes: 120 additions & 0 deletions code/zig/01-graphs_hamiltonian_cycle.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
const std = @import("std");
const print = std.debug.print;

/// Number of vertices in the graph
const N = 5;

/// A utility function to print the solution
fn printSolution(path: [N]i32) void {
print("Solution Exists: ", .{});
for (0..N) |i| {
print("{d} ", .{path[i]});
}
// Print the first vertex again to show the complete cycle
print("{d}\n\n", .{path[0]});
}

/// A utility function to check if the vertex `v` can be added at index `pos`
/// in the Hamiltonian cycle constructed so far (stored in `path`)
fn isSafe(v: i32, graph: *[N][N]i32, path: [N]i32, pos: usize) bool {
// Check if this vertex is an adjacent vertex of the previously added vertex.
if (graph.*[@intCast(path[pos - 1])][@intCast(v)] == 0) return false;

// Check if the vertex has already been included.
for (0..pos) |i| {
if (path[i] == v) return false;
}

return true;
}

/// A recursive utility function to solve the Hamiltonian cycle problem
fn hamiltonianCycleUtil(graph: *[N][N]i32, path: *[N]i32, pos: usize) bool {
// Base case: If all vertices are included in the Hamiltonian cycle
if (pos == N) {
// And if there is an edge from the last included vertex to the first vertex
if (graph.*[@intCast(path[pos - 1])][@intCast(path[0])] == 1) {
return true;
} else {
return false;
}
}

// Try different vertices as the next candidate in the Hamiltonian cycle.
// We don't try for 0 as we included 0 as the starting point in hamiltonianCycle()
for (1..N) |v| {
const v_int: i32 = @intCast(v);
// Check if this vertex can be added to the Hamiltonian cycle
if (isSafe(v_int, graph, path.*, pos)) {
path.*[pos] = v_int;

// Recur to construct the rest of the path
if (hamiltonianCycleUtil(graph, path, pos + 1))
return true;

// If adding vertex `v` doesn't lead to a solution, then remove it
path.*[pos] = -1;
}
}

// If no vertex can be added to the Hamiltonian cycle constructed so far,
// then return false
return false;
}

/// This function solves the Hamiltonian cycle problem using backtracking.
/// It mainly uses `hamiltonianCycleUtil()` to solve the problem.
/// It returns false if there is no Hamiltonian cycle possible,
/// otherwise returns true and prints the path.
fn hamiltonianCycle(graph: *[N][N]i32) bool {
var path: [N]i32 = [_]i32{-1} ** N;

// Let us put vertex 0 as the first vertex in the path.
// If there is a Hamiltonian cycle,
// then the path can be started from any point
// of the cycle as the graph is undirected
path[0] = 0;
if (!hamiltonianCycleUtil(graph, &path, 1)) {
print("Solution does not exist\n\n", .{});
return false;
}

printSolution(path);
return true;
}

/// Main function
pub fn main() !void {
// Test case 1:
// (0)--(1)--(2)
// | / \ |
// | / \ |
// | / \ |
// (3)-------(4)
var graph1: [N][N]i32 = .{
.{ 0, 1, 0, 1, 0 },
.{ 1, 0, 1, 1, 1 },
.{ 0, 1, 0, 0, 1 },
.{ 1, 1, 0, 0, 1 },
.{ 0, 1, 1, 1, 0 },
};

_ = hamiltonianCycle(&graph1);

// Test case 2:
// (0)--(1)--(2)
// | / \ |
// | / \ |
// | / \ |
// (3) (4)
var graph2: [N][N]i32 = .{
.{ 0, 1, 0, 1, 0 },
.{ 1, 0, 1, 1, 1 },
.{ 0, 1, 0, 0, 1 },
.{ 1, 1, 0, 0, 0 },
.{ 0, 1, 1, 0, 0 },
};

print("Test Case 2:\n", .{});
_ = hamiltonianCycle(&graph2);
}
Loading

0 comments on commit 8d95d6b

Please sign in to comment.