mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-16 13:40:58 +00:00
Add ru version (#1865)
* Add Russian docs site baseline * Add Russian localized codebase * Polish Russian code wording * Update ru code translation. * Update code translation and chapter covers. * Fix pythontutor extraction. * Add README and landing page. * placeholder of profiles * Use figures of English version * Remove chapter paperbook
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
zig-out
|
||||
zig-cache
|
||||
.zig-cache
|
||||
!/.vscode/
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug",
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/zig-out/bin/${fileBasenameNoExtension}",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"preLaunchTask": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"zig.testArgs": ["build", "test", "-Dtest-filter=${filter}"]
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "zig build",
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// File: build.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
//! Zig Version: 0.14.1
|
||||
//! Build Command: zig build
|
||||
//! Run Command: zig build run | zig build run_*
|
||||
//! Test Command: zig build test | zig build test -Dtest-filter=*
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const chapters = [_][]const u8{
|
||||
"chapter_computational_complexity",
|
||||
"chapter_array_and_linkedlist",
|
||||
"chapter_stack_and_queue",
|
||||
"chapter_hashing",
|
||||
"chapter_tree",
|
||||
"chapter_heap",
|
||||
"chapter_searching",
|
||||
"chapter_sorting",
|
||||
"chapter_dynamic_programming",
|
||||
};
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{};
|
||||
|
||||
buildChapterExeModules(b, target, optimize, &chapters, test_step, test_filters);
|
||||
buildMainExeModule(b, target, optimize);
|
||||
}
|
||||
|
||||
fn buildChapterExeModules(
|
||||
b: *std.Build,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
chapter_dirs: []const []const u8,
|
||||
test_step: *std.Build.Step,
|
||||
test_filters: []const []const u8,
|
||||
) void {
|
||||
for (chapter_dirs) |chapter_dir_name| {
|
||||
const chapter_dir_path = std.fs.path.join(b.allocator, &[_][]const u8{chapter_dir_name}) catch continue;
|
||||
var chapter_dir = std.fs.cwd().openDir(chapter_dir_path, .{ .iterate = true }) catch continue;
|
||||
defer chapter_dir.close();
|
||||
|
||||
var it = chapter_dir.iterate();
|
||||
while (it.next() catch continue) |chapter_dir_entry| {
|
||||
if (chapter_dir_entry.kind != .file or !std.mem.endsWith(u8, chapter_dir_entry.name, ".zig")) continue;
|
||||
const exe_mod = buildExeModuleFromChapterDirEntry(b, target, optimize, chapter_dir_name, chapter_dir_entry) catch continue;
|
||||
addTestStepToExeModule(b, test_step, exe_mod, test_filters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn buildExeModuleFromChapterDirEntry(
|
||||
b: *std.Build,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
chapter_dir_name: []const u8,
|
||||
chapter_dir_entry: std.fs.Dir.Entry,
|
||||
) !*std.Build.Module {
|
||||
const zig_file_path = try std.fs.path.join(b.allocator, &[_][]const u8{ chapter_dir_name, chapter_dir_entry.name });
|
||||
const zig_file_name = chapter_dir_entry.name[0 .. chapter_dir_entry.name.len - 4]; // abstract zig file name from xxx.zig
|
||||
|
||||
// Здесь временно добавлены только главы про массивы и связные списки; после доработки будут открыты все
|
||||
const new_algo_names = [_][]const u8{
|
||||
"array",
|
||||
"linked_list",
|
||||
"list",
|
||||
"my_list",
|
||||
"iteration",
|
||||
"recursion",
|
||||
"space_complexity",
|
||||
"time_complexity",
|
||||
"worst_best_time_complexity",
|
||||
};
|
||||
var can_run = false;
|
||||
for (new_algo_names) |name| {
|
||||
if (std.mem.eql(u8, zig_file_name, name)) {
|
||||
can_run = true;
|
||||
}
|
||||
}
|
||||
if (!can_run) {
|
||||
return error.CanNotRunUseOldZigCodes;
|
||||
}
|
||||
|
||||
// std.debug.print("now run zig file name = {s}\n", .{zig_file_name});
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.root_source_file = b.path(zig_file_path),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = zig_file_name,
|
||||
.root_module = exe_mod,
|
||||
});
|
||||
|
||||
const utils_mod = createUtilsModule(b, target, optimize);
|
||||
exe_mod.addImport("utils", utils_mod);
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const step_name = try std.fmt.allocPrint(b.allocator, "run_{s}", .{zig_file_name});
|
||||
const step_desc = try std.fmt.allocPrint(b.allocator, "Run {s}/{s}.zig", .{ chapter_dir_name, zig_file_name });
|
||||
const run_step = b.step(step_name, step_desc);
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
return exe_mod;
|
||||
}
|
||||
|
||||
fn buildMainExeModule(
|
||||
b: *std.Build,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
) void {
|
||||
const exe_mod = b.createModule(.{
|
||||
.root_source_file = b.path("main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const utils_mod = createUtilsModule(b, target, optimize);
|
||||
exe_mod.addImport("utils", utils_mod);
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "main",
|
||||
.root_module = exe_mod,
|
||||
});
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run all hello algo zig");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
|
||||
fn createUtilsModule(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Module {
|
||||
const utils_mod = b.createModule(.{
|
||||
.root_source_file = b.path("utils/utils.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
return utils_mod;
|
||||
}
|
||||
|
||||
fn addTestStepToExeModule(b: *std.Build, test_step: *std.Build.Step, exe_mod: *std.Build.Module, test_filters: []const []const u8) void {
|
||||
const exe_unit_tests = b.addTest(.{
|
||||
.root_module = exe_mod,
|
||||
.filters = test_filters,
|
||||
});
|
||||
|
||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||
test_step.dependOn(&run_exe_unit_tests.step);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// File: array.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
|
||||
// Случайный доступ к элементу
|
||||
pub fn randomAccess(nums: []const i32) i32 {
|
||||
// Случайным образом выбрать целое число из интервала [0, nums.len)
|
||||
const random_index = std.crypto.random.intRangeLessThan(usize, 0, nums.len);
|
||||
// Получить и вернуть случайный элемент
|
||||
const randomNum = nums[random_index];
|
||||
return randomNum;
|
||||
}
|
||||
|
||||
// Увеличить длину массива
|
||||
pub fn extend(allocator: std.mem.Allocator, nums: []const i32, enlarge: usize) ![]i32 {
|
||||
// Инициализировать массив увеличенной длины
|
||||
const res = try allocator.alloc(i32, nums.len + enlarge);
|
||||
@memset(res, 0);
|
||||
|
||||
// Скопировать все элементы исходного массива в новый массив
|
||||
std.mem.copyForwards(i32, res, nums);
|
||||
|
||||
// Вернуть новый массив после расширения
|
||||
return res;
|
||||
}
|
||||
|
||||
// Вставить элемент num по индексу index в массив
|
||||
pub fn insert(nums: []i32, num: i32, index: usize) void {
|
||||
// Сдвинуть элемент с индексом index и все последующие элементы на одну позицию назад
|
||||
var i = nums.len - 1;
|
||||
while (i > index) : (i -= 1) {
|
||||
nums[i] = nums[i - 1];
|
||||
}
|
||||
// Присвоить num элементу по индексу index
|
||||
nums[index] = num;
|
||||
}
|
||||
|
||||
// Удалить элемент по индексу index
|
||||
pub fn remove(nums: []i32, index: usize) void {
|
||||
// Сдвинуть все элементы после индекса index на одну позицию вперед
|
||||
var i = index;
|
||||
while (i < nums.len - 1) : (i += 1) {
|
||||
nums[i] = nums[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Обход массива
|
||||
pub fn traverse(nums: []const i32) void {
|
||||
var count: i32 = 0;
|
||||
|
||||
// Обход массива по индексам
|
||||
var i: usize = 0;
|
||||
while (i < nums.len) : (i += 1) {
|
||||
count += nums[i];
|
||||
}
|
||||
|
||||
// Непосредственно обходить элементы массива
|
||||
count = 0;
|
||||
for (nums) |num| {
|
||||
count += num;
|
||||
}
|
||||
|
||||
// Одновременно обходить индексы и элементы данных
|
||||
for (nums, 0..) |num, index| {
|
||||
count += nums[index];
|
||||
count += num;
|
||||
}
|
||||
}
|
||||
|
||||
// Найти заданный элемент в массиве
|
||||
pub fn find(nums: []i32, target: i32) i32 {
|
||||
for (nums, 0..) |num, i| {
|
||||
if (num == target) return @intCast(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() !void {
|
||||
// Инициализация массива
|
||||
const arr = [_]i32{0} ** 5;
|
||||
std.debug.print("Массив arr = {}\n", .{utils.fmt.slice(&arr)});
|
||||
|
||||
// Срез массива
|
||||
var array = [_]i32{ 1, 3, 2, 5, 4 };
|
||||
var known_at_runtime_zero: usize = 0;
|
||||
_ = &known_at_runtime_zero;
|
||||
var nums = array[known_at_runtime_zero..array.len]; // Превратить указатель в срез через известную во время выполнения переменную known_at_runtime_zero
|
||||
std.debug.print("Массив nums = {}\n", .{utils.fmt.slice(nums)});
|
||||
|
||||
// Случайный доступ
|
||||
const randomNum = randomAccess(nums);
|
||||
std.debug.print("Случайный элемент из nums = {}\n", .{randomNum});
|
||||
|
||||
// Инициализация аллокатора памяти
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
|
||||
// Расширение длины
|
||||
nums = try extend(allocator, nums, 3);
|
||||
std.debug.print("После расширения длины массива до 8 nums = {}\n", .{utils.fmt.slice(nums)});
|
||||
|
||||
// Вставка элемента
|
||||
insert(nums, 6, 3);
|
||||
std.debug.print("После вставки числа 6 по индексу 3 nums = {}\n", .{utils.fmt.slice(nums)});
|
||||
|
||||
// Удаление элемента
|
||||
remove(nums, 2);
|
||||
std.debug.print("После удаления элемента по индексу 2 nums = {}\n", .{utils.fmt.slice(nums)});
|
||||
|
||||
// Обход массива
|
||||
traverse(nums);
|
||||
|
||||
// Поиск элемента
|
||||
const index = find(nums, 3);
|
||||
std.debug.print("Поиск элемента 3 в nums: индекс = {}\n", .{index});
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
try run();
|
||||
}
|
||||
|
||||
test "array" {
|
||||
try run();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// File: linked_list.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
const ListNode = utils.ListNode;
|
||||
|
||||
// Вставить узел P после узла n0 в связном списке
|
||||
pub fn insert(comptime T: type, n0: *ListNode(T), P: *ListNode(T)) void {
|
||||
const n1 = n0.next;
|
||||
P.next = n1;
|
||||
n0.next = P;
|
||||
}
|
||||
|
||||
// Удалить первый узел после узла n0 в связном списке
|
||||
pub fn remove(comptime T: type, n0: *ListNode(T)) void {
|
||||
// n0 -> P -> n1 => n0 -> n1
|
||||
const P = n0.next;
|
||||
const n1 = P.?.next;
|
||||
n0.next = n1;
|
||||
}
|
||||
|
||||
// Доступ к узлу связного списка по индексу index
|
||||
pub fn access(comptime T: type, node: *ListNode(T), index: i32) ?*ListNode(T) {
|
||||
var head: ?*ListNode(T) = node;
|
||||
var i: i32 = 0;
|
||||
while (i < index) : (i += 1) {
|
||||
if (head) |cur| {
|
||||
head = cur.next;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
// Найти в связном списке первый узел со значением target
|
||||
pub fn find(comptime T: type, node: *ListNode(T), target: T) i32 {
|
||||
var head: ?*ListNode(T) = node;
|
||||
var index: i32 = 0;
|
||||
while (head) |cur| {
|
||||
if (cur.val == target) return index;
|
||||
head = cur.next;
|
||||
index += 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() void {
|
||||
// Инициализация всех узлов
|
||||
var n0 = ListNode(i32){ .val = 1 };
|
||||
var n1 = ListNode(i32){ .val = 3 };
|
||||
var n2 = ListNode(i32){ .val = 2 };
|
||||
var n3 = ListNode(i32){ .val = 5 };
|
||||
var n4 = ListNode(i32){ .val = 4 };
|
||||
// Построить ссылки между узлами
|
||||
n0.next = &n1;
|
||||
n1.next = &n2;
|
||||
n2.next = &n3;
|
||||
n3.next = &n4;
|
||||
std.debug.print(
|
||||
"Инициализированный связный список = {}\n",\n .{utils.fmt.linkedList(i32, &n0)},\n);
|
||||
|
||||
// Вставка узла
|
||||
var tmp = ListNode(i32){ .val = 0 };
|
||||
insert(i32, &n0, &tmp);
|
||||
std.debug.print(
|
||||
"Связный список после вставки узла = {}\n",\n .{utils.fmt.linkedList(i32, &n0)},\n);
|
||||
|
||||
// Удаление узла
|
||||
remove(i32, &n0);
|
||||
std.debug.print(
|
||||
"Связный список после удаления узла = {}\n",\n .{utils.fmt.linkedList(i32, &n0)},\n);
|
||||
|
||||
// Доступ к узлу
|
||||
const node = access(i32, &n0, 3);
|
||||
std.debug.print(
|
||||
"Значение узла по индексу 3 в связном списке = {}\n",\n .{node.?.val},\n);
|
||||
|
||||
// Поиск узла
|
||||
const index = find(i32, &n0, 2);
|
||||
std.debug.print(
|
||||
"Индекс узла со значением 2 в связном списке = {}\n",\n .{index},\n);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
run();
|
||||
}
|
||||
|
||||
test "linked_list" {
|
||||
run();
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// File: list.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
|
||||
// Driver Code
|
||||
pub fn run() !void {
|
||||
// Инициализация списка
|
||||
var nums = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer nums.deinit(); // Отложенное освобождение памяти
|
||||
|
||||
try nums.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 });
|
||||
std.debug.print("Список nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Доступ к элементу
|
||||
const num = nums.items[1];
|
||||
std.debug.print("Элемент по индексу 1: num = {}\n", .{num});
|
||||
|
||||
// Обновление элемента
|
||||
nums.items[1] = 0;
|
||||
std.debug.print("После обновления элемента по индексу 1 до 0 nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Очистить список
|
||||
nums.clearRetainingCapacity();
|
||||
std.debug.print("После очистки списка nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Добавление элемента в конец
|
||||
try nums.append(1);
|
||||
try nums.append(3);
|
||||
try nums.append(2);
|
||||
try nums.append(5);
|
||||
try nums.append(4);
|
||||
std.debug.print("После добавления элементов nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Вставка элемента в середину
|
||||
try nums.insert(3, 6);
|
||||
std.debug.print("После вставки числа 6 по индексу 3 nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Удаление элемента
|
||||
_ = nums.orderedRemove(3);
|
||||
std.debug.print("После удаления элемента по индексу 3 nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Обходить список по индексам
|
||||
var count: i32 = 0;
|
||||
var i: usize = 0;
|
||||
while (i < nums.items.len) : (i += 1) {
|
||||
count += nums.items[i];
|
||||
}
|
||||
|
||||
// Непосредственно обходить элементы списка
|
||||
count = 0;
|
||||
for (nums.items) |x| {
|
||||
count += x;
|
||||
}
|
||||
|
||||
// Объединить два списка
|
||||
var nums1 = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer nums1.deinit();
|
||||
try nums1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 });
|
||||
try nums.insertSlice(nums.items.len, nums1.items);
|
||||
std.debug.print("После конкатенации списка nums1 к nums nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
// Отсортировать список
|
||||
std.mem.sort(i32, nums.items, {}, comptime std.sort.asc(i32));
|
||||
std.debug.print("После сортировки списка nums = {}\n", .{utils.fmt.slice(nums.items)});
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
try run();
|
||||
}
|
||||
|
||||
test "list" {
|
||||
try run();
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// File: my_list.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
|
||||
// Класс списка
|
||||
const MyList = struct {
|
||||
const Self = @This();
|
||||
|
||||
items: []i32, // Массив (для хранения элементов списка)
|
||||
capacity: usize, // Вместимость списка
|
||||
allocator: std.mem.Allocator, // Аллокатор памяти
|
||||
|
||||
extend_ratio: usize = 2, // Коэффициент увеличения списка при каждом расширении
|
||||
|
||||
// Конструктор (выделение памяти + инициализация списка)
|
||||
pub fn init(allocator: std.mem.Allocator) Self {
|
||||
return Self{
|
||||
.items = &[_]i32{},
|
||||
.capacity = 0,
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: Self) void {
|
||||
self.allocator.free(self.allocatedSlice());
|
||||
}
|
||||
|
||||
// Добавление элемента в конец
|
||||
pub fn add(self: *Self, item: i32) !void {
|
||||
// При превышении вместимости по числу элементов запускается расширение
|
||||
const newlen = self.items.len + 1;
|
||||
try self.ensureTotalCapacity(newlen);
|
||||
|
||||
// Обновление элемента
|
||||
self.items.len += 1;
|
||||
const new_item_ptr = &self.items[self.items.len - 1];
|
||||
new_item_ptr.* = item;
|
||||
}
|
||||
|
||||
// Получить длину списка (текущее число элементов)
|
||||
pub fn getSize(self: *Self) usize {
|
||||
return self.items.len;
|
||||
}
|
||||
|
||||
// Получить вместимость списка
|
||||
pub fn getCapacity(self: *Self) usize {
|
||||
return self.capacity;
|
||||
}
|
||||
|
||||
// Доступ к элементу
|
||||
pub fn get(self: *Self, index: usize) i32 {
|
||||
// Если индекс выходит за границы, выбрасывается исключение; далее аналогично
|
||||
if (index < 0 or index >= self.items.len) {
|
||||
@panic("индекс выходит за границы");
|
||||
}
|
||||
return self.items[index];
|
||||
}
|
||||
|
||||
// Обновление элемента
|
||||
pub fn set(self: *Self, index: usize, num: i32) void {
|
||||
// Если индекс выходит за границы, выбрасывается исключение; далее аналогично
|
||||
if (index < 0 or index >= self.items.len) {
|
||||
@panic("индекс выходит за границы");
|
||||
}
|
||||
self.items[index] = num;
|
||||
}
|
||||
|
||||
// Вставка элемента в середину
|
||||
pub fn insert(self: *Self, index: usize, item: i32) !void {
|
||||
if (index < 0 or index >= self.items.len) {
|
||||
@panic("индекс выходит за границы");
|
||||
}
|
||||
|
||||
// При превышении вместимости по числу элементов запускается расширение
|
||||
const newlen = self.items.len + 1;
|
||||
try self.ensureTotalCapacity(newlen);
|
||||
|
||||
// Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
|
||||
self.items.len += 1;
|
||||
var i = self.items.len - 1;
|
||||
while (i >= index) : (i -= 1) {
|
||||
self.items[i] = self.items[i - 1];
|
||||
}
|
||||
self.items[index] = item;
|
||||
}
|
||||
|
||||
// Удаление элемента
|
||||
pub fn remove(self: *Self, index: usize) i32 {
|
||||
if (index < 0 or index >= self.getSize()) {
|
||||
@panic("индекс выходит за границы");
|
||||
}
|
||||
// Сдвинуть все элементы после индекса index на одну позицию вперед
|
||||
const item = self.items[index];
|
||||
var i = index;
|
||||
while (i < self.items.len - 1) : (i += 1) {
|
||||
self.items[i] = self.items[i + 1];
|
||||
}
|
||||
self.items.len -= 1;
|
||||
// Вернуть удаленный элемент
|
||||
return item;
|
||||
}
|
||||
|
||||
// Преобразовать список в массив
|
||||
pub fn toArraySlice(self: *Self) ![]i32 {
|
||||
return self.toOwnedSlice(false);
|
||||
}
|
||||
|
||||
// Вернуть новый срез и указать, нужно ли сбросить или очистить контейнер списка
|
||||
pub fn toOwnedSlice(self: *Self, clear: bool) ![]i32 {
|
||||
const allocator = self.allocator;
|
||||
const old_memory = self.allocatedSlice();
|
||||
if (allocator.remap(old_memory, self.items.len)) |new_items| {
|
||||
if (clear) {
|
||||
self.* = init(allocator);
|
||||
}
|
||||
return new_items;
|
||||
}
|
||||
|
||||
const new_memory = try allocator.alloc(i32, self.items.len);
|
||||
@memcpy(new_memory, self.items);
|
||||
if (clear) {
|
||||
self.clearAndFree();
|
||||
}
|
||||
return new_memory;
|
||||
}
|
||||
|
||||
// Расширение списка
|
||||
fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void {
|
||||
if (self.capacity >= new_capacity) return;
|
||||
const capcacity = if (self.capacity == 0) 10 else self.capacity;
|
||||
const better_capacity = capcacity * self.extend_ratio;
|
||||
|
||||
const old_memory = self.allocatedSlice();
|
||||
if (self.allocator.remap(old_memory, better_capacity)) |new_memory| {
|
||||
self.items.ptr = new_memory.ptr;
|
||||
self.capacity = new_memory.len;
|
||||
} else {
|
||||
const new_memory = try self.allocator.alloc(i32, better_capacity);
|
||||
@memcpy(new_memory[0..self.items.len], self.items);
|
||||
self.allocator.free(old_memory);
|
||||
self.items.ptr = new_memory.ptr;
|
||||
self.capacity = new_memory.len;
|
||||
}
|
||||
}
|
||||
|
||||
fn clearAndFree(self: *Self, allocator: std.mem.Allocator) void {
|
||||
allocator.free(self.allocatedSlice());
|
||||
self.items.len = 0;
|
||||
self.capacity = 0;
|
||||
}
|
||||
|
||||
fn allocatedSlice(self: Self) []i32 {
|
||||
return self.items.ptr[0..self.capacity];
|
||||
}
|
||||
};
|
||||
|
||||
// Driver Code
|
||||
pub fn run() !void {
|
||||
var gpa = std.heap.DebugAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
// Инициализация списка
|
||||
var nums = MyList.init(allocator);
|
||||
// Отложенное освобождение памяти
|
||||
defer nums.deinit();
|
||||
|
||||
// Добавление элемента в конец
|
||||
try nums.add(1);
|
||||
try nums.add(3);
|
||||
try nums.add(2);
|
||||
try nums.add(5);
|
||||
try nums.add(4);
|
||||
std.debug.print("Список nums = {}, вместимость = {}, длина = {}\n", .{\n utils.fmt.slice(nums.items),\n nums.getCapacity(),\n nums.getSize(),\n});
|
||||
|
||||
// Вставка элемента в середину
|
||||
try nums.insert(3, 6);
|
||||
std.debug.print(
|
||||
"После вставки числа 6 по индексу 3 получаем nums = {}\n",\n .{utils.fmt.slice(nums.items)},\n);
|
||||
|
||||
// Удаление элемента
|
||||
_ = nums.remove(3);
|
||||
std.debug.print(
|
||||
"После удаления элемента по индексу 3 получаем nums = {}\n",\n .{utils.fmt.slice(nums.items)},\n);
|
||||
|
||||
// Доступ к элементу
|
||||
const num = nums.get(1);
|
||||
std.debug.print("Элемент по индексу 1: num = {}\n", .{num});
|
||||
|
||||
// Обновление элемента
|
||||
nums.set(1, 0);
|
||||
std.debug.print(
|
||||
"После обновления элемента по индексу 1 значением 0 получаем nums = {}\n",\n .{utils.fmt.slice(nums.items)},\n);
|
||||
|
||||
// Проверка механизма расширения
|
||||
var i: i32 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
// При i = 5 длина списка превысит его вместимость, и в этот момент сработает механизм расширения
|
||||
try nums.add(i);
|
||||
}
|
||||
std.debug.print(
|
||||
"Список nums после увеличения вместимости = {}, вместимость = {}, длина = {}\n",\n .{\n utils.fmt.slice(nums.items),\n nums.getCapacity(),\n nums.getSize(),\n },\n);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
try run();
|
||||
}
|
||||
|
||||
test "my_list" {
|
||||
try run();
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// File: iteration.zig
|
||||
// Created Time: 2023-09-27
|
||||
// Author: QiLOL (pikaqqpika@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
// Цикл for
|
||||
fn forLoop(n: usize) i32 {
|
||||
var res: i32 = 0;
|
||||
// Циклическое суммирование 1, 2, ..., n-1, n
|
||||
for (1..n + 1) |i| {
|
||||
res += @intCast(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Цикл while
|
||||
fn whileLoop(n: i32) i32 {
|
||||
var res: i32 = 0;
|
||||
var i: i32 = 1; // Инициализация условной переменной
|
||||
// Циклическое суммирование 1, 2, ..., n-1, n
|
||||
while (i <= n) : (i += 1) {
|
||||
res += @intCast(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Цикл while (двойное обновление)
|
||||
fn whileLoopII(n: i32) i32 {
|
||||
var res: i32 = 0;
|
||||
var i: i32 = 1; // Инициализация условной переменной
|
||||
// Циклическое суммирование 1, 4, 10, ...
|
||||
while (i <= n) : ({
|
||||
// Обновить условную переменную
|
||||
i += 1;
|
||||
i *= 2;
|
||||
}) {
|
||||
res += @intCast(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Двойной цикл for
|
||||
fn nestedForLoop(allocator: Allocator, n: usize) ![]const u8 {
|
||||
var res = std.ArrayList(u8).init(allocator);
|
||||
defer res.deinit();
|
||||
var buffer: [20]u8 = undefined;
|
||||
// Цикл по i = 1, 2, ..., n-1, n
|
||||
for (1..n + 1) |i| {
|
||||
// Цикл по j = 1, 2, ..., n-1, n
|
||||
for (1..n + 1) |j| {
|
||||
const str = try std.fmt.bufPrint(&buffer, "({d}, {d}), ", .{ i, j });
|
||||
try res.appendSlice(str);
|
||||
}
|
||||
}
|
||||
return res.toOwnedSlice();
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() !void {
|
||||
var gpa = std.heap.DebugAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
const n: i32 = 5;
|
||||
var res: i32 = 0;
|
||||
|
||||
res = forLoop(n);
|
||||
std.debug.print("Результат суммирования в цикле for res = {}\n", .{res});
|
||||
|
||||
res = whileLoop(n);
|
||||
std.debug.print("Результат суммирования в цикле while res = {}\n", .{res});
|
||||
|
||||
res = whileLoopII(n);
|
||||
std.debug.print("Результат суммирования в цикле while (двойное обновление) res = {}\n", .{res});
|
||||
|
||||
const resStr = try nestedForLoop(allocator, n);
|
||||
std.debug.print("Результат обхода в двойном цикле for {s}\n", .{resStr});
|
||||
allocator.free(resStr);
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
try run();
|
||||
}
|
||||
|
||||
test "interation" {
|
||||
try run();
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// File: recursion.zig
|
||||
// Created Time: 2023-09-27
|
||||
// Author: QiLOL (pikaqqpika@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Рекурсивная функция
|
||||
fn recur(n: i32) i32 {
|
||||
// Условие завершения
|
||||
if (n == 1) {
|
||||
return 1;
|
||||
}
|
||||
// Рекурсия: рекурсивный вызов
|
||||
const res = recur(n - 1);
|
||||
// Возврат: вернуть результат
|
||||
return n + res;
|
||||
}
|
||||
|
||||
// Имитация рекурсии итерацией
|
||||
fn forLoopRecur(comptime n: i32) i32 {
|
||||
// Использовать явный стек для имитации системного стека вызовов
|
||||
var stack: [n]i32 = undefined;
|
||||
var res: i32 = 0;
|
||||
// Рекурсия: рекурсивный вызов
|
||||
var i: usize = n;
|
||||
while (i > 0) {
|
||||
stack[i - 1] = @intCast(i);
|
||||
i -= 1;
|
||||
}
|
||||
// Возврат: вернуть результат
|
||||
var index: usize = n;
|
||||
while (index > 0) {
|
||||
index -= 1;
|
||||
res += stack[index];
|
||||
}
|
||||
// res = 1+2+3+...+n
|
||||
return res;
|
||||
}
|
||||
|
||||
// Хвосторекурсивная функция
|
||||
fn tailRecur(n: i32, res: i32) i32 {
|
||||
// Условие завершения
|
||||
if (n == 0) {
|
||||
return res;
|
||||
}
|
||||
// Хвостовой рекурсивный вызов
|
||||
return tailRecur(n - 1, res + n);
|
||||
}
|
||||
|
||||
// Числа Фибоначчи
|
||||
fn fib(n: i32) i32 {
|
||||
// Условие завершения: f(1) = 0, f(2) = 1
|
||||
if (n == 1 or n == 2) {
|
||||
return n - 1;
|
||||
}
|
||||
// Рекурсивный вызов f(n) = f(n-1) + f(n-2)
|
||||
const res: i32 = fib(n - 1) + fib(n - 2);
|
||||
// Вернуть результат f(n)
|
||||
return res;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() void {
|
||||
const n: i32 = 5;
|
||||
var res: i32 = 0;
|
||||
|
||||
res = recur(n);
|
||||
std.debug.print("Результат суммирования в рекурсивной функции res = {}\n", .{recur(n)});
|
||||
|
||||
res = forLoopRecur(n);
|
||||
std.debug.print("Результат суммирования при имитации рекурсии итерацией res = {}\n", .{forLoopRecur(n)});
|
||||
|
||||
res = tailRecur(n, 0);
|
||||
std.debug.print("Результат суммирования в хвостовой рекурсии res = {}\n", .{tailRecur(n, 0)});
|
||||
|
||||
res = fib(n);
|
||||
std.debug.print("Член последовательности Фибоначчи с номером {} = {}\n", .{ n, fib(n) });
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
run();
|
||||
}
|
||||
|
||||
test "recursion" {
|
||||
run();
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// File: space_complexity.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
const ListNode = utils.ListNode;
|
||||
const TreeNode = utils.TreeNode;
|
||||
|
||||
// Функция
|
||||
fn function() i32 {
|
||||
// Выполнить некоторые операции
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Постоянная сложность
|
||||
fn constant(n: i32) void {
|
||||
// Константы, переменные и объекты занимают O(1) памяти
|
||||
const a: i32 = 0;
|
||||
const b: i32 = 0;
|
||||
const nums = [_]i32{0} ** 10000;
|
||||
const node = ListNode(i32){ .val = 0 };
|
||||
var i: i32 = 0;
|
||||
// Переменные в цикле занимают O(1) памяти
|
||||
while (i < n) : (i += 1) {
|
||||
const c: i32 = 0;
|
||||
_ = c;
|
||||
}
|
||||
// Функции в цикле занимают O(1) памяти
|
||||
i = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
_ = function();
|
||||
}
|
||||
_ = a;
|
||||
_ = b;
|
||||
_ = nums;
|
||||
_ = node;
|
||||
}
|
||||
|
||||
// Линейная сложность
|
||||
fn linear(comptime n: i32) !void {
|
||||
// Массив длины n занимает O(n) памяти
|
||||
const nums = [_]i32{0} ** n;
|
||||
// Список длины n занимает O(n) памяти
|
||||
var nodes = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer nodes.deinit();
|
||||
var i: i32 = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
try nodes.append(i);
|
||||
}
|
||||
// Хеш-таблица длины n занимает O(n) памяти
|
||||
var map = std.AutoArrayHashMap(i32, []const u8).init(std.heap.page_allocator);
|
||||
defer map.deinit();
|
||||
var j: i32 = 0;
|
||||
while (j < n) : (j += 1) {
|
||||
const string = try std.fmt.allocPrint(std.heap.page_allocator, "{d}", .{j});
|
||||
defer std.heap.page_allocator.free(string);
|
||||
try map.put(i, string);
|
||||
}
|
||||
_ = nums;
|
||||
}
|
||||
|
||||
// Линейная сложность (рекурсивная реализация)
|
||||
fn linearRecur(comptime n: i32) void {
|
||||
std.debug.print("Рекурсия n = {}\n", .{n});
|
||||
if (n == 1) return;
|
||||
linearRecur(n - 1);
|
||||
}
|
||||
|
||||
// Квадратичная сложность
|
||||
fn quadratic(n: i32) !void {
|
||||
// Двумерный список занимает O(n^2) памяти
|
||||
var nodes = std.ArrayList(std.ArrayList(i32)).init(std.heap.page_allocator);
|
||||
defer nodes.deinit();
|
||||
var i: i32 = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
var tmp = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer tmp.deinit();
|
||||
var j: i32 = 0;
|
||||
while (j < n) : (j += 1) {
|
||||
try tmp.append(0);
|
||||
}
|
||||
try nodes.append(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// Квадратичная сложность (рекурсивная реализация)
|
||||
fn quadraticRecur(comptime n: i32) i32 {
|
||||
if (n <= 0) return 0;
|
||||
const nums = [_]i32{0} ** n;
|
||||
std.debug.print("В рекурсии n = {} длина nums = {}\n", .{ n, nums.len });
|
||||
return quadraticRecur(n - 1);
|
||||
}
|
||||
|
||||
// Экспоненциальная сложность (построение полного двоичного дерева)
|
||||
fn buildTree(allocator: std.mem.Allocator, n: i32) !?*TreeNode(i32) {
|
||||
if (n == 0) return null;
|
||||
const root = try allocator.create(TreeNode(i32));
|
||||
root.init(0);
|
||||
root.left = try buildTree(allocator, n - 1);
|
||||
root.right = try buildTree(allocator, n - 1);
|
||||
return root;
|
||||
}
|
||||
|
||||
// Освободить память дерева
|
||||
fn freeTree(allocator: std.mem.Allocator, root: ?*const TreeNode(i32)) void {
|
||||
if (root == null) return;
|
||||
freeTree(allocator, root.?.left);
|
||||
freeTree(allocator, root.?.right);
|
||||
allocator.destroy(root.?);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() !void {
|
||||
var gpa = std.heap.DebugAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
const n: i32 = 5;
|
||||
// Постоянная сложность
|
||||
constant(n);
|
||||
// Линейная сложность
|
||||
try linear(n);
|
||||
linearRecur(n);
|
||||
// Квадратичная сложность
|
||||
try quadratic(n);
|
||||
_ = quadraticRecur(n);
|
||||
// Экспоненциальная сложность
|
||||
const root = try buildTree(allocator, n);
|
||||
defer freeTree(allocator, root);
|
||||
std.debug.print("{}\n", .{utils.fmt.tree(i32, root)});
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
try run();
|
||||
}
|
||||
|
||||
test "space_complexity" {
|
||||
try run();
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
// File: time_complexity.zig
|
||||
// Created Time: 2022-12-28
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Постоянная сложность
|
||||
fn constant(n: i32) i32 {
|
||||
_ = n;
|
||||
var count: i32 = 0;
|
||||
const size: i32 = 100_000;
|
||||
var i: i32 = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Линейная сложность
|
||||
fn linear(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Линейная сложность (обход массива)
|
||||
fn arrayTraversal(nums: []i32) i32 {
|
||||
var count: i32 = 0;
|
||||
// Число итераций пропорционально длине массива
|
||||
for (nums) |_| {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Квадратичная сложность
|
||||
fn quadratic(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
// Число итераций квадратично зависит от размера данных n
|
||||
while (i < n) : (i += 1) {
|
||||
var j: i32 = 0;
|
||||
while (j < n) : (j += 1) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Квадратичная сложность (пузырьковая сортировка)
|
||||
fn bubbleSort(nums: []i32) i32 {
|
||||
var count: i32 = 0; // Счетчик
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
var i: i32 = @as(i32, @intCast(nums.len)) - 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
var j: usize = 0;
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
while (j < i) : (j += 1) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
const tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
count += 3; // Обмен элементов включает 3 элементарные операции
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Экспоненциальная сложность (итеративная реализация)
|
||||
fn exponential(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var bas: i32 = 1;
|
||||
var i: i32 = 0;
|
||||
// На каждом шаге клетка делится надвое, образуя последовательность 1, 2, 4, 8, ..., 2^(n-1)
|
||||
while (i < n) : (i += 1) {
|
||||
var j: i32 = 0;
|
||||
while (j < bas) : (j += 1) {
|
||||
count += 1;
|
||||
}
|
||||
bas *= 2;
|
||||
}
|
||||
// count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
|
||||
return count;
|
||||
}
|
||||
|
||||
// Экспоненциальная сложность (рекурсивная реализация)
|
||||
fn expRecur(n: i32) i32 {
|
||||
if (n == 1) return 1;
|
||||
return expRecur(n - 1) + expRecur(n - 1) + 1;
|
||||
}
|
||||
|
||||
// Логарифмическая сложность (итеративная реализация)
|
||||
fn logarithmic(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var n_var: i32 = n;
|
||||
while (n_var > 1) : (n_var = @divTrunc(n_var, 2)) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Логарифмическая сложность (рекурсивная реализация)
|
||||
fn logRecur(n: i32) i32 {
|
||||
if (n <= 1) return 0;
|
||||
return logRecur(@divTrunc(n, 2)) + 1;
|
||||
}
|
||||
|
||||
// Линейно-логарифмическая сложность
|
||||
fn linearLogRecur(n: i32) i32 {
|
||||
if (n <= 1) return 1;
|
||||
var count: i32 = linearLogRecur(@divTrunc(n, 2)) + linearLogRecur(@divTrunc(n, 2));
|
||||
var i: i32 = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Факториальная сложность (рекурсивная реализация)
|
||||
fn factorialRecur(n: i32) i32 {
|
||||
if (n == 0) return 1;
|
||||
var count: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
// Из одного получается n
|
||||
while (i < n) : (i += 1) {
|
||||
count += factorialRecur(n - 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() void {
|
||||
// Можно изменить n и запустить программу, чтобы увидеть, как меняется число операций при разных сложностях
|
||||
const n: i32 = 8;
|
||||
std.debug.print("Размер входных данных n = {}\n", .{n});
|
||||
|
||||
var count = constant(n);
|
||||
std.debug.print("Число операций постоянной сложности = {}\n", .{count});
|
||||
|
||||
count = linear(n);
|
||||
std.debug.print("Число операций линейной сложности = {}\n", .{count});
|
||||
var nums = [_]i32{0} ** n;
|
||||
count = arrayTraversal(&nums);
|
||||
std.debug.print("Число операций линейной сложности (обход массива) = {}\n", .{count});
|
||||
|
||||
count = quadratic(n);
|
||||
std.debug.print("Число операций квадратичной сложности = {}\n", .{count});
|
||||
for (&nums, 0..) |*num, i| {
|
||||
num.* = n - @as(i32, @intCast(i)); // [n,n-1,...,2,1]
|
||||
}
|
||||
count = bubbleSort(&nums);
|
||||
std.debug.print("Число операций квадратичной сложности (пузырьковая сортировка) = {}\n", .{count});
|
||||
|
||||
count = exponential(n);
|
||||
std.debug.print("Число операций экспоненциальной сложности (итеративная реализация) = {}\n", .{count});
|
||||
count = expRecur(n);
|
||||
std.debug.print("Число операций экспоненциальной сложности (рекурсивная реализация) = {}\n", .{count});
|
||||
|
||||
count = logarithmic(n);
|
||||
std.debug.print("Число операций логарифмической сложности (итеративная реализация) = {}\n", .{count});
|
||||
count = logRecur(n);
|
||||
std.debug.print("Число операций логарифмической сложности (рекурсивная реализация) = {}\n", .{count});
|
||||
|
||||
count = linearLogRecur(n);
|
||||
std.debug.print("Число операций линейно-логарифмической сложности (рекурсивная реализация) = {}\n", .{count});
|
||||
|
||||
count = factorialRecur(n);
|
||||
std.debug.print("Число операций факториальной сложности (рекурсивная реализация) = {}\n", .{count});
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
run();
|
||||
}
|
||||
|
||||
test "time_complexity" {
|
||||
run();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// File: worst_best_time_complexity.zig
|
||||
// Created Time: 2022-12-28
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const utils = @import("utils");
|
||||
|
||||
// Создать массив с элементами { 1, 2, ..., n } в случайном порядке
|
||||
pub fn randomNumbers(comptime n: usize) [n]i32 {
|
||||
var nums: [n]i32 = undefined;
|
||||
// Создать массив nums = { 1, 2, 3, ..., n }
|
||||
for (&nums, 0..) |*num, i| {
|
||||
num.* = @as(i32, @intCast(i)) + 1;
|
||||
}
|
||||
// Случайно перемешать элементы массива
|
||||
const rand = std.crypto.random;
|
||||
rand.shuffle(i32, &nums);
|
||||
return nums;
|
||||
}
|
||||
|
||||
// Найти индекс числа 1 в массиве nums
|
||||
pub fn findOne(nums: []i32) i32 {
|
||||
for (nums, 0..) |num, i| {
|
||||
// Когда элемент 1 находится в начале массива, достигается лучшая временная сложность O(1)
|
||||
// Когда элемент 1 находится в конце массива, достигается худшая временная сложность O(n)
|
||||
if (num == 1) return @intCast(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn run() void {
|
||||
var i: i32 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
const n: usize = 100;
|
||||
var nums = randomNumbers(n);
|
||||
const index = findOne(&nums);
|
||||
std.debug.print("После перемешивания массива [ 1, 2, ..., n ] = ", .{});
|
||||
std.debug.print("{}\n", .{utils.fmt.slice(nums)});
|
||||
|
||||
std.debug.print("Индекс числа 1 = {}\n", .{index});
|
||||
}
|
||||
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
run();
|
||||
}
|
||||
|
||||
test "worst_best_time_complexity" {
|
||||
run();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// File: climbing_stairs_backtrack.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Бэктрекинг
|
||||
fn backtrack(choices: []i32, state: i32, n: i32, res: std.ArrayList(i32)) void {
|
||||
// Когда подъем достигает n-й ступени, число вариантов увеличивается на 1
|
||||
if (state == n) {
|
||||
res.items[0] = res.items[0] + 1;
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
for (choices) |choice| {
|
||||
// Отсечение: нельзя выходить за n-ю ступень
|
||||
if (state + choice > n) {
|
||||
continue;
|
||||
}
|
||||
// Попытка: сделать выбор и обновить состояние
|
||||
backtrack(choices, state + choice, n, res);
|
||||
// Откат
|
||||
}
|
||||
}
|
||||
|
||||
// Подъем по лестнице: бэктрекинг
|
||||
fn climbingStairsBacktrack(n: usize) !i32 {
|
||||
var choices = [_]i32{ 1, 2 }; // Можно подняться на 1 или 2 ступени
|
||||
var state: i32 = 0; // Начать подъем с 0-й ступени
|
||||
var res = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer res.deinit();
|
||||
try res.append(0); // Использовать res[0] для хранения числа решений
|
||||
backtrack(&choices, state, @intCast(n), res);
|
||||
return res.items[0];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var n: usize = 9;
|
||||
|
||||
var res = try climbingStairsBacktrack(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// File: climbing_stairs_constraint_dp.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Подъем по лестнице с ограничениями: динамическое программирование
|
||||
fn climbingStairsConstraintDP(comptime n: usize) i32 {
|
||||
if (n == 1 or n == 2) {
|
||||
return 1;
|
||||
}
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
var dp = [_][3]i32{ [_]i32{ -1, -1, -1 } } ** (n + 1);
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1][1] = 1;
|
||||
dp[1][2] = 0;
|
||||
dp[2][1] = 0;
|
||||
dp[2][2] = 1;
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for (3..n + 1) |i| {
|
||||
dp[i][1] = dp[i - 1][2];
|
||||
dp[i][2] = dp[i - 2][1] + dp[i - 2][2];
|
||||
}
|
||||
return dp[n][1] + dp[n][2];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var n: usize = 9;
|
||||
|
||||
var res = climbingStairsConstraintDP(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// File: climbing_stairs_dfs.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Поиск
|
||||
fn dfs(i: usize) i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
if (i == 1 or i == 2) {
|
||||
return @intCast(i);
|
||||
}
|
||||
// dp[i] = dp[i-1] + dp[i-2]
|
||||
var count = dfs(i - 1) + dfs(i - 2);
|
||||
return count;
|
||||
}
|
||||
|
||||
// Подъем по лестнице: поиск
|
||||
fn climbingStairsDFS(comptime n: usize) i32 {
|
||||
return dfs(n);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var n: usize = 9;
|
||||
|
||||
var res = climbingStairsDFS(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// File: climbing_stairs_dfs_mem.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Поиск с мемоизацией
|
||||
fn dfs(i: usize, mem: []i32) i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
if (i == 1 or i == 2) {
|
||||
return @intCast(i);
|
||||
}
|
||||
// Если запись dp[i] существует, сразу вернуть ее
|
||||
if (mem[i] != -1) {
|
||||
return mem[i];
|
||||
}
|
||||
// dp[i] = dp[i-1] + dp[i-2]
|
||||
var count = dfs(i - 1, mem) + dfs(i - 2, mem);
|
||||
// Сохранить dp[i]
|
||||
mem[i] = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
// Подъем по лестнице: поиск с мемоизацией
|
||||
fn climbingStairsDFSMem(comptime n: usize) i32 {
|
||||
// mem[i] хранит число способов подняться на i-ю ступень, -1 означает отсутствие записи
|
||||
var mem = [_]i32{ -1 } ** (n + 1);
|
||||
return dfs(n, &mem);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var n: usize = 9;
|
||||
|
||||
var res = climbingStairsDFSMem(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// File: climbing_stairs_dp.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Подъем по лестнице: динамическое программирование
|
||||
fn climbingStairsDP(comptime n: usize) i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
if (n == 1 or n == 2) {
|
||||
return @intCast(n);
|
||||
}
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
var dp = [_]i32{-1} ** (n + 1);
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1] = 1;
|
||||
dp[2] = 2;
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for (3..n + 1) |i| {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
|
||||
// Подъем по лестнице: динамическое программирование с оптимизацией памяти
|
||||
fn climbingStairsDPComp(comptime n: usize) i32 {
|
||||
if (n == 1 or n == 2) {
|
||||
return @intCast(n);
|
||||
}
|
||||
var a: i32 = 1;
|
||||
var b: i32 = 2;
|
||||
for (3..n + 1) |_| {
|
||||
var tmp = b;
|
||||
b = a + b;
|
||||
a = tmp;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var n: usize = 9;
|
||||
|
||||
var res = climbingStairsDP(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
res = climbingStairsDPComp(n);
|
||||
std.debug.print("Количество способов подняться по лестнице из {} ступеней: {} вариантов\n", .{ n, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// File: coin_change.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Размен монет: динамическое программирование
|
||||
fn coinChangeDP(comptime coins: []i32, comptime amt: usize) i32 {
|
||||
comptime var n = coins.len;
|
||||
comptime var max = amt + 1;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_][amt + 1]i32{[_]i32{0} ** (amt + 1)} ** (n + 1);
|
||||
// Переход состояний: первая строка и первый столбец
|
||||
for (1..amt + 1) |a| {
|
||||
dp[0][a] = max;
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
for (1..n + 1) |i| {
|
||||
for (1..amt + 1) |a| {
|
||||
if (coins[i - 1] > @as(i32, @intCast(a))) {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[i][a] = dp[i - 1][a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету i
|
||||
dp[i][a] = @min(dp[i - 1][a], dp[i][a - @as(usize, @intCast(coins[i - 1]))] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dp[n][amt] != max) {
|
||||
return @intCast(dp[n][amt]);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Размен монет: динамическое программирование с оптимизацией памяти
|
||||
fn coinChangeDPComp(comptime coins: []i32, comptime amt: usize) i32 {
|
||||
comptime var n = coins.len;
|
||||
comptime var max = amt + 1;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_]i32{0} ** (amt + 1);
|
||||
@memset(&dp, max);
|
||||
dp[0] = 0;
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..amt + 1) |a| {
|
||||
if (coins[i - 1] > @as(i32, @intCast(a))) {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[a] = dp[a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету i
|
||||
dp[a] = @min(dp[a], dp[a - @as(usize, @intCast(coins[i - 1]))] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dp[amt] != max) {
|
||||
return @intCast(dp[amt]);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var coins = [_]i32{ 1, 2, 5 };
|
||||
comptime var amt: usize = 4;
|
||||
|
||||
// Динамическое программирование
|
||||
var res = coinChangeDP(&coins, amt);
|
||||
std.debug.print("Минимальное число монет для набора целевой суммы = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = coinChangeDPComp(&coins, amt);
|
||||
std.debug.print("Минимальное число монет для набора целевой суммы = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// File: coin_change_ii.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Размен монет II: динамическое программирование
|
||||
fn coinChangeIIDP(comptime coins: []i32, comptime amt: usize) i32 {
|
||||
comptime var n = coins.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_][amt + 1]i32{[_]i32{0} ** (amt + 1)} ** (n + 1);
|
||||
// Инициализация первого столбца
|
||||
for (0..n + 1) |i| {
|
||||
dp[i][0] = 1;
|
||||
}
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..amt + 1) |a| {
|
||||
if (coins[i - 1] > @as(i32, @intCast(a))) {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[i][a] = dp[i - 1][a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету i
|
||||
dp[i][a] = dp[i - 1][a] + dp[i][a - @as(usize, @intCast(coins[i - 1]))];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n][amt];
|
||||
}
|
||||
|
||||
// Размен монет II: динамическое программирование с оптимизацией памяти
|
||||
fn coinChangeIIDPComp(comptime coins: []i32, comptime amt: usize) i32 {
|
||||
comptime var n = coins.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_]i32{0} ** (amt + 1);
|
||||
dp[0] = 1;
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..amt + 1) |a| {
|
||||
if (coins[i - 1] > @as(i32, @intCast(a))) {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[a] = dp[a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету i
|
||||
dp[a] = dp[a] + dp[a - @as(usize, @intCast(coins[i - 1]))];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[amt];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var coins = [_]i32{ 1, 2, 5 };
|
||||
comptime var amt: usize = 5;
|
||||
|
||||
// Динамическое программирование
|
||||
var res = coinChangeIIDP(&coins, amt);
|
||||
std.debug.print("Количество комбинаций монет для набора целевой суммы = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = coinChangeIIDPComp(&coins, amt);
|
||||
std.debug.print("Количество комбинаций монет для набора целевой суммы = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// File: edit_distance.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Редакционное расстояние: полный перебор
|
||||
fn editDistanceDFS(comptime s: []const u8, comptime t: []const u8, i: usize, j: usize) i32 {
|
||||
// Если s и t пусты, вернуть 0
|
||||
if (i == 0 and j == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Если s пусто, вернуть длину t
|
||||
if (i == 0) {
|
||||
return @intCast(j);
|
||||
}
|
||||
// Если t пусто, вернуть длину s
|
||||
if (j == 0) {
|
||||
return @intCast(i);
|
||||
}
|
||||
// Если два символа равны, сразу пропустить их
|
||||
if (s[i - 1] == t[j - 1]) {
|
||||
return editDistanceDFS(s, t, i - 1, j - 1);
|
||||
}
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 1
|
||||
var insert = editDistanceDFS(s, t, i, j - 1);
|
||||
var delete = editDistanceDFS(s, t, i - 1, j);
|
||||
var replace = editDistanceDFS(s, t, i - 1, j - 1);
|
||||
// Вернуть минимальное число шагов редактирования
|
||||
return @min(@min(insert, delete), replace) + 1;
|
||||
}
|
||||
|
||||
// Редакционное расстояние: поиск с мемоизацией
|
||||
fn editDistanceDFSMem(comptime s: []const u8, comptime t: []const u8, mem: anytype, i: usize, j: usize) i32 {
|
||||
// Если s и t пусты, вернуть 0
|
||||
if (i == 0 and j == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Если s пусто, вернуть длину t
|
||||
if (i == 0) {
|
||||
return @intCast(j);
|
||||
}
|
||||
// Если t пусто, вернуть длину s
|
||||
if (j == 0) {
|
||||
return @intCast(i);
|
||||
}
|
||||
// Если запись уже есть, сразу вернуть ее
|
||||
if (mem[i][j] != -1) {
|
||||
return mem[i][j];
|
||||
}
|
||||
// Если два символа равны, сразу пропустить их
|
||||
if (s[i - 1] == t[j - 1]) {
|
||||
return editDistanceDFSMem(s, t, mem, i - 1, j - 1);
|
||||
}
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 1
|
||||
var insert = editDistanceDFSMem(s, t, mem, i, j - 1);
|
||||
var delete = editDistanceDFSMem(s, t, mem, i - 1, j);
|
||||
var replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1);
|
||||
// Сохранить и вернуть минимальное число шагов редактирования
|
||||
mem[i][j] = @min(@min(insert, delete), replace) + 1;
|
||||
return mem[i][j];
|
||||
}
|
||||
|
||||
// Редакционное расстояние: динамическое программирование
|
||||
fn editDistanceDP(comptime s: []const u8, comptime t: []const u8) i32 {
|
||||
comptime var n = s.len;
|
||||
comptime var m = t.len;
|
||||
var dp = [_][m + 1]i32{[_]i32{0} ** (m + 1)} ** (n + 1);
|
||||
// Переход состояний: первая строка и первый столбец
|
||||
for (1..n + 1) |i| {
|
||||
dp[i][0] = @intCast(i);
|
||||
}
|
||||
for (1..m + 1) |j| {
|
||||
dp[0][j] = @intCast(j);
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
for (1..n + 1) |i| {
|
||||
for (1..m + 1) |j| {
|
||||
if (s[i - 1] == t[j - 1]) {
|
||||
// Если два символа равны, сразу пропустить их
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
} else {
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 1
|
||||
dp[i][j] = @min(@min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n][m];
|
||||
}
|
||||
|
||||
// Редакционное расстояние: динамическое программирование с оптимизацией памяти
|
||||
fn editDistanceDPComp(comptime s: []const u8, comptime t: []const u8) i32 {
|
||||
comptime var n = s.len;
|
||||
comptime var m = t.len;
|
||||
var dp = [_]i32{0} ** (m + 1);
|
||||
// Переход состояний: первая строка
|
||||
for (1..m + 1) |j| {
|
||||
dp[j] = @intCast(j);
|
||||
}
|
||||
// Переход состояний: остальные строки
|
||||
for (1..n + 1) |i| {
|
||||
// Переход состояний: первый столбец
|
||||
var leftup = dp[0]; // Временно сохранить dp[i-1, j-1]
|
||||
dp[0] = @intCast(i);
|
||||
// Переход состояний: остальные столбцы
|
||||
for (1..m + 1) |j| {
|
||||
var temp = dp[j];
|
||||
if (s[i - 1] == t[j - 1]) {
|
||||
// Если два символа равны, сразу пропустить их
|
||||
dp[j] = leftup;
|
||||
} else {
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 1
|
||||
dp[j] = @min(@min(dp[j - 1], dp[j]), leftup) + 1;
|
||||
}
|
||||
leftup = temp; // Обновить до значения dp[i-1, j-1] для следующей итерации
|
||||
}
|
||||
}
|
||||
return dp[m];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
const s = "bag";
|
||||
const t = "pack";
|
||||
comptime var n = s.len;
|
||||
comptime var m = t.len;
|
||||
|
||||
// Полный перебор
|
||||
var res = editDistanceDFS(s, t, n, m);
|
||||
std.debug.print("Чтобы преобразовать {s} в {s}, нужно минимум {} шагов\n", .{ s, t, res });
|
||||
|
||||
// Поиск с запоминанием
|
||||
var mem = [_][m + 1]i32{[_]i32{-1} ** (m + 1)} ** (n + 1);
|
||||
res = editDistanceDFSMem(s, t, @constCast(&mem), n, m);
|
||||
std.debug.print("Чтобы преобразовать {s} в {s}, нужно минимум {} шагов\n", .{ s, t, res });
|
||||
|
||||
// Динамическое программирование
|
||||
res = editDistanceDP(s, t);
|
||||
std.debug.print("Чтобы преобразовать {s} в {s}, нужно минимум {} шагов\n", .{ s, t, res });
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = editDistanceDPComp(s, t);
|
||||
std.debug.print("Чтобы преобразовать {s} в {s}, нужно минимум {} шагов\n", .{ s, t, res });
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
// File: knapsack.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Рюкзак 0-1: полный перебор
|
||||
fn knapsackDFS(wgt: []i32, val: []i32, i: usize, c: usize) i32 {
|
||||
// Если все предметы уже рассмотрены или в рюкзаке не осталось места, вернуть стоимость 0
|
||||
if (i == 0 or c == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Если вместимость рюкзака превышена, можно только не класть предмет в рюкзак
|
||||
if (wgt[i - 1] > c) {
|
||||
return knapsackDFS(wgt, val, i - 1, c);
|
||||
}
|
||||
// Вычислить максимальную стоимость для случаев, когда предмет i не кладут и кладут
|
||||
var no = knapsackDFS(wgt, val, i - 1, c);
|
||||
var yes = knapsackDFS(wgt, val, i - 1, c - @as(usize, @intCast(wgt[i - 1]))) + val[i - 1];
|
||||
// Вернуть вариант с большей стоимостью из двух возможных
|
||||
return @max(no, yes);
|
||||
}
|
||||
|
||||
// Рюкзак 0-1: поиск с мемоизацией
|
||||
fn knapsackDFSMem(wgt: []i32, val: []i32, mem: anytype, i: usize, c: usize) i32 {
|
||||
// Если все предметы уже рассмотрены или в рюкзаке не осталось места, вернуть стоимость 0
|
||||
if (i == 0 or c == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Если запись уже есть, вернуть сразу
|
||||
if (mem[i][c] != -1) {
|
||||
return mem[i][c];
|
||||
}
|
||||
// Если вместимость рюкзака превышена, можно только не класть предмет в рюкзак
|
||||
if (wgt[i - 1] > c) {
|
||||
return knapsackDFSMem(wgt, val, mem, i - 1, c);
|
||||
}
|
||||
// Вычислить максимальную стоимость для случаев, когда предмет i не кладут и кладут
|
||||
var no = knapsackDFSMem(wgt, val, mem, i - 1, c);
|
||||
var yes = knapsackDFSMem(wgt, val, mem, i - 1, c - @as(usize, @intCast(wgt[i - 1]))) + val[i - 1];
|
||||
// Сохранить и вернуть вариант с большей стоимостью из двух решений
|
||||
mem[i][c] = @max(no, yes);
|
||||
return mem[i][c];
|
||||
}
|
||||
|
||||
// Рюкзак 0-1: динамическое программирование
|
||||
fn knapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 {
|
||||
comptime var n = wgt.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_][cap + 1]i32{[_]i32{0} ** (cap + 1)} ** (n + 1);
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..cap + 1) |c| {
|
||||
if (wgt[i - 1] > c) {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[i][c] = dp[i - 1][c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет i
|
||||
dp[i][c] = @max(dp[i - 1][c], dp[i - 1][c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n][cap];
|
||||
}
|
||||
|
||||
// Рюкзак 0-1: динамическое программирование с оптимизацией памяти
|
||||
fn knapsackDPComp(wgt: []i32, val: []i32, comptime cap: usize) i32 {
|
||||
var n = wgt.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_]i32{0} ** (cap + 1);
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
// Обход в обратном порядке
|
||||
var c = cap;
|
||||
while (c > 0) : (c -= 1) {
|
||||
if (wgt[i - 1] < c) {
|
||||
// Большее из двух решений: не брать или взять предмет i
|
||||
dp[c] = @max(dp[c], dp[c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[cap];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var wgt = [_]i32{ 10, 20, 30, 40, 50 };
|
||||
comptime var val = [_]i32{ 50, 120, 150, 210, 240 };
|
||||
comptime var cap = 50;
|
||||
comptime var n = wgt.len;
|
||||
|
||||
// Полный перебор
|
||||
var res = knapsackDFS(&wgt, &val, n, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
// Поиск с запоминанием
|
||||
var mem = [_][cap + 1]i32{[_]i32{-1} ** (cap + 1)} ** (n + 1);
|
||||
res = knapsackDFSMem(&wgt, &val, @constCast(&mem), n, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование
|
||||
res = knapsackDP(&wgt, &val, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = knapsackDPComp(&wgt, &val, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// File: min_cost_climbing_stairs_dp.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Минимальная стоимость подъема по лестнице: динамическое программирование
|
||||
fn minCostClimbingStairsDP(comptime cost: []i32) i32 {
|
||||
comptime var n = cost.len - 1;
|
||||
if (n == 1 or n == 2) {
|
||||
return cost[n];
|
||||
}
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
var dp = [_]i32{-1} ** (n + 1);
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1] = cost[1];
|
||||
dp[2] = cost[2];
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for (3..n + 1) |i| {
|
||||
dp[i] = @min(dp[i - 1], dp[i - 2]) + cost[i];
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
|
||||
// Минимальная стоимость подъема по лестнице: динамическое программирование с оптимизацией памяти
|
||||
fn minCostClimbingStairsDPComp(cost: []i32) i32 {
|
||||
var n = cost.len - 1;
|
||||
if (n == 1 or n == 2) {
|
||||
return cost[n];
|
||||
}
|
||||
var a = cost[1];
|
||||
var b = cost[2];
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for (3..n + 1) |i| {
|
||||
var tmp = b;
|
||||
b = @min(a, tmp) + cost[i];
|
||||
a = tmp;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var cost = [_]i32{ 0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1 };
|
||||
std.debug.print("Стоимость подъема по ступеням = {any}\n", .{cost});
|
||||
|
||||
var res = minCostClimbingStairsDP(&cost);
|
||||
std.debug.print("Стоимость подъема по ступеням = {}\n", .{res});
|
||||
|
||||
res = minCostClimbingStairsDPComp(&cost);
|
||||
std.debug.print("Стоимость подъема по ступеням = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// File: min_path_sum.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Минимальная сумма пути: полный перебор
|
||||
fn minPathSumDFS(grid: anytype, i: i32, j: i32) i32 {
|
||||
// Если это верхняя левая ячейка, завершить поиск
|
||||
if (i == 0 and j == 0) {
|
||||
return grid[0][0];
|
||||
}
|
||||
// Если индексы строки или столбца выходят за границы, вернуть стоимость +∞
|
||||
if (i < 0 or j < 0) {
|
||||
return std.math.maxInt(i32);
|
||||
}
|
||||
// Вычислить минимальную стоимость пути из левого верхнего угла до (i-1, j) и (i, j-1)
|
||||
var up = minPathSumDFS(grid, i - 1, j);
|
||||
var left = minPathSumDFS(grid, i, j - 1);
|
||||
// Вернуть минимальную стоимость пути из левого верхнего угла до (i, j)
|
||||
return @min(left, up) + grid[@as(usize, @intCast(i))][@as(usize, @intCast(j))];
|
||||
}
|
||||
|
||||
// Минимальная сумма пути: поиск с мемоизацией
|
||||
fn minPathSumDFSMem(grid: anytype, mem: anytype, i: i32, j: i32) i32 {
|
||||
// Если это верхняя левая ячейка, завершить поиск
|
||||
if (i == 0 and j == 0) {
|
||||
return grid[0][0];
|
||||
}
|
||||
// Если индексы строки или столбца выходят за границы, вернуть стоимость +∞
|
||||
if (i < 0 or j < 0) {
|
||||
return std.math.maxInt(i32);
|
||||
}
|
||||
// Если запись уже есть, вернуть сразу
|
||||
if (mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))] != -1) {
|
||||
return mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))];
|
||||
}
|
||||
// Вычислить минимальную стоимость пути из левого верхнего угла до (i-1, j) и (i, j-1)
|
||||
var up = minPathSumDFSMem(grid, mem, i - 1, j);
|
||||
var left = minPathSumDFSMem(grid, mem, i, j - 1);
|
||||
// Вернуть минимальную стоимость пути из левого верхнего угла в (i, j)
|
||||
// Записать и вернуть минимальную стоимость пути из левого верхнего угла в (i, j)
|
||||
mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))] = @min(left, up) + grid[@as(usize, @intCast(i))][@as(usize, @intCast(j))];
|
||||
return mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))];
|
||||
}
|
||||
|
||||
// Минимальная сумма пути: динамическое программирование
|
||||
fn minPathSumDP(comptime grid: anytype) i32 {
|
||||
comptime var n = grid.len;
|
||||
comptime var m = grid[0].len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_][m]i32{[_]i32{0} ** m} ** n;
|
||||
dp[0][0] = grid[0][0];
|
||||
// Переход состояний: первая строка
|
||||
for (1..m) |j| {
|
||||
dp[0][j] = dp[0][j - 1] + grid[0][j];
|
||||
}
|
||||
// Переход состояний: первый столбец
|
||||
for (1..n) |i| {
|
||||
dp[i][0] = dp[i - 1][0] + grid[i][0];
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
for (1..n) |i| {
|
||||
for (1..m) |j| {
|
||||
dp[i][j] = @min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];
|
||||
}
|
||||
}
|
||||
return dp[n - 1][m - 1];
|
||||
}
|
||||
|
||||
// Минимальная сумма пути: динамическое программирование с оптимизацией памяти
|
||||
fn minPathSumDPComp(comptime grid: anytype) i32 {
|
||||
comptime var n = grid.len;
|
||||
comptime var m = grid[0].len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_]i32{0} ** m;
|
||||
// Переход состояний: первая строка
|
||||
dp[0] = grid[0][0];
|
||||
for (1..m) |j| {
|
||||
dp[j] = dp[j - 1] + grid[0][j];
|
||||
}
|
||||
// Переход состояний: остальные строки
|
||||
for (1..n) |i| {
|
||||
// Переход состояний: первый столбец
|
||||
dp[0] = dp[0] + grid[i][0];
|
||||
for (1..m) |j| {
|
||||
dp[j] = @min(dp[j - 1], dp[j]) + grid[i][j];
|
||||
}
|
||||
}
|
||||
return dp[m - 1];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var grid = [_][4]i32{
|
||||
[_]i32{ 1, 3, 1, 5 },
|
||||
[_]i32{ 2, 2, 4, 2 },
|
||||
[_]i32{ 5, 3, 2, 1 },
|
||||
[_]i32{ 4, 3, 5, 2 },
|
||||
};
|
||||
comptime var n = grid.len;
|
||||
comptime var m = grid[0].len;
|
||||
|
||||
// Полный перебор
|
||||
var res = minPathSumDFS(&grid, n - 1, m - 1);
|
||||
std.debug.print("Минимальная сумма пути из левого верхнего угла в правый нижний = {}\n", .{res});
|
||||
|
||||
// Поиск с мемоизацией
|
||||
var mem = [_][m]i32{[_]i32{-1} ** m} ** n;
|
||||
res = minPathSumDFSMem(&grid, &mem, n - 1, m - 1);
|
||||
std.debug.print("Минимальная сумма пути из левого верхнего угла в правый нижний = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование
|
||||
res = minPathSumDP(&grid);
|
||||
std.debug.print("Минимальная сумма пути из левого верхнего угла в правый нижний = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = minPathSumDPComp(&grid);
|
||||
std.debug.print("Минимальная сумма пути из левого верхнего угла в правый нижний = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// File: unbounded_knapsack.zig
|
||||
// Created Time: 2023-07-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Полный рюкзак: динамическое программирование
|
||||
fn unboundedKnapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 {
|
||||
comptime var n = wgt.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_][cap + 1]i32{[_]i32{0} ** (cap + 1)} ** (n + 1);
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..cap + 1) |c| {
|
||||
if (wgt[i - 1] > c) {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[i][c] = dp[i - 1][c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет i
|
||||
dp[i][c] = @max(dp[i - 1][c], dp[i][c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n][cap];
|
||||
}
|
||||
|
||||
// Полный рюкзак: динамическое программирование с оптимизацией памяти
|
||||
fn unboundedKnapsackDPComp(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 {
|
||||
comptime var n = wgt.len;
|
||||
// Инициализация таблицы dp
|
||||
var dp = [_]i32{0} ** (cap + 1);
|
||||
// Переход состояний
|
||||
for (1..n + 1) |i| {
|
||||
for (1..cap + 1) |c| {
|
||||
if (wgt[i - 1] > c) {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[c] = dp[c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет i
|
||||
dp[c] = @max(dp[c], dp[c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[cap];
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
comptime var wgt = [_]i32{ 1, 2, 3 };
|
||||
comptime var val = [_]i32{ 5, 11, 15 };
|
||||
comptime var cap = 4;
|
||||
|
||||
// Динамическое программирование
|
||||
var res = unboundedKnapsackDP(&wgt, &val, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
res = unboundedKnapsackDPComp(&wgt, &val, cap);
|
||||
std.debug.print("Максимальная стоимость предметов без превышения вместимости рюкзака = {}\n", .{res});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// File: array_hash_map.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Пара ключ-значение
|
||||
const Pair = struct {
|
||||
key: usize = undefined,
|
||||
val: []const u8 = undefined,
|
||||
|
||||
pub fn init(key: usize, val: []const u8) Pair {
|
||||
return Pair {
|
||||
.key = key,
|
||||
.val = val,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Хеш-таблица на основе массива
|
||||
pub fn ArrayHashMap(comptime T: type) type {
|
||||
return struct {
|
||||
bucket: ?std.ArrayList(?T) = null,
|
||||
mem_allocator: std.mem.Allocator = undefined,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
// Конструктор
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
|
||||
self.mem_allocator = allocator;
|
||||
// Инициализировать корзину (массив) длиной 100
|
||||
self.bucket = std.ArrayList(?T).init(self.mem_allocator);
|
||||
var i: i32 = 0;
|
||||
while (i < 100) : (i += 1) {
|
||||
try self.bucket.?.append(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Деструктор
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.bucket != null) self.bucket.?.deinit();
|
||||
}
|
||||
|
||||
// Хеш-функция
|
||||
fn hashFunc(key: usize) usize {
|
||||
var index = key % 100;
|
||||
return index;
|
||||
}
|
||||
|
||||
// Операция поиска
|
||||
pub fn get(self: *Self, key: usize) []const u8 {
|
||||
var index = hashFunc(key);
|
||||
var pair = self.bucket.?.items[index];
|
||||
return pair.?.val;
|
||||
}
|
||||
|
||||
// Операция добавления
|
||||
pub fn put(self: *Self, key: usize, val: []const u8) !void {
|
||||
var pair = Pair.init(key, val);
|
||||
var index = hashFunc(key);
|
||||
self.bucket.?.items[index] = pair;
|
||||
}
|
||||
|
||||
// Операция удаления
|
||||
pub fn remove(self: *Self, key: usize) !void {
|
||||
var index = hashFunc(key);
|
||||
// Присвоить null, что означает удаление
|
||||
self.bucket.?.items[index] = null;
|
||||
}
|
||||
|
||||
// Получить все пары ключ-значение
|
||||
pub fn pairSet(self: *Self) !std.ArrayList(T) {
|
||||
var entry_set = std.ArrayList(T).init(self.mem_allocator);
|
||||
for (self.bucket.?.items) |item| {
|
||||
if (item == null) continue;
|
||||
try entry_set.append(item.?);
|
||||
}
|
||||
return entry_set;
|
||||
}
|
||||
|
||||
// Получить все ключи
|
||||
pub fn keySet(self: *Self) !std.ArrayList(usize) {
|
||||
var key_set = std.ArrayList(usize).init(self.mem_allocator);
|
||||
for (self.bucket.?.items) |item| {
|
||||
if (item == null) continue;
|
||||
try key_set.append(item.?.key);
|
||||
}
|
||||
return key_set;
|
||||
}
|
||||
|
||||
// Получить все значения
|
||||
pub fn valueSet(self: *Self) !std.ArrayList([]const u8) {
|
||||
var value_set = std.ArrayList([]const u8).init(self.mem_allocator);
|
||||
for (self.bucket.?.items) |item| {
|
||||
if (item == null) continue;
|
||||
try value_set.append(item.?.val);
|
||||
}
|
||||
return value_set;
|
||||
}
|
||||
|
||||
// Вывести хеш-таблицу
|
||||
pub fn print(self: *Self) !void {
|
||||
var entry_set = try self.pairSet();
|
||||
defer entry_set.deinit();
|
||||
for (entry_set.items) |item| {
|
||||
std.debug.print("{} -> {s}\n", .{item.key, item.val});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация хеш-таблицы
|
||||
var map = ArrayHashMap(Pair){};
|
||||
try map.init(std.heap.page_allocator);
|
||||
defer map.deinit();
|
||||
|
||||
// Операция добавления
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
try map.put(12836, "Сяо Ха");
|
||||
try map.put(15937, "Сяо Ло");
|
||||
try map.put(16750, "Сяо Суань");
|
||||
try map.put(13276, "Сяо Фа");
|
||||
try map.put(10583, "Сяо Я");
|
||||
std.debug.print("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение\n", .{});
|
||||
try map.print();
|
||||
|
||||
// Операция поиска
|
||||
// Передать ключ key в хеш-таблицу и получить значение value
|
||||
var name = map.get(15937);
|
||||
std.debug.print("\nПо номеру 15937 найдено имя {s}\n", .{name});
|
||||
|
||||
// Операция удаления
|
||||
// Удалить пару (key, value) из хеш-таблицы
|
||||
try map.remove(10583);
|
||||
std.debug.print("\nПосле удаления 10583 хеш-таблица имеет вид\nКлюч -> Значение\n", .{});
|
||||
try map.print();
|
||||
|
||||
// Обход хеш-таблицы
|
||||
std.debug.print("\nОтдельный обход пар ключ-значение\n", .{});
|
||||
var entry_set = try map.pairSet();
|
||||
for (entry_set.items) |kv| {
|
||||
std.debug.print("{} -> {s}\n", .{kv.key, kv.val});
|
||||
}
|
||||
defer entry_set.deinit();
|
||||
std.debug.print("\nОтдельный обход ключей\n", .{});
|
||||
var key_set = try map.keySet();
|
||||
for (key_set.items) |key| {
|
||||
std.debug.print("{}\n", .{key});
|
||||
}
|
||||
defer key_set.deinit();
|
||||
std.debug.print("\nОтдельный обход значений\n", .{});
|
||||
var value_set = try map.valueSet();
|
||||
for (value_set.items) |val| {
|
||||
std.debug.print("{s}\n", .{val});
|
||||
}
|
||||
defer value_set.deinit();
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// File: hash_map.zig
|
||||
// Created Time: 2023-01-13
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация хеш-таблицы
|
||||
var map = std.AutoHashMap(i32, []const u8).init(std.heap.page_allocator);
|
||||
// Отложенное освобождение памяти
|
||||
defer map.deinit();
|
||||
|
||||
// Операция добавления
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
try map.put(12836, "Сяо Ха");
|
||||
try map.put(15937, "Сяо Ло");
|
||||
try map.put(16750, "Сяо Суань");
|
||||
try map.put(13276, "Сяо Фа");
|
||||
try map.put(10583, "Сяо Я");
|
||||
std.debug.print("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение\n", .{});
|
||||
inc.PrintUtil.printHashMap(i32, []const u8, map);
|
||||
|
||||
// Операция поиска
|
||||
// Передать ключ key в хеш-таблицу и получить значение value
|
||||
var name = map.get(15937).?;
|
||||
std.debug.print("\nПо номеру 15937 найдено имя {s}\n", .{name});
|
||||
|
||||
// Операция удаления
|
||||
// Удалить пару (key, value) из хеш-таблицы
|
||||
_ = map.remove(10583);
|
||||
std.debug.print("\nПосле удаления 10583 хеш-таблица имеет вид\nКлюч -> Значение\n", .{});
|
||||
inc.PrintUtil.printHashMap(i32, []const u8, map);
|
||||
|
||||
// Обход хеш-таблицы
|
||||
std.debug.print("\nОтдельный обход пар ключ-значение\n", .{});
|
||||
inc.PrintUtil.printHashMap(i32, []const u8, map);
|
||||
|
||||
std.debug.print("\nОтдельный обход ключей\n", .{});
|
||||
var it = map.iterator();
|
||||
while (it.next()) |kv| {
|
||||
std.debug.print("{}\n", .{kv.key_ptr.*});
|
||||
}
|
||||
|
||||
std.debug.print("\nОтдельный обход значений\n", .{});
|
||||
it = map.iterator();
|
||||
while (it.next()) |kv| {
|
||||
std.debug.print("{s}\n", .{kv.value_ptr.*});
|
||||
}
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// File: heap.zig
|
||||
// Created Time: 2023-01-14
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
fn lessThan(context: void, a: i32, b: i32) std.math.Order {
|
||||
_ = context;
|
||||
return std.math.order(a, b);
|
||||
}
|
||||
|
||||
fn greaterThan(context: void, a: i32, b: i32) std.math.Order {
|
||||
return lessThan(context, a, b).invert();
|
||||
}
|
||||
|
||||
fn testPush(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype, val: T) !void {
|
||||
try heap.add(val); // Добавление элемента в кучу
|
||||
std.debug.print("\nПосле добавления элемента {} в кучу\n", .{val});
|
||||
try inc.PrintUtil.printHeap(T, mem_allocator, heap);
|
||||
}
|
||||
|
||||
fn testPop(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype) !void {
|
||||
var val = heap.remove(); // Извлечение элемента с вершины кучи
|
||||
std.debug.print("\nПосле извлечения элемента вершины кучи {}\n", .{val});
|
||||
try inc.PrintUtil.printHeap(T, mem_allocator, heap);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация аллокатора памяти
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
|
||||
// Инициализировать кучу
|
||||
// Инициализировать минимальную кучу
|
||||
const PQlt = std.PriorityQueue(i32, void, lessThan);
|
||||
var min_heap = PQlt.init(std.heap.page_allocator, {});
|
||||
defer min_heap.deinit();
|
||||
// Инициализация максимальной кучи
|
||||
const PQgt = std.PriorityQueue(i32, void, greaterThan);
|
||||
var max_heap = PQgt.init(std.heap.page_allocator, {});
|
||||
defer max_heap.deinit();
|
||||
|
||||
std.debug.print("\nНиже приведен тестовый пример для большой кучи", .{});
|
||||
|
||||
// Добавление элемента в кучу
|
||||
try testPush(i32, mem_allocator, &max_heap, 1);
|
||||
try testPush(i32, mem_allocator, &max_heap, 3);
|
||||
try testPush(i32, mem_allocator, &max_heap, 2);
|
||||
try testPush(i32, mem_allocator, &max_heap, 5);
|
||||
try testPush(i32, mem_allocator, &max_heap, 4);
|
||||
|
||||
// Получение элемента с вершины кучи
|
||||
var peek = max_heap.peek().?;
|
||||
std.debug.print("\nЭлемент на вершине кучи = {}\n", .{peek});
|
||||
|
||||
// Извлечение элемента с вершины кучи
|
||||
try testPop(i32, mem_allocator, &max_heap);
|
||||
try testPop(i32, mem_allocator, &max_heap);
|
||||
try testPop(i32, mem_allocator, &max_heap);
|
||||
try testPop(i32, mem_allocator, &max_heap);
|
||||
try testPop(i32, mem_allocator, &max_heap);
|
||||
|
||||
// Получить размер кучи
|
||||
var size = max_heap.len;
|
||||
std.debug.print("\nКоличество элементов в куче = {}\n", .{size});
|
||||
|
||||
// Проверка, пуста ли куча
|
||||
var is_empty = if (max_heap.len == 0) true else false;
|
||||
std.debug.print("\nПуста ли куча: {}\n", .{is_empty});
|
||||
|
||||
// Построить кучу по входному списку
|
||||
try min_heap.addSlice(&[_]i32{ 1, 3, 2, 5, 4 });
|
||||
std.debug.print("\nПосле построения мин-кучи из входного списка\n", .{});
|
||||
try inc.PrintUtil.printHeap(i32, mem_allocator, min_heap);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// File: my_heap.zig
|
||||
// Created Time: 2023-01-14
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Упрощенная реализация класса кучи
|
||||
pub fn MaxHeap(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
max_heap: ?std.ArrayList(T) = null, // Использовать список вместо массива, чтобы не учитывать проблему расширения
|
||||
|
||||
// Конструктор, строящий кучу по входному списку
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator, nums: []const T) !void {
|
||||
if (self.max_heap != null) return;
|
||||
self.max_heap = std.ArrayList(T).init(allocator);
|
||||
// Добавить элементы списка в кучу без изменений
|
||||
try self.max_heap.?.appendSlice(nums);
|
||||
// Выполнить heapify для всех узлов, кроме листовых
|
||||
var i: usize = parent(self.size() - 1) + 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
try self.siftDown(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Деструктор, освободить память
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.max_heap != null) self.max_heap.?.deinit();
|
||||
}
|
||||
|
||||
// Получить индекс левого дочернего узла
|
||||
fn left(i: usize) usize {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
// Получить индекс правого дочернего узла
|
||||
fn right(i: usize) usize {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
// Получить индекс родительского узла
|
||||
fn parent(i: usize) usize {
|
||||
// return (i - 1) / 2; // округление вниз при делении
|
||||
return @divFloor(i - 1, 2);
|
||||
}
|
||||
|
||||
// Поменять элементы местами
|
||||
fn swap(self: *Self, i: usize, j: usize) !void {
|
||||
var tmp = self.max_heap.?.items[i];
|
||||
try self.max_heap.?.replaceRange(i, 1, &[_]T{self.max_heap.?.items[j]});
|
||||
try self.max_heap.?.replaceRange(j, 1, &[_]T{tmp});
|
||||
}
|
||||
|
||||
// Получение размера кучи
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.max_heap.?.items.len;
|
||||
}
|
||||
|
||||
// Проверка, пуста ли куча
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
// Доступ к элементу на вершине кучи
|
||||
pub fn peek(self: *Self) T {
|
||||
return self.max_heap.?.items[0];
|
||||
}
|
||||
|
||||
// Добавление элемента в кучу
|
||||
pub fn push(self: *Self, val: T) !void {
|
||||
// Добавление узла
|
||||
try self.max_heap.?.append(val);
|
||||
// Просеивание снизу вверх
|
||||
try self.siftUp(self.size() - 1);
|
||||
}
|
||||
|
||||
// Начиная с узла i, выполнить просеивание снизу вверх
|
||||
fn siftUp(self: *Self, i_: usize) !void {
|
||||
var i = i_;
|
||||
while (true) {
|
||||
// Получение родительского узла для узла i
|
||||
var p = parent(i);
|
||||
// Завершить heapify, когда «корневой узел уже пройден» или «узел не требует исправления»
|
||||
if (p < 0 or self.max_heap.?.items[i] <= self.max_heap.?.items[p]) break;
|
||||
// Поменять два узла местами
|
||||
try self.swap(i, p);
|
||||
// Циклическое просеивание вверх
|
||||
i = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Извлечение элемента из кучи
|
||||
pub fn pop(self: *Self) !T {
|
||||
// Обработка проверки
|
||||
if (self.isEmpty()) unreachable;
|
||||
// Поменять корневой узел с самым правым листом местами (поменять первый и последний элементы)
|
||||
try self.swap(0, self.size() - 1);
|
||||
// Удаление узла
|
||||
var val = self.max_heap.?.pop();
|
||||
// Просеивание сверху вниз
|
||||
try self.siftDown(0);
|
||||
// Вернуть элемент с вершины кучи
|
||||
return val;
|
||||
}
|
||||
|
||||
// Начиная с узла i, выполнить просеивание сверху вниз
|
||||
fn siftDown(self: *Self, i_: usize) !void {
|
||||
var i = i_;
|
||||
while (true) {
|
||||
// Определить узел с максимальным значением среди i, l и r и обозначить его как ma
|
||||
var l = left(i);
|
||||
var r = right(i);
|
||||
var ma = i;
|
||||
if (l < self.size() and self.max_heap.?.items[l] > self.max_heap.?.items[ma]) ma = l;
|
||||
if (r < self.size() and self.max_heap.?.items[r] > self.max_heap.?.items[ma]) ma = r;
|
||||
// Если узел i уже максимален или индексы l и r вне границ, дальнейшее просеивание не требуется, выйти
|
||||
if (ma == i) break;
|
||||
// Поменять два узла местами
|
||||
try self.swap(i, ma);
|
||||
// Циклическое просеивание вниз
|
||||
i = ma;
|
||||
}
|
||||
}
|
||||
|
||||
fn lessThan(context: void, a: T, b: T) std.math.Order {
|
||||
_ = context;
|
||||
return std.math.order(a, b);
|
||||
}
|
||||
|
||||
fn greaterThan(context: void, a: T, b: T) std.math.Order {
|
||||
return lessThan(context, a, b).invert();
|
||||
}
|
||||
|
||||
// Вывести кучу (двоичное дерево)
|
||||
pub fn print(self: *Self, mem_allocator: std.mem.Allocator) !void {
|
||||
const PQgt = std.PriorityQueue(T, void, greaterThan);
|
||||
var queue = PQgt.init(std.heap.page_allocator, {});
|
||||
defer queue.deinit();
|
||||
try queue.addSlice(self.max_heap.?.items);
|
||||
try inc.PrintUtil.printHeap(T, mem_allocator, queue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация аллокатора памяти
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
|
||||
// Инициализация максимальной кучи
|
||||
var max_heap = MaxHeap(i32){};
|
||||
try max_heap.init(std.heap.page_allocator, &[_]i32{ 9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2 });
|
||||
defer max_heap.deinit();
|
||||
std.debug.print("\nПосле построения кучи из входного списка\n", .{});
|
||||
try max_heap.print(mem_allocator);
|
||||
|
||||
// Получение элемента с вершины кучи
|
||||
var peek = max_heap.peek();
|
||||
std.debug.print("\nЭлемент на вершине кучи = {}\n", .{peek});
|
||||
|
||||
// Добавление элемента в кучу
|
||||
const val = 7;
|
||||
try max_heap.push(val);
|
||||
std.debug.print("\nПосле добавления элемента {} в кучу\n", .{val});
|
||||
try max_heap.print(mem_allocator);
|
||||
|
||||
// Извлечение элемента с вершины кучи
|
||||
peek = try max_heap.pop();
|
||||
std.debug.print("\nПосле извлечения элемента вершины кучи {}\n", .{peek});
|
||||
try max_heap.print(mem_allocator);
|
||||
|
||||
// Получить размер кучи
|
||||
var size = max_heap.size();
|
||||
std.debug.print("\nКоличество элементов в куче = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли куча
|
||||
var is_empty = max_heap.isEmpty();
|
||||
std.debug.print("\nПуста ли куча: {}\n", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// File: binary_search.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Бинарный поиск (двусторонне замкнутый интервал)
|
||||
fn binarySearch(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len - 1;
|
||||
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if (nums.items[m] < target) { // Это означает, что target находится в интервале [m+1, j]
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // Это означает, что target находится в интервале [i, m-1]
|
||||
j = m - 1;
|
||||
} else { // Целевой элемент найден, вернуть его индекс
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Бинарный поиск (лево замкнутый, право открытый интервал)
|
||||
fn binarySearchLCRO(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len;
|
||||
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if (nums.items[m] < target) { // Это означает, что target находится в интервале [m+1, j)
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // Это означает, что target находится в интервале [i, m)
|
||||
j = m;
|
||||
} else { // Целевой элемент найден, вернуть его индекс
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var target: i32 = 6;
|
||||
var nums = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer nums.deinit();
|
||||
try nums.appendSlice(&[_]i32{ 1, 3, 6, 8, 12, 15, 23, 26, 31, 35 });
|
||||
|
||||
// Бинарный поиск (двусторонне замкнутый интервал)
|
||||
var index = binarySearch(i32, nums, target);
|
||||
std.debug.print("Индекс целевого элемента 6 = {}\n", .{index});
|
||||
|
||||
// Бинарный поиск (лево замкнутый, право открытый интервал)
|
||||
index = binarySearchLCRO(i32, nums, target);
|
||||
std.debug.print("Индекс целевого элемента 6 = {}\n", .{index});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// File: hashing_search.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Хеш-поиск (массив)
|
||||
fn hashingSearchArray(comptime T: type, map: std.AutoHashMap(T, T), target: T) T {
|
||||
// key хеш-таблицы: целевой элемент, value: индекс
|
||||
// Если такого key нет в хеш-таблице, вернуть -1
|
||||
if (map.getKey(target) == null) return -1;
|
||||
return map.get(target).?;
|
||||
}
|
||||
|
||||
// Хеш-поиск (связный список)
|
||||
fn hashingSearchLinkedList(comptime T: type, map: std.AutoHashMap(T, *inc.ListNode(T)), target: T) ?*inc.ListNode(T) {
|
||||
// key хеш-таблицы: значение целевого узла, value: объект узла
|
||||
// Если такого key нет в хеш-таблице, вернуть null
|
||||
if (map.getKey(target) == null) return null;
|
||||
return map.get(target);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var target: i32 = 3;
|
||||
|
||||
// Хеш-поиск (массив)
|
||||
var nums = [_]i32{ 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 };
|
||||
// Инициализация хеш-таблицы
|
||||
var map = std.AutoHashMap(i32, i32).init(std.heap.page_allocator);
|
||||
defer map.deinit();
|
||||
for (nums, 0..) |num, i| {
|
||||
try map.put(num, @as(i32, @intCast(i))); // key: элемент, value: индекс
|
||||
}
|
||||
var index = hashingSearchArray(i32, map, target);
|
||||
std.debug.print("Индекс целевого элемента 3 = {}\n", .{index});
|
||||
|
||||
// Хеш-поиск (связный список)
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var head = try inc.ListUtil.arrToLinkedList(i32, mem_allocator, &nums);
|
||||
// Инициализация хеш-таблицы
|
||||
var map1 = std.AutoHashMap(i32, *inc.ListNode(i32)).init(std.heap.page_allocator);
|
||||
defer map1.deinit();
|
||||
while (head != null) {
|
||||
try map1.put(head.?.val, head.?);
|
||||
head = head.?.next;
|
||||
}
|
||||
var node = hashingSearchLinkedList(i32, map1, target);
|
||||
std.debug.print("Объект узла со значением 3 = ", .{});
|
||||
try inc.PrintUtil.printLinkedList(i32, node);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// File: linear_search.zig
|
||||
// Created Time: 2023-01-13
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Линейный поиск (массив)
|
||||
fn linearSearchArray(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// Обход массива
|
||||
for (nums.items, 0..) |num, i| {
|
||||
// Найти целевой элемент и вернуть его индекс
|
||||
if (num == target) {
|
||||
return @intCast(i);
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Линейный поиск (связный список)
|
||||
pub fn linearSearchLinkedList(comptime T: type, node: ?*inc.ListNode(T), target: T) ?*inc.ListNode(T) {
|
||||
var head = node;
|
||||
// Обойти связный список
|
||||
while (head != null) {
|
||||
// Найти целевой узел и вернуть его
|
||||
if (head.?.val == target) return head;
|
||||
head = head.?.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var target: i32 = 3;
|
||||
|
||||
// Выполнить линейный поиск в массиве
|
||||
var nums = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
defer nums.deinit();
|
||||
try nums.appendSlice(&[_]i32{ 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 });
|
||||
var index = linearSearchArray(i32, nums, target);
|
||||
std.debug.print("Индекс целевого элемента 3 = {}\n", .{index});
|
||||
|
||||
// Выполнить линейный поиск в связном списке
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var head = try inc.ListUtil.listToLinkedList(i32, mem_allocator, nums);
|
||||
var node = linearSearchLinkedList(i32, head, target);
|
||||
std.debug.print("Объект узла со значением 3 = ", .{});
|
||||
try inc.PrintUtil.printLinkedList(i32, node);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// File: two_sum.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Метод 1: полный перебор
|
||||
pub fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 {
|
||||
var size: usize = nums.len;
|
||||
var i: usize = 0;
|
||||
// Два вложенных цикла, временная сложность O(n^2)
|
||||
while (i < size - 1) : (i += 1) {
|
||||
var j = i + 1;
|
||||
while (j < size) : (j += 1) {
|
||||
if (nums[i] + nums[j] == target) {
|
||||
return [_]i32{@intCast(i), @intCast(j)};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Метод 2: вспомогательная хеш-таблица
|
||||
pub fn twoSumHashTable(nums: []i32, target: i32) !?[2]i32 {
|
||||
var size: usize = nums.len;
|
||||
// Вспомогательная хеш-таблица, пространственная сложность O(n)
|
||||
var dic = std.AutoHashMap(i32, i32).init(std.heap.page_allocator);
|
||||
defer dic.deinit();
|
||||
var i: usize = 0;
|
||||
// Один цикл, временная сложность O(n)
|
||||
while (i < size) : (i += 1) {
|
||||
if (dic.contains(target - nums[i])) {
|
||||
return [_]i32{dic.get(target - nums[i]).?, @intCast(i)};
|
||||
}
|
||||
try dic.put(nums[i], @intCast(i));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
pub fn main() !void {
|
||||
// ======= Test Case =======
|
||||
var nums = [_]i32{ 2, 7, 11, 15 };
|
||||
var target: i32 = 9;
|
||||
|
||||
// ====== Основной код ======
|
||||
// Метод 1
|
||||
var res = twoSumBruteForce(&nums, target).?;
|
||||
std.debug.print("Метод 1: res = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &res);
|
||||
// Метод 2
|
||||
res = (try twoSumHashTable(&nums, target)).?;
|
||||
std.debug.print("\nМетод 2: res = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &res);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// File: bubble_sort.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Пузырьковая сортировка
|
||||
fn bubbleSort(nums: []i32) void {
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
var i: usize = nums.len - 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
var j: usize = 0;
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
while (j < i) : (j += 1) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
var tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Пузырьковая сортировка (оптимизация флагом)
|
||||
fn bubbleSortWithFlag(nums: []i32) void {
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
var i: usize = nums.len - 1;
|
||||
while (i > 0) : (i -= 1) {
|
||||
var flag = false; // Инициализировать флаг
|
||||
var j: usize = 0;
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
while (j < i) : (j += 1) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
var tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (!flag) break; // На этой итерации «всплытия» не было ни одного обмена, сразу выйти
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var nums = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
bubbleSort(&nums);
|
||||
std.debug.print("После завершения пузырьковой сортировки nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
var nums1 = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
bubbleSortWithFlag(&nums1);
|
||||
std.debug.print("\nПосле завершения пузырьковой сортировки nums1 = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums1);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// File: insertion_sort.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Сортировка вставками
|
||||
fn insertionSort(nums: []i32) void {
|
||||
// Внешний цикл: отсортированный диапазон [0, i-1]
|
||||
var i: usize = 1;
|
||||
while (i < nums.len) : (i += 1) {
|
||||
var base = nums[i];
|
||||
var j: usize = i;
|
||||
// Внутренний цикл: вставить base в правильную позицию отсортированного диапазона [0, i-1]
|
||||
while (j >= 1 and nums[j - 1] > base) : (j -= 1) {
|
||||
nums[j] = nums[j - 1]; // Сдвинуть nums[j] на одну позицию вправо
|
||||
}
|
||||
nums[j] = base; // Поместить base в правильную позицию
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
var nums = [_]i32{ 4, 1, 3, 1, 5, 2 };
|
||||
insertionSort(&nums);
|
||||
std.debug.print("После завершения сортировки вставками nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// File: merge_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Объединить левый и правый подмассивы
|
||||
// Диапазон левого подмассива [left, mid]
|
||||
// Диапазон правого подмассива [mid + 1, right]
|
||||
fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void {
|
||||
// Инициализация вспомогательного массива
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var tmp = try mem_allocator.alloc(i32, right + 1 - left);
|
||||
std.mem.copy(i32, tmp, nums[left..right+1]);
|
||||
// Начальный и конечный индексы левого подмассива
|
||||
var leftStart = left - left;
|
||||
var leftEnd = mid - left;
|
||||
// Начальный и конечный индексы правого подмассива
|
||||
var rightStart = mid + 1 - left;
|
||||
var rightEnd = right - left;
|
||||
// i и j указывают соответственно на первые элементы левого и правого подмассивов
|
||||
var i = leftStart;
|
||||
var j = rightStart;
|
||||
// Объединить левый и правый подмассивы, перезаписывая исходный массив nums
|
||||
var k = left;
|
||||
while (k <= right) : (k += 1) {
|
||||
// Если «левый подмассив уже полностью слит», выбрать элемент правого подмассива и выполнить j++
|
||||
if (i > leftEnd) {
|
||||
nums[k] = tmp[j];
|
||||
j += 1;
|
||||
// Иначе, если «правый подмассив уже полностью слит» или «элемент левого подмассива <= элементу правого подмассива», выбрать элемент левого подмассива и выполнить i++
|
||||
} else if (j > rightEnd or tmp[i] <= tmp[j]) {
|
||||
nums[k] = tmp[i];
|
||||
i += 1;
|
||||
// Иначе, если «оба подмассива еще не полностью слиты» и «элемент левого подмассива > элемента правого подмассива», выбрать элемент правого подмассива и выполнить j++
|
||||
} else {
|
||||
nums[k] = tmp[j];
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Сортировка слиянием
|
||||
fn mergeSort(nums: []i32, left: usize, right: usize) !void {
|
||||
// Условие завершения
|
||||
if (left >= right) return; // Завершить рекурсию, когда длина подмассива равна 1
|
||||
// Этап разбиения
|
||||
var mid = left + (right - left) / 2; // Вычислить середину
|
||||
try mergeSort(nums, left, mid); // Рекурсивно обработать левый подмассив
|
||||
try mergeSort(nums, mid + 1, right); // Рекурсивно обработать правый подмассив
|
||||
// Этап слияния
|
||||
try merge(nums, left, mid, right);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Сортировка слиянием
|
||||
var nums = [_]i32{ 7, 3, 2, 6, 0, 1, 5, 4 };
|
||||
try mergeSort(&nums, 0, nums.len - 1);
|
||||
std.debug.print("После завершения сортировки слиянием nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// File: quick_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Класс быстрой сортировки
|
||||
const QuickSort = struct {
|
||||
|
||||
// Обмен элементов
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// Разбиение с опорными указателями
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
swap(nums, i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
swap(nums, i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
return i; // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
// Быстрая сортировка
|
||||
pub fn quickSort(nums: []i32, left: usize, right: usize) void {
|
||||
// Завершить рекурсию, когда длина подмассива равна 1
|
||||
if (left >= right) return;
|
||||
// Разбиение с опорными указателями
|
||||
var pivot = partition(nums, left, right);
|
||||
// Рекурсивно обработать левый и правый подмассивы
|
||||
quickSort(nums, left, pivot - 1);
|
||||
quickSort(nums, pivot + 1, right);
|
||||
}
|
||||
};
|
||||
|
||||
// Класс быстрой сортировки (оптимизация медианным опорным элементом)
|
||||
const QuickSortMedian = struct {
|
||||
|
||||
// Обмен элементов
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// Выбрать медиану из трех кандидатов
|
||||
pub fn medianThree(nums: []i32, left: usize, mid: usize, right: usize) usize {
|
||||
var l = nums[left];
|
||||
var m = nums[mid];
|
||||
var r = nums[right];
|
||||
if ((l <= m && m <= r) || (r <= m && m <= l))
|
||||
return mid; // m находится между l и r
|
||||
if ((m <= l && l <= r) || (r <= l && l <= m))
|
||||
return left; // l находится между m и r
|
||||
return right;
|
||||
}
|
||||
|
||||
// Разбиение с опорными указателями (медиана трех)
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// Выбрать медиану из трех кандидатов
|
||||
var med = medianThree(nums, left, (left + right) / 2, right);
|
||||
// Переместить медиану в крайний левый элемент массива
|
||||
swap(nums, left, med);
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
swap(nums, i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
swap(nums, i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
return i; // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
// Быстрая сортировка
|
||||
pub fn quickSort(nums: []i32, left: usize, right: usize) void {
|
||||
// Завершить рекурсию, когда длина подмассива равна 1
|
||||
if (left >= right) return;
|
||||
// Разбиение с опорными указателями
|
||||
var pivot = partition(nums, left, right);
|
||||
if (pivot == 0) return;
|
||||
// Рекурсивно обработать левый и правый подмассивы
|
||||
quickSort(nums, left, pivot - 1);
|
||||
quickSort(nums, pivot + 1, right);
|
||||
}
|
||||
};
|
||||
|
||||
// Класс быстрой сортировки (оптимизация глубины рекурсии)
|
||||
const QuickSortTailCall = struct {
|
||||
|
||||
// Обмен элементов
|
||||
pub fn swap(nums: []i32, i: usize, j: usize) void {
|
||||
var tmp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
// Разбиение с опорными указателями
|
||||
pub fn partition(nums: []i32, left: usize, right: usize) usize {
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
var i = left;
|
||||
var j = right;
|
||||
while (i < j) {
|
||||
while (i < j and nums[j] >= nums[left]) j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
while (i < j and nums[i] <= nums[left]) i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
swap(nums, i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
swap(nums, i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
return i; // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
// Быстрая сортировка (оптимизация глубины рекурсии)
|
||||
pub fn quickSort(nums: []i32, left_: usize, right_: usize) void {
|
||||
var left = left_;
|
||||
var right = right_;
|
||||
// Завершить рекурсию, когда длина подмассива равна 1
|
||||
while (left < right) {
|
||||
// Операция разбиения с опорными указателями
|
||||
var pivot = partition(nums, left, right);
|
||||
// Выполнить быструю сортировку для более короткого из двух подмассивов
|
||||
if (pivot - left < right - pivot) {
|
||||
quickSort(nums, left, pivot - 1); // Рекурсивно отсортировать левый подмассив
|
||||
left = pivot + 1; // Оставшийся неотсортированный диапазон: [pivot + 1, right]
|
||||
} else {
|
||||
quickSort(nums, pivot + 1, right); // Рекурсивно отсортировать правый подмассив
|
||||
right = pivot - 1; // Оставшийся неотсортированный диапазон: [left, pivot - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Быстрая сортировка
|
||||
var nums = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSort.quickSort(&nums, 0, nums.len - 1);
|
||||
std.debug.print("После завершения быстрой сортировки nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
// Быстрая сортировка (оптимизация медианным опорным элементом)
|
||||
var nums1 = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSortMedian.quickSort(&nums1, 0, nums1.len - 1);
|
||||
std.debug.print("\nПосле завершения быстрой сортировки (оптимизация медианным опорным элементом) nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums1);
|
||||
|
||||
// Быстрая сортировка (оптимизация глубины рекурсии)
|
||||
var nums2 = [_]i32{ 2, 4, 1, 0, 3, 5 };
|
||||
QuickSortTailCall.quickSort(&nums2, 0, nums2.len - 1);
|
||||
std.debug.print("\nПосле завершения быстрой сортировки (оптимизация глубины рекурсии) nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums2);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// File: radix_sort.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Получить k-й разряд элемента num, где exp = 10^(k-1)
|
||||
fn digit(num: i32, exp: i32) i32 {
|
||||
// Передача exp вместо k позволяет избежать повторного дорогостоящего вычисления степени
|
||||
return @mod(@divFloor(num, exp), 10);
|
||||
}
|
||||
|
||||
// Сортировка подсчетом (сортировка по k-му разряду nums)
|
||||
fn countingSortDigit(nums: []i32, exp: i32) !void {
|
||||
// Разряды десятичной системы лежат в диапазоне 0~9, поэтому нужен массив корзин длины 10
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
// defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
var counter = try mem_allocator.alloc(usize, 10);
|
||||
@memset(counter, 0);
|
||||
var n = nums.len;
|
||||
// Подсчитать число появлений каждой цифры от 0 до 9
|
||||
for (nums) |num| {
|
||||
var d: u32 = @bitCast(digit(num, exp)); // Получить k-й разряд nums[i], обозначив его как d
|
||||
counter[d] += 1; // Подсчитать число появлений цифры d
|
||||
}
|
||||
// Вычислить префиксные суммы и преобразовать «число появлений» в «индекс массива»
|
||||
var i: usize = 1;
|
||||
while (i < 10) : (i += 1) {
|
||||
counter[i] += counter[i - 1];
|
||||
}
|
||||
// Выполняя обратный проход, заполнить res элементами по статистике в корзинах
|
||||
var res = try mem_allocator.alloc(i32, n);
|
||||
i = n - 1;
|
||||
while (i >= 0) : (i -= 1) {
|
||||
var d: u32 = @bitCast(digit(nums[i], exp));
|
||||
var j = counter[d] - 1; // Получить индекс j цифры d в массиве
|
||||
res[j] = nums[i]; // Поместить текущий элемент по индексу j
|
||||
counter[d] -= 1; // Уменьшить количество d на 1
|
||||
if (i == 0) break;
|
||||
}
|
||||
// Перезаписать исходный массив nums результатом
|
||||
i = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
nums[i] = res[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Поразрядная сортировка
|
||||
fn radixSort(nums: []i32) !void {
|
||||
// Получить максимальный элемент массива, чтобы определить максимальное число разрядов
|
||||
var m: i32 = std.math.minInt(i32);
|
||||
for (nums) |num| {
|
||||
if (num > m) m = num;
|
||||
}
|
||||
// Проходить разряды от младшего к старшему
|
||||
var exp: i32 = 1;
|
||||
while (exp <= m) : (exp *= 10) {
|
||||
// Выполнить сортировку подсчетом по k-му разряду элементов массива
|
||||
// k = 1 -> exp = 1
|
||||
// k = 2 -> exp = 10
|
||||
// то есть exp = 10^(k-1)
|
||||
try countingSortDigit(nums, exp);
|
||||
}
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Поразрядная сортировка
|
||||
var nums = [_]i32{ 23, 12, 3, 4, 788, 192 };
|
||||
try radixSort(&nums);
|
||||
std.debug.print("После завершения поразрядной сортировки nums = ", .{});
|
||||
inc.PrintUtil.printArray(i32, &nums);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// File: array_queue.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Очередь на основе кольцевого массива
|
||||
pub fn ArrayQueue(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
nums: []T = undefined, // Массив для хранения элементов очереди
|
||||
cap: usize = 0, // Вместимость очереди
|
||||
front: usize = 0, // Указатель head, указывающий на первый элемент очереди
|
||||
queSize: usize = 0, // Указатель хвоста, указывающий на позицию после хвоста
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор (выделение памяти + инициализация массива)
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator, cap: usize) !void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
self.cap = cap;
|
||||
self.nums = try self.mem_allocator.alloc(T, self.cap);
|
||||
@memset(self.nums, @as(T, 0));
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Получить вместимость очереди
|
||||
pub fn capacity(self: *Self) usize {
|
||||
return self.cap;
|
||||
}
|
||||
|
||||
// Получение длины очереди
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.queSize;
|
||||
}
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.queSize == 0;
|
||||
}
|
||||
|
||||
// Поместить в очередь
|
||||
pub fn push(self: *Self, num: T) !void {
|
||||
if (self.size() == self.capacity()) {
|
||||
std.debug.print("Очередь заполнена\n", .{});
|
||||
return;
|
||||
}
|
||||
// Вычислить указатель хвоста, указывающий на индекс хвоста + 1
|
||||
// С помощью операции взятия по модулю вернуть rear к началу после выхода за конец массива
|
||||
var rear = (self.front + self.queSize) % self.capacity();
|
||||
// Добавить num после хвостового узла
|
||||
self.nums[rear] = num;
|
||||
self.queSize += 1;
|
||||
}
|
||||
|
||||
// Извлечь из очереди
|
||||
pub fn pop(self: *Self) T {
|
||||
var num = self.peek();
|
||||
// Указатель head сдвигается на одну позицию назад; если он выходит за конец, то возвращается в начало массива
|
||||
self.front = (self.front + 1) % self.capacity();
|
||||
self.queSize -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
pub fn peek(self: *Self) T {
|
||||
if (self.isEmpty()) @panic("очередь пуста");
|
||||
return self.nums[self.front];
|
||||
}
|
||||
|
||||
// Вернуть массив
|
||||
pub fn toArray(self: *Self) ![]T {
|
||||
// Преобразовывать только элементы списка в пределах фактической длины
|
||||
var res = try self.mem_allocator.alloc(T, self.size());
|
||||
@memset(res, @as(T, 0));
|
||||
var i: usize = 0;
|
||||
var j: usize = self.front;
|
||||
while (i < self.size()) : ({ i += 1; j += 1; }) {
|
||||
res[i] = self.nums[j % self.capacity()];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация очереди
|
||||
var capacity: usize = 10;
|
||||
var queue = ArrayQueue(i32){};
|
||||
try queue.init(std.heap.page_allocator, capacity);
|
||||
defer queue.deinit();
|
||||
|
||||
// Добавление элемента в очередь
|
||||
try queue.push(1);
|
||||
try queue.push(3);
|
||||
try queue.push(2);
|
||||
try queue.push(5);
|
||||
try queue.push(4);
|
||||
std.debug.print("Очередь queue = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try queue.toArray());
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
var peek = queue.peek();
|
||||
std.debug.print("\nЭлемент в начале очереди peek = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
var pop = queue.pop();
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, очередь после извлечения queue = ", .{pop});
|
||||
inc.PrintUtil.printArray(i32, try queue.toArray());
|
||||
|
||||
// Получение длины очереди
|
||||
var size = queue.size();
|
||||
std.debug.print("\nДлина очереди size = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
var is_empty = queue.isEmpty();
|
||||
std.debug.print("\nПуста ли очередь = {}", .{is_empty});
|
||||
|
||||
// Проверка кольцевого массива
|
||||
var i: i32 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
try queue.push(i);
|
||||
_ = queue.pop();
|
||||
std.debug.print("\nПосле {}-го добавления и извлечения queue = ", .{i});
|
||||
inc.PrintUtil.printArray(i32, try queue.toArray());
|
||||
}
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// File: array_stack.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Стек на основе массива
|
||||
pub fn ArrayStack(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
stack: ?std.ArrayList(T) = null,
|
||||
|
||||
// Конструктор (выделение памяти + инициализация стека)
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) void {
|
||||
if (self.stack == null) {
|
||||
self.stack = std.ArrayList(T).init(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.stack == null) return;
|
||||
self.stack.?.deinit();
|
||||
}
|
||||
|
||||
// Получение длины стека
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.stack.?.items.len;
|
||||
}
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
pub fn peek(self: *Self) T {
|
||||
if (self.isEmpty()) @panic("стек пуст");
|
||||
return self.stack.?.items[self.size() - 1];
|
||||
}
|
||||
|
||||
// Поместить в стек
|
||||
pub fn push(self: *Self, num: T) !void {
|
||||
try self.stack.?.append(num);
|
||||
}
|
||||
|
||||
// Извлечь из стека
|
||||
pub fn pop(self: *Self) T {
|
||||
var num = self.stack.?.pop();
|
||||
return num;
|
||||
}
|
||||
|
||||
// Вернуть ArrayList
|
||||
pub fn toList(self: *Self) std.ArrayList(T) {
|
||||
return self.stack.?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация стека
|
||||
var stack = ArrayStack(i32){};
|
||||
stack.init(std.heap.page_allocator);
|
||||
// Отложенное освобождение памяти
|
||||
defer stack.deinit();
|
||||
|
||||
// Помещение элемента в стек
|
||||
try stack.push(1);
|
||||
try stack.push(3);
|
||||
try stack.push(2);
|
||||
try stack.push(5);
|
||||
try stack.push(4);
|
||||
std.debug.print("Стек stack = ", .{});
|
||||
inc.PrintUtil.printList(i32, stack.toList());
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
var peek = stack.peek();
|
||||
std.debug.print("\nВерхний элемент стека peek = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из стека
|
||||
var top = stack.pop();
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, стек после извлечения stack = ", .{top});
|
||||
inc.PrintUtil.printList(i32, stack.toList());
|
||||
|
||||
// Получение длины стека
|
||||
var size = stack.size();
|
||||
std.debug.print("\nДлина стека size = {}", .{size});
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
var is_empty = stack.isEmpty();
|
||||
std.debug.print("\nПуст ли стек = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// File: deque.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация двусторонней очереди
|
||||
const L = std.TailQueue(i32);
|
||||
var deque = L{};
|
||||
|
||||
// Добавление элемента в очередь
|
||||
var node1 = L.Node{ .data = 2 };
|
||||
var node2 = L.Node{ .data = 5 };
|
||||
var node3 = L.Node{ .data = 4 };
|
||||
var node4 = L.Node{ .data = 3 };
|
||||
var node5 = L.Node{ .data = 1 };
|
||||
deque.append(&node1); // Добавить в хвост очереди
|
||||
deque.append(&node2);
|
||||
deque.append(&node3);
|
||||
deque.prepend(&node4); // Добавить в голову очереди
|
||||
deque.prepend(&node5);
|
||||
std.debug.print("Двусторонняя очередь deque = ", .{});
|
||||
inc.PrintUtil.printQueue(i32, deque);
|
||||
|
||||
// Доступ к элементу
|
||||
var peek_first = deque.first.?.data; // Элемент в голове очереди
|
||||
std.debug.print("\nЭлемент в начале очереди peek_first = {}", .{peek_first});
|
||||
var peek_last = deque.last.?.data; // Элемент в хвосте очереди
|
||||
std.debug.print("\nЭлемент в конце очереди peek_last = {}", .{peek_last});
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
var pop_first = deque.popFirst().?.data; // Извлечь элемент из головы очереди
|
||||
std.debug.print("\nИзвлечен элемент из головы pop_first = {}, deque после извлечения из головы = ", .{pop_first});
|
||||
inc.PrintUtil.printQueue(i32, deque);
|
||||
var pop_last = deque.pop().?.data; // Извлечь элемент из хвоста очереди
|
||||
std.debug.print("\nИзвлечен элемент из хвоста pop_last = {}, deque после извлечения из хвоста = ", .{pop_last});
|
||||
inc.PrintUtil.printQueue(i32, deque);
|
||||
|
||||
// Получение длины двусторонней очереди
|
||||
var size = deque.len;
|
||||
std.debug.print("\nДлина двусторонней очереди size = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли двусторонняя очередь
|
||||
var is_empty = if (deque.len == 0) true else false;
|
||||
std.debug.print("\nПуста ли двусторонняя очередь = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
// File: linkedlist_deque.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Узел двусвязного списка
|
||||
pub fn ListNode(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
val: T = undefined, // Значение узла
|
||||
next: ?*Self = null, // Указатель на узел-преемник
|
||||
prev: ?*Self = null, // Указатель на узел-предшественник
|
||||
|
||||
// Initialize a list node with specific value
|
||||
pub fn init(self: *Self, x: i32) void {
|
||||
self.val = x;
|
||||
self.next = null;
|
||||
self.prev = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Двусторонняя очередь на основе двусвязного списка
|
||||
pub fn LinkedListDeque(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
front: ?*ListNode(T) = null, // Головной узел front
|
||||
rear: ?*ListNode(T) = null, // Хвостовой узел rear
|
||||
que_size: usize = 0, // Длина двусторонней очереди
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор (выделение памяти + инициализация очереди)
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
self.front = null;
|
||||
self.rear = null;
|
||||
self.que_size = 0;
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Получение длины двусторонней очереди
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.que_size;
|
||||
}
|
||||
|
||||
// Проверка, пуста ли двусторонняя очередь
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
// Операция добавления в очередь
|
||||
pub fn push(self: *Self, num: T, is_front: bool) !void {
|
||||
var node = try self.mem_allocator.create(ListNode(T));
|
||||
node.init(num);
|
||||
// Если связный список пуст, сделать так, чтобы и front, и rear указывали на node
|
||||
if (self.isEmpty()) {
|
||||
self.front = node;
|
||||
self.rear = node;
|
||||
// Операция добавления в голову очереди
|
||||
} else if (is_front) {
|
||||
// Добавить node в голову списка
|
||||
self.front.?.prev = node;
|
||||
node.next = self.front;
|
||||
self.front = node; // Обновить головной узел
|
||||
// Операция добавления в хвост очереди
|
||||
} else {
|
||||
// Добавить node в хвост списка
|
||||
self.rear.?.next = node;
|
||||
node.prev = self.rear;
|
||||
self.rear = node; // Обновить хвостовой узел
|
||||
}
|
||||
self.que_size += 1; // Обновить длину очереди
|
||||
}
|
||||
|
||||
// Добавление в голову очереди
|
||||
pub fn pushFirst(self: *Self, num: T) !void {
|
||||
try self.push(num, true);
|
||||
}
|
||||
|
||||
// Добавление в хвост очереди
|
||||
pub fn pushLast(self: *Self, num: T) !void {
|
||||
try self.push(num, false);
|
||||
}
|
||||
|
||||
// Операция извлечения из очереди
|
||||
pub fn pop(self: *Self, is_front: bool) T {
|
||||
if (self.isEmpty()) @panic("двусторонняя очередь пуста");
|
||||
var val: T = undefined;
|
||||
// Операция извлечения из головы очереди
|
||||
if (is_front) {
|
||||
val = self.front.?.val; // Временно сохранить значение головного узла
|
||||
// Удалить головной узел
|
||||
var fNext = self.front.?.next;
|
||||
if (fNext != null) {
|
||||
fNext.?.prev = null;
|
||||
self.front.?.next = null;
|
||||
}
|
||||
self.front = fNext; // Обновить головной узел
|
||||
// Операция извлечения из хвоста очереди
|
||||
} else {
|
||||
val = self.rear.?.val; // Временно сохранить значение хвостового узла
|
||||
// Удалить хвостовой узел
|
||||
var rPrev = self.rear.?.prev;
|
||||
if (rPrev != null) {
|
||||
rPrev.?.next = null;
|
||||
self.rear.?.prev = null;
|
||||
}
|
||||
self.rear = rPrev; // Обновить хвостовой узел
|
||||
}
|
||||
self.que_size -= 1; // Обновить длину очереди
|
||||
return val;
|
||||
}
|
||||
|
||||
// Извлечение из головы очереди
|
||||
pub fn popFirst(self: *Self) T {
|
||||
return self.pop(true);
|
||||
}
|
||||
|
||||
// Извлечение из хвоста очереди
|
||||
pub fn popLast(self: *Self) T {
|
||||
return self.pop(false);
|
||||
}
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
pub fn peekFirst(self: *Self) T {
|
||||
if (self.isEmpty()) @panic("двусторонняя очередь пуста");
|
||||
return self.front.?.val;
|
||||
}
|
||||
|
||||
// Доступ к элементу в конце очереди
|
||||
pub fn peekLast(self: *Self) T {
|
||||
if (self.isEmpty()) @panic("двусторонняя очередь пуста");
|
||||
return self.rear.?.val;
|
||||
}
|
||||
|
||||
// Вернуть массив для вывода
|
||||
pub fn toArray(self: *Self) ![]T {
|
||||
var node = self.front;
|
||||
var res = try self.mem_allocator.alloc(T, self.size());
|
||||
@memset(res, @as(T, 0));
|
||||
var i: usize = 0;
|
||||
while (i < res.len) : (i += 1) {
|
||||
res[i] = node.?.val;
|
||||
node = node.?.next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация двусторонней очереди
|
||||
var deque = LinkedListDeque(i32){};
|
||||
try deque.init(std.heap.page_allocator);
|
||||
defer deque.deinit();
|
||||
try deque.pushLast(3);
|
||||
try deque.pushLast(2);
|
||||
try deque.pushLast(5);
|
||||
std.debug.print("Двусторонняя очередь deque = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try deque.toArray());
|
||||
|
||||
// Доступ к элементу
|
||||
var peek_first = deque.peekFirst();
|
||||
std.debug.print("\nЭлемент в начале очереди peek_first = {}", .{peek_first});
|
||||
var peek_last = deque.peekLast();
|
||||
std.debug.print("\nЭлемент в конце очереди peek_last = {}", .{peek_last});
|
||||
|
||||
// Добавление элемента в очередь
|
||||
try deque.pushLast(4);
|
||||
std.debug.print("\nПосле добавления элемента 4 в хвост deque = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try deque.toArray());
|
||||
try deque.pushFirst(1);
|
||||
std.debug.print("\nПосле добавления элемента 1 в голову deque = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try deque.toArray());
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
var pop_last = deque.popLast();
|
||||
std.debug.print("\nИзвлечен элемент из хвоста = {}, deque после извлечения из хвоста = ", .{pop_last});
|
||||
inc.PrintUtil.printArray(i32, try deque.toArray());
|
||||
var pop_first = deque.popFirst();
|
||||
std.debug.print("\nИзвлечен элемент из головы = {}, deque после извлечения из головы = ", .{pop_first});
|
||||
inc.PrintUtil.printArray(i32, try deque.toArray());
|
||||
|
||||
// Получение длины двусторонней очереди
|
||||
var size = deque.size();
|
||||
std.debug.print("\nДлина двусторонней очереди size = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли двусторонняя очередь
|
||||
var is_empty = deque.isEmpty();
|
||||
std.debug.print("\nПуста ли двусторонняя очередь = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// File: linkedlist_queue.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Очередь на основе связного списка
|
||||
pub fn LinkedListQueue(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
front: ?*inc.ListNode(T) = null, // Головной узел front
|
||||
rear: ?*inc.ListNode(T) = null, // Хвостовой узел rear
|
||||
que_size: usize = 0, // Длина очереди
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор (выделение памяти + инициализация очереди)
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
self.front = null;
|
||||
self.rear = null;
|
||||
self.que_size = 0;
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Получение длины очереди
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.que_size;
|
||||
}
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
pub fn peek(self: *Self) T {
|
||||
if (self.size() == 0) @panic("очередь пуста");
|
||||
return self.front.?.val;
|
||||
}
|
||||
|
||||
// Поместить в очередь
|
||||
pub fn push(self: *Self, num: T) !void {
|
||||
// Добавить num после хвостового узла
|
||||
var node = try self.mem_allocator.create(inc.ListNode(T));
|
||||
node.init(num);
|
||||
// Если очередь пуста, сделать так, чтобы и head, и tail указывали на этот узел
|
||||
if (self.front == null) {
|
||||
self.front = node;
|
||||
self.rear = node;
|
||||
// Если очередь не пуста, добавить этот узел после хвостового узла
|
||||
} else {
|
||||
self.rear.?.next = node;
|
||||
self.rear = node;
|
||||
}
|
||||
self.que_size += 1;
|
||||
}
|
||||
|
||||
// Извлечь из очереди
|
||||
pub fn pop(self: *Self) T {
|
||||
var num = self.peek();
|
||||
// Удалить головной узел
|
||||
self.front = self.front.?.next;
|
||||
self.que_size -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
// Преобразовать связный список в массив
|
||||
pub fn toArray(self: *Self) ![]T {
|
||||
var node = self.front;
|
||||
var res = try self.mem_allocator.alloc(T, self.size());
|
||||
@memset(res, @as(T, 0));
|
||||
var i: usize = 0;
|
||||
while (i < res.len) : (i += 1) {
|
||||
res[i] = node.?.val;
|
||||
node = node.?.next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация очереди
|
||||
var queue = LinkedListQueue(i32){};
|
||||
try queue.init(std.heap.page_allocator);
|
||||
defer queue.deinit();
|
||||
|
||||
// Добавление элемента в очередь
|
||||
try queue.push(1);
|
||||
try queue.push(3);
|
||||
try queue.push(2);
|
||||
try queue.push(5);
|
||||
try queue.push(4);
|
||||
std.debug.print("Очередь queue = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try queue.toArray());
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
var peek = queue.peek();
|
||||
std.debug.print("\nЭлемент в начале очереди peek = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
var pop = queue.pop();
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, очередь после извлечения queue = ", .{pop});
|
||||
inc.PrintUtil.printArray(i32, try queue.toArray());
|
||||
|
||||
// Получение длины очереди
|
||||
var size = queue.size();
|
||||
std.debug.print("\nДлина очереди size = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
var is_empty = queue.isEmpty();
|
||||
std.debug.print("\nПуста ли очередь = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// File: linkedlist_stack.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Стек на основе связного списка
|
||||
pub fn LinkedListStack(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
stack_top: ?*inc.ListNode(T) = null, // Использовать головной узел как вершину стека
|
||||
stk_size: usize = 0, // Длина стека
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор (выделение памяти + инициализация стека)
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
self.stack_top = null;
|
||||
self.stk_size = 0;
|
||||
}
|
||||
|
||||
// Деструктор (освобождение памяти)
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Получение длины стека
|
||||
pub fn size(self: *Self) usize {
|
||||
return self.stk_size;
|
||||
}
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
pub fn isEmpty(self: *Self) bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
pub fn peek(self: *Self) T {
|
||||
if (self.size() == 0) @panic("стек пуст");
|
||||
return self.stack_top.?.val;
|
||||
}
|
||||
|
||||
// Поместить в стек
|
||||
pub fn push(self: *Self, num: T) !void {
|
||||
var node = try self.mem_allocator.create(inc.ListNode(T));
|
||||
node.init(num);
|
||||
node.next = self.stack_top;
|
||||
self.stack_top = node;
|
||||
self.stk_size += 1;
|
||||
}
|
||||
|
||||
// Извлечь из стека
|
||||
pub fn pop(self: *Self) T {
|
||||
var num = self.peek();
|
||||
self.stack_top = self.stack_top.?.next;
|
||||
self.stk_size -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
// Преобразовать стек в массив
|
||||
pub fn toArray(self: *Self) ![]T {
|
||||
var node = self.stack_top;
|
||||
var res = try self.mem_allocator.alloc(T, self.size());
|
||||
@memset(res, @as(T, 0));
|
||||
var i: usize = 0;
|
||||
while (i < res.len) : (i += 1) {
|
||||
res[res.len - i - 1] = node.?.val;
|
||||
node = node.?.next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация стека
|
||||
var stack = LinkedListStack(i32){};
|
||||
try stack.init(std.heap.page_allocator);
|
||||
// Отложенное освобождение памяти
|
||||
defer stack.deinit();
|
||||
|
||||
// Помещение элемента в стек
|
||||
try stack.push(1);
|
||||
try stack.push(3);
|
||||
try stack.push(2);
|
||||
try stack.push(5);
|
||||
try stack.push(4);
|
||||
std.debug.print("Стек stack = ", .{});
|
||||
inc.PrintUtil.printArray(i32, try stack.toArray());
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
var peek = stack.peek();
|
||||
std.debug.print("\nВерхний элемент стека top = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из стека
|
||||
var pop = stack.pop();
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, стек после извлечения stack = ", .{pop});
|
||||
inc.PrintUtil.printArray(i32, try stack.toArray());
|
||||
|
||||
// Получение длины стека
|
||||
var size = stack.size();
|
||||
std.debug.print("\nДлина стека size = {}", .{size});
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
var is_empty = stack.isEmpty();
|
||||
std.debug.print("\nПуст ли стек = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// File: queue.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация очереди
|
||||
const L = std.TailQueue(i32);
|
||||
var queue = L{};
|
||||
|
||||
// Добавление элемента в очередь
|
||||
var node1 = L.Node{ .data = 1 };
|
||||
var node2 = L.Node{ .data = 3 };
|
||||
var node3 = L.Node{ .data = 2 };
|
||||
var node4 = L.Node{ .data = 5 };
|
||||
var node5 = L.Node{ .data = 4 };
|
||||
queue.append(&node1);
|
||||
queue.append(&node2);
|
||||
queue.append(&node3);
|
||||
queue.append(&node4);
|
||||
queue.append(&node5);
|
||||
std.debug.print("Очередь queue = ", .{});
|
||||
inc.PrintUtil.printQueue(i32, queue);
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
var peek = queue.first.?.data;
|
||||
std.debug.print("\nЭлемент в начале очереди peek = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
var pop = queue.popFirst().?.data;
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, очередь после извлечения queue = ", .{pop});
|
||||
inc.PrintUtil.printQueue(i32, queue);
|
||||
|
||||
// Получение длины очереди
|
||||
var size = queue.len;
|
||||
std.debug.print("\nДлина очереди size = {}", .{size});
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
var is_empty = if (queue.len == 0) true else false;
|
||||
std.debug.print("\nПуста ли очередь = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// File: stack.zig
|
||||
// Created Time: 2023-01-08
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализировать стек
|
||||
// В Zig рекомендуется использовать ArrayList как стек
|
||||
var stack = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
// Отложенное освобождение памяти
|
||||
defer stack.deinit();
|
||||
|
||||
// Помещение элемента в стек
|
||||
try stack.append(1);
|
||||
try stack.append(3);
|
||||
try stack.append(2);
|
||||
try stack.append(5);
|
||||
try stack.append(4);
|
||||
std.debug.print("Стек stack = ", .{});
|
||||
inc.PrintUtil.printList(i32, stack);
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
var peek = stack.items[stack.items.len - 1];
|
||||
std.debug.print("\nВерхний элемент стека peek = {}", .{peek});
|
||||
|
||||
// Извлечение элемента из стека
|
||||
var pop = stack.pop();
|
||||
std.debug.print("\nИзвлечен элемент pop = {}, стек после извлечения stack = ", .{pop});
|
||||
inc.PrintUtil.printList(i32, stack);
|
||||
|
||||
// Получение длины стека
|
||||
var size = stack.items.len;
|
||||
std.debug.print("\nДлина стека size = {}", .{size});
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
var is_empty = if (stack.items.len == 0) true else false;
|
||||
std.debug.print("\nПуст ли стек = {}", .{is_empty});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
// File: avl_tree.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// AVL-дерево
|
||||
pub fn AVLTree(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
root: ?*inc.TreeNode(T) = null, // Корневой узел
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator) void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
}
|
||||
|
||||
// Метод-деструктор
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Получить высоту узла
|
||||
fn height(self: *Self, node: ?*inc.TreeNode(T)) i32 {
|
||||
_ = self;
|
||||
// Высота пустого узла равна -1, высота листового узла равна 0
|
||||
return if (node == null) -1 else node.?.height;
|
||||
}
|
||||
|
||||
// Обновить высоту узла
|
||||
fn updateHeight(self: *Self, node: ?*inc.TreeNode(T)) void {
|
||||
// Высота узла равна высоте более высокого поддерева + 1
|
||||
node.?.height = @max(self.height(node.?.left), self.height(node.?.right)) + 1;
|
||||
}
|
||||
|
||||
// Получить коэффициент баланса
|
||||
fn balanceFactor(self: *Self, node: ?*inc.TreeNode(T)) i32 {
|
||||
// Коэффициент баланса пустого узла равен 0
|
||||
if (node == null) return 0;
|
||||
// Коэффициент баланса узла = высота левого поддерева - высота правого поддерева
|
||||
return self.height(node.?.left) - self.height(node.?.right);
|
||||
}
|
||||
|
||||
// Операция правого вращения
|
||||
fn rightRotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) {
|
||||
var child = node.?.left;
|
||||
var grandChild = child.?.right;
|
||||
// Выполнить правое вращение узла node вокруг child
|
||||
child.?.right = node;
|
||||
node.?.left = grandChild;
|
||||
// Обновить высоту узла
|
||||
self.updateHeight(node);
|
||||
self.updateHeight(child);
|
||||
// Вернуть корневой узел поддерева после вращения
|
||||
return child;
|
||||
}
|
||||
|
||||
// Операция левого вращения
|
||||
fn leftRotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) {
|
||||
var child = node.?.right;
|
||||
var grandChild = child.?.left;
|
||||
// Выполнить левое вращение узла node вокруг child
|
||||
child.?.left = node;
|
||||
node.?.right = grandChild;
|
||||
// Обновить высоту узла
|
||||
self.updateHeight(node);
|
||||
self.updateHeight(child);
|
||||
// Вернуть корневой узел поддерева после вращения
|
||||
return child;
|
||||
}
|
||||
|
||||
// Выполнить вращение, чтобы снова сбалансировать поддерево
|
||||
fn rotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) {
|
||||
// Получить коэффициент баланса узла node
|
||||
var balance_factor = self.balanceFactor(node);
|
||||
// Левосторонне перекошенное дерево
|
||||
if (balance_factor > 1) {
|
||||
if (self.balanceFactor(node.?.left) >= 0) {
|
||||
// Правое вращение
|
||||
return self.rightRotate(node);
|
||||
} else {
|
||||
// Сначала левое вращение, затем правое
|
||||
node.?.left = self.leftRotate(node.?.left);
|
||||
return self.rightRotate(node);
|
||||
}
|
||||
}
|
||||
// Правосторонне перекошенное дерево
|
||||
if (balance_factor < -1) {
|
||||
if (self.balanceFactor(node.?.right) <= 0) {
|
||||
// Левое вращение
|
||||
return self.leftRotate(node);
|
||||
} else {
|
||||
// Сначала правое вращение, затем левое
|
||||
node.?.right = self.rightRotate(node.?.right);
|
||||
return self.leftRotate(node);
|
||||
}
|
||||
}
|
||||
// Дерево сбалансировано, вращение не требуется, вернуть сразу
|
||||
return node;
|
||||
}
|
||||
|
||||
// Вставка узла
|
||||
fn insert(self: *Self, val: T) !void {
|
||||
self.root = (try self.insertHelper(self.root, val)).?;
|
||||
}
|
||||
|
||||
// Рекурсивная вставка узла (вспомогательный метод)
|
||||
fn insertHelper(self: *Self, node_: ?*inc.TreeNode(T), val: T) !?*inc.TreeNode(T) {
|
||||
var node = node_;
|
||||
if (node == null) {
|
||||
var tmp_node = try self.mem_allocator.create(inc.TreeNode(T));
|
||||
tmp_node.init(val);
|
||||
return tmp_node;
|
||||
}
|
||||
// 1. Найти позицию вставки и вставить узел
|
||||
if (val < node.?.val) {
|
||||
node.?.left = try self.insertHelper(node.?.left, val);
|
||||
} else if (val > node.?.val) {
|
||||
node.?.right = try self.insertHelper(node.?.right, val);
|
||||
} else {
|
||||
return node; // Повторяющийся узел не вставлять, сразу вернуть
|
||||
}
|
||||
self.updateHeight(node); // Обновить высоту узла
|
||||
// 2. Выполнить вращение, чтобы снова сбалансировать поддерево
|
||||
node = self.rotate(node);
|
||||
// Вернуть корневой узел поддерева
|
||||
return node;
|
||||
}
|
||||
|
||||
// Удаление узла
|
||||
fn remove(self: *Self, val: T) void {
|
||||
self.root = self.removeHelper(self.root, val).?;
|
||||
}
|
||||
|
||||
// Рекурсивное удаление узла (вспомогательный метод)
|
||||
fn removeHelper(self: *Self, node_: ?*inc.TreeNode(T), val: T) ?*inc.TreeNode(T) {
|
||||
var node = node_;
|
||||
if (node == null) return null;
|
||||
// 1. Найти узел и удалить его
|
||||
if (val < node.?.val) {
|
||||
node.?.left = self.removeHelper(node.?.left, val);
|
||||
} else if (val > node.?.val) {
|
||||
node.?.right = self.removeHelper(node.?.right, val);
|
||||
} else {
|
||||
if (node.?.left == null or node.?.right == null) {
|
||||
var child = if (node.?.left != null) node.?.left else node.?.right;
|
||||
// Число дочерних узлов = 0, удалить node и сразу вернуть
|
||||
if (child == null) {
|
||||
return null;
|
||||
// Число дочерних узлов = 1, удалить node напрямую
|
||||
} else {
|
||||
node = child;
|
||||
}
|
||||
} else {
|
||||
// Число дочерних узлов = 2, удалить следующий по симметричному обходу узел и заменить им текущий узел
|
||||
var temp = node.?.right;
|
||||
while (temp.?.left != null) {
|
||||
temp = temp.?.left;
|
||||
}
|
||||
node.?.right = self.removeHelper(node.?.right, temp.?.val);
|
||||
node.?.val = temp.?.val;
|
||||
}
|
||||
}
|
||||
self.updateHeight(node); // Обновить высоту узла
|
||||
// 2. Выполнить вращение, чтобы снова сбалансировать поддерево
|
||||
node = self.rotate(node);
|
||||
// Вернуть корневой узел поддерева
|
||||
return node;
|
||||
}
|
||||
|
||||
// Поиск узла
|
||||
fn search(self: *Self, val: T) ?*inc.TreeNode(T) {
|
||||
var cur = self.root;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while (cur != null) {
|
||||
// Целевой узел находится в правом поддереве cur
|
||||
if (cur.?.val < val) {
|
||||
cur = cur.?.right;
|
||||
// Целевой узел находится в левом поддереве cur
|
||||
} else if (cur.?.val > val) {
|
||||
cur = cur.?.left;
|
||||
// Найти целевой узел и выйти из цикла
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Вернуть целевой узел
|
||||
return cur;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn testInsert(comptime T: type, tree_: *AVLTree(T), val: T) !void {
|
||||
var tree = tree_;
|
||||
try tree.insert(val);
|
||||
std.debug.print("\nПосле вставки узла {} AVL-дерево имеет вид\n", .{val});
|
||||
try inc.PrintUtil.printTree(tree.root, null, false);
|
||||
}
|
||||
|
||||
pub fn testRemove(comptime T: type, tree_: *AVLTree(T), val: T) void {
|
||||
var tree = tree_;
|
||||
tree.remove(val);
|
||||
std.debug.print("\nПосле удаления узла {} AVL-дерево имеет вид\n", .{val});
|
||||
try inc.PrintUtil.printTree(tree.root, null, false);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация пустого AVL-дерева
|
||||
var avl_tree = AVLTree(i32){};
|
||||
avl_tree.init(std.heap.page_allocator);
|
||||
defer avl_tree.deinit();
|
||||
|
||||
// Вставка узла
|
||||
// Обратите внимание, как AVL-дерево сохраняет баланс после вставки узла
|
||||
try testInsert(i32, &avl_tree, 1);
|
||||
try testInsert(i32, &avl_tree, 2);
|
||||
try testInsert(i32, &avl_tree, 3);
|
||||
try testInsert(i32, &avl_tree, 4);
|
||||
try testInsert(i32, &avl_tree, 5);
|
||||
try testInsert(i32, &avl_tree, 8);
|
||||
try testInsert(i32, &avl_tree, 7);
|
||||
try testInsert(i32, &avl_tree, 9);
|
||||
try testInsert(i32, &avl_tree, 10);
|
||||
try testInsert(i32, &avl_tree, 6);
|
||||
|
||||
// Вставка повторяющегося узла
|
||||
try testInsert(i32, &avl_tree, 7);
|
||||
|
||||
// Удаление узла
|
||||
// Обратите внимание, как AVL-дерево сохраняет баланс после удаления узла
|
||||
testRemove(i32, &avl_tree, 8); // Удаление узла степени 0
|
||||
testRemove(i32, &avl_tree, 5); // Удаление узла степени 1
|
||||
testRemove(i32, &avl_tree, 4); // Удаление узла степени 2
|
||||
|
||||
// Поиск узла
|
||||
var node = avl_tree.search(7).?;
|
||||
std.debug.print("\nНайденный объект узла = {any}, значение узла = {}\n", .{node, node.val});
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// File: binary_search_tree.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Двоичное дерево поиска
|
||||
pub fn BinarySearchTree(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
root: ?*inc.TreeNode(T) = null,
|
||||
mem_arena: ?std.heap.ArenaAllocator = null,
|
||||
mem_allocator: std.mem.Allocator = undefined, // Аллокатор памяти
|
||||
|
||||
// Конструктор
|
||||
pub fn init(self: *Self, allocator: std.mem.Allocator, nums: []T) !void {
|
||||
if (self.mem_arena == null) {
|
||||
self.mem_arena = std.heap.ArenaAllocator.init(allocator);
|
||||
self.mem_allocator = self.mem_arena.?.allocator();
|
||||
}
|
||||
std.mem.sort(T, nums, {}, comptime std.sort.asc(T)); // Отсортировать массив
|
||||
self.root = try self.buildTree(nums, 0, nums.len - 1); // Построить двоичное дерево поиска
|
||||
}
|
||||
|
||||
// Метод-деструктор
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.mem_arena == null) return;
|
||||
self.mem_arena.?.deinit();
|
||||
}
|
||||
|
||||
// Построить двоичное дерево поиска
|
||||
fn buildTree(self: *Self, nums: []T, i: usize, j: usize) !?*inc.TreeNode(T) {
|
||||
if (i > j) return null;
|
||||
// Использовать средний узел массива как корневой узел
|
||||
var mid = i + (j - i) / 2;
|
||||
var node = try self.mem_allocator.create(inc.TreeNode(T));
|
||||
node.init(nums[mid]);
|
||||
// Рекурсивно построить левое и правое поддеревья
|
||||
if (mid >= 1) node.left = try self.buildTree(nums, i, mid - 1);
|
||||
node.right = try self.buildTree(nums, mid + 1, j);
|
||||
return node;
|
||||
}
|
||||
|
||||
// Получить корневой узел двоичного дерева
|
||||
fn getRoot(self: *Self) ?*inc.TreeNode(T) {
|
||||
return self.root;
|
||||
}
|
||||
|
||||
// Поиск узла
|
||||
fn search(self: *Self, num: T) ?*inc.TreeNode(T) {
|
||||
var cur = self.root;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while (cur != null) {
|
||||
// Целевой узел находится в правом поддереве cur
|
||||
if (cur.?.val < num) {
|
||||
cur = cur.?.right;
|
||||
// Целевой узел находится в левом поддереве cur
|
||||
} else if (cur.?.val > num) {
|
||||
cur = cur.?.left;
|
||||
// Найти целевой узел и выйти из цикла
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Вернуть целевой узел
|
||||
return cur;
|
||||
}
|
||||
|
||||
// Вставка узла
|
||||
fn insert(self: *Self, num: T) !void {
|
||||
// Если дерево пусто, инициализировать корневой узел
|
||||
if (self.root == null) {
|
||||
self.root = try self.mem_allocator.create(inc.TreeNode(T));
|
||||
return;
|
||||
}
|
||||
var cur = self.root;
|
||||
var pre: ?*inc.TreeNode(T) = null;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while (cur != null) {
|
||||
// Найти повторяющийся узел и сразу вернуть
|
||||
if (cur.?.val == num) return;
|
||||
pre = cur;
|
||||
// Позиция вставки находится в правом поддереве cur
|
||||
if (cur.?.val < num) {
|
||||
cur = cur.?.right;
|
||||
// Позиция вставки находится в левом поддереве cur
|
||||
} else {
|
||||
cur = cur.?.left;
|
||||
}
|
||||
}
|
||||
// Вставка узла
|
||||
var node = try self.mem_allocator.create(inc.TreeNode(T));
|
||||
node.init(num);
|
||||
if (pre.?.val < num) {
|
||||
pre.?.right = node;
|
||||
} else {
|
||||
pre.?.left = node;
|
||||
}
|
||||
}
|
||||
|
||||
// Удаление узла
|
||||
fn remove(self: *Self, num: T) void {
|
||||
// Если дерево пусто, сразу вернуть
|
||||
if (self.root == null) return;
|
||||
var cur = self.root;
|
||||
var pre: ?*inc.TreeNode(T) = null;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while (cur != null) {
|
||||
// Найти узел для удаления и выйти из цикла
|
||||
if (cur.?.val == num) break;
|
||||
pre = cur;
|
||||
// Узел для удаления находится в правом поддереве cur
|
||||
if (cur.?.val < num) {
|
||||
cur = cur.?.right;
|
||||
// Узел для удаления находится в левом поддереве cur
|
||||
} else {
|
||||
cur = cur.?.left;
|
||||
}
|
||||
}
|
||||
// Если узел для удаления отсутствует, сразу вернуть
|
||||
if (cur == null) return;
|
||||
// Число дочерних узлов = 0 или 1
|
||||
if (cur.?.left == null or cur.?.right == null) {
|
||||
// Когда число дочерних узлов = 0 / 1, child = null / этот дочерний узел
|
||||
var child = if (cur.?.left != null) cur.?.left else cur.?.right;
|
||||
// Удалить узел cur
|
||||
if (pre.?.left == cur) {
|
||||
pre.?.left = child;
|
||||
} else {
|
||||
pre.?.right = child;
|
||||
}
|
||||
// Число дочерних узлов = 2
|
||||
} else {
|
||||
// Получить следующий узел после cur в симметричном обходе
|
||||
var tmp = cur.?.right;
|
||||
while (tmp.?.left != null) {
|
||||
tmp = tmp.?.left;
|
||||
}
|
||||
var tmp_val = tmp.?.val;
|
||||
// Рекурсивно удалить узел tmp
|
||||
self.remove(tmp.?.val);
|
||||
// Перезаписать cur значением tmp
|
||||
cur.?.val = tmp_val;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация двоичного дерева
|
||||
var nums = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
var bst = BinarySearchTree(i32){};
|
||||
try bst.init(std.heap.page_allocator, &nums);
|
||||
defer bst.deinit();
|
||||
std.debug.print("Инициализированное двоичное дерево\n", .{});
|
||||
try inc.PrintUtil.printTree(bst.getRoot(), null, false);
|
||||
|
||||
// Поиск узла
|
||||
var node = bst.search(7);
|
||||
std.debug.print("\nНайденный объект узла = {any}, значение узла = {}\n", .{node, node.?.val});
|
||||
|
||||
// Вставка узла
|
||||
try bst.insert(16);
|
||||
std.debug.print("\nПосле вставки узла 16 двоичное дерево имеет вид\n", .{});
|
||||
try inc.PrintUtil.printTree(bst.getRoot(), null, false);
|
||||
|
||||
// Удаление узла
|
||||
bst.remove(1);
|
||||
std.debug.print("\nПосле удаления узла 1 двоичное дерево имеет вид\n", .{});
|
||||
try inc.PrintUtil.printTree(bst.getRoot(), null, false);
|
||||
bst.remove(2);
|
||||
std.debug.print("\nПосле удаления узла 2 двоичное дерево имеет вид\n", .{});
|
||||
try inc.PrintUtil.printTree(bst.getRoot(), null, false);
|
||||
bst.remove(4);
|
||||
std.debug.print("\nПосле удаления узла 4 двоичное дерево имеет вид\n", .{});
|
||||
try inc.PrintUtil.printTree(bst.getRoot(), null, false);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// File: binary_tree.zig
|
||||
// Created Time: 2023-01-14
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация двоичного дерева
|
||||
// Инициализация узлов
|
||||
var n1 = inc.TreeNode(i32){ .val = 1 };
|
||||
var n2 = inc.TreeNode(i32){ .val = 2 };
|
||||
var n3 = inc.TreeNode(i32){ .val = 3 };
|
||||
var n4 = inc.TreeNode(i32){ .val = 4 };
|
||||
var n5 = inc.TreeNode(i32){ .val = 5 };
|
||||
// Построить связи между узлами (указатели)
|
||||
n1.left = &n2;
|
||||
n1.right = &n3;
|
||||
n2.left = &n4;
|
||||
n2.right = &n5;
|
||||
std.debug.print("Инициализация двоичного дерева\n", .{});
|
||||
try inc.PrintUtil.printTree(&n1, null, false);
|
||||
|
||||
// Вставка и удаление узлов
|
||||
var p = inc.TreeNode(i32){ .val = 0 };
|
||||
// Вставить узел P между n1 -> n2
|
||||
n1.left = &p;
|
||||
p.left = &n2;
|
||||
std.debug.print("После вставки узла P\n", .{});
|
||||
try inc.PrintUtil.printTree(&n1, null, false);
|
||||
// Удаление узла
|
||||
n1.left = &n2;
|
||||
std.debug.print("После удаления узла P\n", .{});
|
||||
try inc.PrintUtil.printTree(&n1, null, false);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// File: binary_tree_bfs.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
// Обход в ширину
|
||||
fn levelOrder(comptime T: type, mem_allocator: std.mem.Allocator, root: *inc.TreeNode(T)) !std.ArrayList(T) {
|
||||
// Инициализировать очередь и добавить корневой узел
|
||||
const L = std.TailQueue(*inc.TreeNode(T));
|
||||
var queue = L{};
|
||||
var root_node = try mem_allocator.create(L.Node);
|
||||
root_node.data = root;
|
||||
queue.append(root_node);
|
||||
// Инициализировать список для хранения последовательности обхода
|
||||
var list = std.ArrayList(T).init(std.heap.page_allocator);
|
||||
while (queue.len > 0) {
|
||||
var queue_node = queue.popFirst().?; // Извлечение из очереди
|
||||
var node = queue_node.data;
|
||||
try list.append(node.val); // Сохранить значение узла
|
||||
if (node.left != null) {
|
||||
var tmp_node = try mem_allocator.create(L.Node);
|
||||
tmp_node.data = node.left.?;
|
||||
queue.append(tmp_node); // Поместить левый дочерний узел в очередь
|
||||
}
|
||||
if (node.right != null) {
|
||||
var tmp_node = try mem_allocator.create(L.Node);
|
||||
tmp_node.data = node.right.?;
|
||||
queue.append(tmp_node); // Поместить правый дочерний узел в очередь
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация аллокатора памяти
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
|
||||
// Инициализировать двоичное дерево
|
||||
// Здесь используется функция, напрямую строящая двоичное дерево из массива
|
||||
var nums = [_]i32{1, 2, 3, 4, 5, 6, 7};
|
||||
var root = try inc.TreeUtil.arrToTree(i32, mem_allocator, &nums);
|
||||
std.debug.print("Инициализация двоичного дерева\n", .{});
|
||||
try inc.PrintUtil.printTree(root, null, false);
|
||||
|
||||
// Обход в ширину
|
||||
var list = try levelOrder(i32, mem_allocator, root.?);
|
||||
defer list.deinit();
|
||||
std.debug.print("\nПоследовательность печати узлов при обходе в ширину = ", .{});
|
||||
inc.PrintUtil.printList(i32, list);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// File: binary_tree_dfs.zig
|
||||
// Created Time: 2023-01-15
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
const inc = @import("include");
|
||||
|
||||
var list = std.ArrayList(i32).init(std.heap.page_allocator);
|
||||
|
||||
// Предварительный обход
|
||||
fn preOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void {
|
||||
if (root == null) return;
|
||||
// Порядок обхода: корень -> левое поддерево -> правое поддерево
|
||||
try list.append(root.?.val);
|
||||
try preOrder(T, root.?.left);
|
||||
try preOrder(T, root.?.right);
|
||||
}
|
||||
|
||||
// Симметричный обход
|
||||
fn inOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void {
|
||||
if (root == null) return;
|
||||
// Порядок обхода: левое поддерево -> корень -> правое поддерево
|
||||
try inOrder(T, root.?.left);
|
||||
try list.append(root.?.val);
|
||||
try inOrder(T, root.?.right);
|
||||
}
|
||||
|
||||
// Обратный обход
|
||||
fn postOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void {
|
||||
if (root == null) return;
|
||||
// Порядок обхода: левое поддерево -> правое поддерево -> корень
|
||||
try postOrder(T, root.?.left);
|
||||
try postOrder(T, root.?.right);
|
||||
try list.append(root.?.val);
|
||||
}
|
||||
|
||||
// Driver Code
|
||||
pub fn main() !void {
|
||||
// Инициализация аллокатора памяти
|
||||
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer mem_arena.deinit();
|
||||
const mem_allocator = mem_arena.allocator();
|
||||
|
||||
// Инициализировать двоичное дерево
|
||||
// Здесь используется функция, напрямую строящая двоичное дерево из массива
|
||||
var nums = [_]i32{1, 2, 3, 4, 5, 6, 7};
|
||||
var root = try inc.TreeUtil.arrToTree(i32, mem_allocator, &nums);
|
||||
std.debug.print("Инициализация двоичного дерева\n", .{});
|
||||
try inc.PrintUtil.printTree(root, null, false);
|
||||
|
||||
// Предварительный обход
|
||||
list.clearRetainingCapacity();
|
||||
try preOrder(i32, root);
|
||||
std.debug.print("\nПоследовательность печати узлов при предварительном обходе = ", .{});
|
||||
inc.PrintUtil.printList(i32, list);
|
||||
|
||||
// Симметричный обход
|
||||
list.clearRetainingCapacity();
|
||||
try inOrder(i32, root);
|
||||
std.debug.print("\nПоследовательность печати узлов при симметричном обходе = ", .{});
|
||||
inc.PrintUtil.printList(i32, list);
|
||||
|
||||
// Обратный обход
|
||||
list.clearRetainingCapacity();
|
||||
try postOrder(i32, root);
|
||||
std.debug.print("\nПоследовательность печати узлов при обратном обходе = ", .{});
|
||||
inc.PrintUtil.printList(i32, list);
|
||||
|
||||
_ = try std.io.getStdIn().reader().readByte();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// File: PrintUtil.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
const std = @import("std");
|
||||
pub const ListUtil = @import("ListNode.zig");
|
||||
pub const ListNode = ListUtil.ListNode;
|
||||
pub const TreeUtil = @import("TreeNode.zig");
|
||||
pub const TreeNode = TreeUtil.TreeNode;
|
||||
|
||||
// Вывести очередь
|
||||
pub fn printQueue(comptime T: type, queue: std.TailQueue(T)) void {
|
||||
var node = queue.first;
|
||||
std.debug.print("[", .{});
|
||||
var i: i32 = 0;
|
||||
while (node != null) : (i += 1) {
|
||||
var data = node.?.data;
|
||||
std.debug.print("{}{s}", .{ data, if (i == queue.len - 1) "]" else ", " });
|
||||
node = node.?.next;
|
||||
}
|
||||
}
|
||||
|
||||
// Вывести хеш-таблицу
|
||||
pub fn printHashMap(comptime TKey: type, comptime TValue: type, map: std.AutoHashMap(TKey, TValue)) void {
|
||||
var it = map.iterator();
|
||||
while (it.next()) |kv| {
|
||||
var key = kv.key_ptr.*;
|
||||
var value = kv.value_ptr.*;
|
||||
std.debug.print("{} -> {s}\n", .{ key, value });
|
||||
}
|
||||
}
|
||||
|
||||
// Вывести кучу
|
||||
pub fn printHeap(comptime T: type, mem_allocator: std.mem.Allocator, queue: anytype) !void {
|
||||
var arr = queue.items;
|
||||
var len = queue.len;
|
||||
std.debug.print("Массивное представление кучи:", .{});
|
||||
printArray(T, arr[0..len]);
|
||||
std.debug.print("\nДревовидное представление кучи:\n", .{});
|
||||
var root = try TreeUtil.arrToTree(T, mem_allocator, arr[0..len]);
|
||||
try printTree(root, null, false);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// File: include.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com)
|
||||
|
||||
pub const PrintUtil = @import("PrintUtil.zig");
|
||||
pub const TreeUtil = @import("TreeNode.zig");
|
||||
pub const TreeNode = TreeUtil.TreeNode;
|
||||
@@ -0,0 +1,25 @@
|
||||
const std = @import("std");
|
||||
|
||||
const iteration = @import("chapter_computational_complexity/iteration.zig");
|
||||
const recursion = @import("chapter_computational_complexity/recursion.zig");
|
||||
const time_complexity = @import("chapter_computational_complexity/time_complexity.zig");
|
||||
const space_complexity = @import("chapter_computational_complexity/space_complexity.zig");
|
||||
const worst_best_time_complexity = @import("chapter_computational_complexity/worst_best_time_complexity.zig");
|
||||
|
||||
const array = @import("chapter_array_and_linkedlist/array.zig");
|
||||
const linked_list = @import("chapter_array_and_linkedlist/linked_list.zig");
|
||||
const list = @import("chapter_array_and_linkedlist/list.zig");
|
||||
const my_list = @import("chapter_array_and_linkedlist/my_list.zig");
|
||||
|
||||
pub fn main() !void {
|
||||
try iteration.run();
|
||||
recursion.run();
|
||||
time_complexity.run();
|
||||
try space_complexity.run();
|
||||
worst_best_time_complexity.run();
|
||||
|
||||
try array.run();
|
||||
linked_list.run();
|
||||
try list.run();
|
||||
try my_list.run();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// File: ListNode.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Узел связного списка
|
||||
pub fn ListNode(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
val: T = 0,
|
||||
next: ?*Self = null,
|
||||
|
||||
// Initialize a list node with specific value
|
||||
pub fn init(self: *Self, x: i32) void {
|
||||
self.val = x;
|
||||
self.next = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Десериализовать список в связный список
|
||||
pub fn listToLinkedList(comptime T: type, allocator: std.mem.Allocator, list: std.ArrayList(T)) !?*ListNode(T) {
|
||||
var dum = try allocator.create(ListNode(T));
|
||||
dum.init(0);
|
||||
var head = dum;
|
||||
for (list.items) |val| {
|
||||
var tmp = try allocator.create(ListNode(T));
|
||||
tmp.init(val);
|
||||
head.next = tmp;
|
||||
head = head.next.?;
|
||||
}
|
||||
return dum.next;
|
||||
}
|
||||
|
||||
// Десериализовать массив в связный список
|
||||
pub fn arrToLinkedList(comptime T: type, mem_allocator: std.mem.Allocator, arr: []T) !?*ListNode(T) {
|
||||
var dum = try mem_allocator.create(ListNode(T));
|
||||
dum.init(0);
|
||||
var head = dum;
|
||||
for (arr) |val| {
|
||||
var tmp = try mem_allocator.create(ListNode(T));
|
||||
tmp.init(val);
|
||||
head.next = tmp;
|
||||
head = head.next.?;
|
||||
}
|
||||
return dum.next;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// File: TreeNode.zig
|
||||
// Created Time: 2023-01-07
|
||||
// Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Узел двоичного дерева
|
||||
pub fn TreeNode(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
val: T = undefined, // Значение узла
|
||||
height: i32 = undefined, // Высота узла
|
||||
left: ?*Self = null, // Указатель на левый дочерний узел
|
||||
right: ?*Self = null, // Указатель на правый дочерний узел
|
||||
|
||||
// Initialize a tree node with specific value
|
||||
pub fn init(self: *Self, x: i32) void {
|
||||
self.val = x;
|
||||
self.height = 0;
|
||||
self.left = null;
|
||||
self.right = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Десериализовать массив в двоичное дерево
|
||||
pub fn arrToTree(comptime T: type, allocator: std.mem.Allocator, arr: []T) !?*TreeNode(T) {
|
||||
if (arr.len == 0) return null;
|
||||
var root = try allocator.create(TreeNode(T));
|
||||
root.init(arr[0]);
|
||||
const L = std.TailQueue(*TreeNode(T));
|
||||
var que = L{};
|
||||
var root_node = try allocator.create(L.Node);
|
||||
root_node.data = root;
|
||||
que.append(root_node);
|
||||
var index: usize = 0;
|
||||
while (que.len > 0) {
|
||||
const que_node = que.popFirst().?;
|
||||
var node = que_node.data;
|
||||
index += 1;
|
||||
if (index >= arr.len) break;
|
||||
if (index < arr.len) {
|
||||
var tmp = try allocator.create(TreeNode(T));
|
||||
tmp.init(arr[index]);
|
||||
node.left = tmp;
|
||||
var tmp_node = try allocator.create(L.Node);
|
||||
tmp_node.data = node.left.?;
|
||||
que.append(tmp_node);
|
||||
}
|
||||
index += 1;
|
||||
if (index >= arr.len) break;
|
||||
if (index < arr.len) {
|
||||
var tmp = try allocator.create(TreeNode(T));
|
||||
tmp.init(arr[index]);
|
||||
node.right = tmp;
|
||||
var tmp_node = try allocator.create(L.Node);
|
||||
tmp_node.data = node.right.?;
|
||||
que.append(tmp_node);
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// File: format.zig
|
||||
// Created Time: 2025-07-19
|
||||
// Author: CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
const ListNode = @import("ListNode.zig").ListNode;
|
||||
const TreeNode = @import("TreeNode.zig").TreeNode;
|
||||
|
||||
pub fn slice(items: anytype) SliceFormatter(@TypeOf(items)) {
|
||||
return .{ .items = items };
|
||||
}
|
||||
|
||||
pub fn SliceFormatter(comptime SliceType: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
items: SliceType,
|
||||
|
||||
pub fn format(
|
||||
self: Self,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
try writer.writeAll("[");
|
||||
|
||||
if (self.items.len > 0) {
|
||||
for (self.items, 0..) |item, i| {
|
||||
try std.fmt.format(writer, "{}", .{item});
|
||||
if (i != self.items.len - 1) {
|
||||
try writer.writeAll(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try writer.writeAll("]");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn linkedList(comptime T: type, head: *const ListNode(T)) LinkedListFormatter(T) {
|
||||
return .{ .head = head };
|
||||
}
|
||||
|
||||
pub fn LinkedListFormatter(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
head: *const ListNode(T),
|
||||
|
||||
pub fn format(
|
||||
self: Self,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
try printLinkedList(self.head, writer);
|
||||
}
|
||||
|
||||
pub fn printLinkedList(head: *const ListNode(T), writer: anytype) !void {
|
||||
try std.fmt.format(writer, "{}", .{head.val});
|
||||
if (head.next) |next_node| {
|
||||
try writer.writeAll("->");
|
||||
try printLinkedList(next_node, writer);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tree(comptime T: type, root: ?*const TreeNode(T)) TreeFormatter(T) {
|
||||
return .{ .root = root };
|
||||
}
|
||||
|
||||
pub fn TreeFormatter(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
root: ?*const TreeNode(T),
|
||||
|
||||
pub fn format(
|
||||
self: Self,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
try printTree(self.root, null, false, writer);
|
||||
}
|
||||
|
||||
// Вывести двоичное дерево
|
||||
fn printTree(root: ?*const TreeNode(T), prev: ?*Trunk, isRight: bool, writer: anytype) !void {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var prev_str = " ";
|
||||
var trunk = Trunk{ .prev = prev, .str = prev_str };
|
||||
|
||||
try printTree(root.?.right, &trunk, true, writer);
|
||||
|
||||
if (prev == null) {
|
||||
trunk.str = "———";
|
||||
} else if (isRight) {
|
||||
trunk.str = "/———";
|
||||
prev_str = " |";
|
||||
} else {
|
||||
trunk.str = "\\———";
|
||||
prev.?.str = prev_str;
|
||||
}
|
||||
|
||||
try showTrunks(&trunk, writer);
|
||||
try std.fmt.format(writer, "{d}\n", .{root.?.val});
|
||||
|
||||
if (prev) |_| {
|
||||
prev.?.str = prev_str;
|
||||
}
|
||||
trunk.str = " |";
|
||||
|
||||
try printTree(root.?.left, &trunk, false, writer);
|
||||
}
|
||||
|
||||
// Вывести двоичное дерево
|
||||
// Этот вывод дерева заимствован из TECHIE DELIGHT
|
||||
// https://www.techiedelight.com/c-program-print-binary-tree/
|
||||
const Trunk = struct {
|
||||
prev: ?*Trunk = null,
|
||||
str: []const u8 = undefined,
|
||||
|
||||
pub fn init(self: *Trunk, prev: ?*Trunk, str: []const u8) void {
|
||||
self.prev = prev;
|
||||
self.str = str;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn showTrunks(p: ?*Trunk, writer: anytype) !void {
|
||||
if (p == null) return;
|
||||
try showTrunks(p.?.prev, writer);
|
||||
try std.fmt.format(writer, "{s}", .{p.?.str});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// File: format.zig
|
||||
// Created Time: 2025-07-15
|
||||
// Author: CreatorMetaSky (creator_meta_sky@163.com)
|
||||
|
||||
const std = @import("std");
|
||||
pub const fmt = @import("format.zig");
|
||||
pub const ListNode = @import("ListNode.zig").ListNode;
|
||||
pub const TreeNode = @import("TreeNode.zig").TreeNode;
|
||||
Reference in New Issue
Block a user