RosettaCodeData/Task/Tree-datastructures/Zig/tree-datastructures.zig

183 lines
5.2 KiB
Zig

const std = @import("std");
const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const print = std.debug.print;
pub const NestTree = struct {
name: []const u8,
children: ArrayList(NestTree),
allocator: Allocator,
pub fn init(allocator: Allocator, name: []const u8) !NestTree {
const owned_name = try allocator.dupe(u8, name);
return NestTree{
.name = owned_name,
.children = ArrayList(NestTree).init(allocator),
.allocator = allocator,
};
}
pub fn deinit(self: *NestTree) void {
for (self.children.items) |*child| {
child.deinit();
}
self.children.deinit();
self.allocator.free(self.name);
}
pub fn addChild(self: *NestTree, name: []const u8) !void {
const child = try NestTree.init(self.allocator, name);
try self.children.append(child);
}
pub fn getChildMut(self: *NestTree, index: usize) ?*NestTree {
if (index >= self.children.items.len) return null;
return &self.children.items[index];
}
pub fn printTree(self: *const NestTree) void {
self.printWithLevel(0);
}
fn printWithLevel(self: *const NestTree, level: usize) void {
var i: usize = 0;
while (i < level * 4) : (i += 1) {
print(" " , .{});
}
print("{s}\n", .{self.name});
for (self.children.items) |*child| {
child.printWithLevel(level + 1);
}
}
pub fn getName(self: *const NestTree) []const u8 {
return self.name;
}
pub fn getChildren(self: *const NestTree) []const NestTree {
return self.children.items;
}
pub fn equals(self: *const NestTree, other: *const NestTree) bool {
if (!std.mem.eql(u8, self.name, other.name)) return false;
if (self.children.items.len != other.children.items.len) return false;
for (self.children.items, other.children.items) |*child1, *child2| {
if (!child1.equals(child2)) return false;
}
return true;
}
};
pub const IndentTree = struct {
items: ArrayList(IndentItem),
allocator: Allocator,
const IndentItem = struct {
level: i32,
name: []const u8,
};
pub fn init(allocator: Allocator, nest: *const NestTree) !IndentTree {
var items = ArrayList(IndentItem).init(allocator);
const root_name = try allocator.dupe(u8, nest.getName());
try items.append(IndentItem{ .level = 0, .name = root_name });
var indent_tree = IndentTree{
.items = items,
.allocator = allocator,
};
try indent_tree.fromNest(nest, 0);
return indent_tree;
}
pub fn deinit(self: *IndentTree) void {
for (self.items.items) |item| {
self.allocator.free(item.name);
}
self.items.deinit();
}
fn fromNest(self: *IndentTree, nest: *const NestTree, level: i32) !void {
for (nest.getChildren()) |*child| {
const child_name = try self.allocator.dupe(u8, child.getName());
try self.items.append(IndentItem{ .level = level + 1, .name = child_name });
try self.fromNest(child, level + 1);
}
}
pub fn printTree(self: *const IndentTree) void {
for (self.items.items) |item| {
print("{} {s}\n", .{ item.level, item.name });
}
}
pub fn toNest(self: *const IndentTree) !NestTree {
if (self.items.items.len == 0) return error.EmptyIndentTree;
var nest = try NestTree.init(self.allocator, self.items.items[0].name);
_ = try self.toNestRecursive(&nest, 1, 0);
return nest;
}
fn toNestRecursive(self: *const IndentTree, nest: *NestTree, pos: usize, level: i32) !usize {
var current_pos = pos;
while (current_pos < self.items.items.len and self.items.items[current_pos].level == level + 1) {
try nest.addChild(self.items.items[current_pos].name);
const child_index = nest.children.items.len - 1;
if (nest.getChildMut(child_index)) |child| {
current_pos = try self.toNestRecursive(child, current_pos + 1, level + 1);
} else {
current_pos += 1;
}
}
return current_pos;
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var n = try NestTree.init(allocator, "RosettaCode");
defer n.deinit();
// Add children
try n.addChild("rocks");
try n.addChild("mocks");
// Access children by index to avoid borrowing issues
if (n.getChildMut(0)) |child1| {
try child1.addChild("code");
try child1.addChild("comparison");
try child1.addChild("wiki");
}
if (n.getChildMut(1)) |child2| {
try child2.addChild("trolling");
}
print("Initial nest format:\n" , .{});
n.printTree();
var i = try IndentTree.init(allocator, &n);
defer i.deinit();
print("\nIndent format:\n" , .{});
i.printTree();
var n2 = try i.toNest();
defer n2.deinit();
print("\nFinal nest format:\n" , .{} );
n2.printTree();
print("\nAre initial and final nest formats equal? {}\n", .{n.equals(&n2)});
}