From ec25970e8e535db6903d59f03850b4f9497fb210 Mon Sep 17 00:00:00 2001 From: krahets Date: Thu, 9 Feb 2023 22:57:25 +0800 Subject: [PATCH] Update .gitignore Add build script for Zig. --- .gitignore | 5 +- .../leetcode_two_sum.zig | 64 ++++----- .../time_complexity.zig | 13 +- codes/zig/chapter_hashing/array_hash_map.zig | 2 +- .../zig/chapter_searching/hashing_search.zig | 2 +- codes/zig/chapter_searching/linear_search.zig | 4 +- codes/zig/chapter_sorting/quick_sort.zig | 3 + docs/chapter_array_and_linkedlist/array.md | 65 +-------- .../linked_list.md | 39 +---- docs/chapter_array_and_linkedlist/list.md | 117 +-------------- .../space_complexity.md | 89 +----------- .../space_time_tradeoff.md | 37 +---- .../time_complexity.md | 135 ++---------------- docs/chapter_hashing/hash_map.md | 2 + docs/chapter_heap/heap.md | 12 +- docs/chapter_searching/binary_search.md | 4 +- docs/chapter_searching/hashing_search.md | 4 +- docs/chapter_searching/linear_search.md | 4 +- docs/chapter_sorting/bubble_sort.md | 4 +- docs/chapter_sorting/insertion_sort.md | 2 +- docs/chapter_sorting/quick_sort.md | 8 +- docs/chapter_stack_and_queue/queue.md | 4 +- docs/chapter_stack_and_queue/stack.md | 4 +- docs/chapter_tree/avl_tree.md | 16 ++- docs/chapter_tree/binary_search_tree.md | 6 +- docs/chapter_tree/binary_tree_traversal.md | 6 +- docs/utils/build_markdown.py | 8 ++ docs/utils/extract_code_go.py | 6 - docs/utils/extract_code_java.py | 5 +- docs/utils/extract_code_zig.py | 90 ++++++++++++ 30 files changed, 227 insertions(+), 533 deletions(-) create mode 100644 docs/utils/extract_code_zig.py diff --git a/.gitignore b/.gitignore index 64103ace0..59c4077a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,9 @@ -# MacOS Desktop Services Store +# macOS .DS_Store # Editor .vscode/ .idea/ -hello-algo.iml # mkdocs files .cache/ @@ -13,4 +12,4 @@ docs/overrides/ # build build/ -site/ \ No newline at end of file +site/ diff --git a/codes/zig/chapter_computational_complexity/leetcode_two_sum.zig b/codes/zig/chapter_computational_complexity/leetcode_two_sum.zig index f68e7f957..533211625 100644 --- a/codes/zig/chapter_computational_complexity/leetcode_two_sum.zig +++ b/codes/zig/chapter_computational_complexity/leetcode_two_sum.zig @@ -6,43 +6,40 @@ const std = @import("std"); const inc = @import("include"); // 方法一:暴力枚举 -const SolutionBruteForce = struct { - pub fn twoSum(self: *SolutionBruteForce, nums: []i32, target: i32) [2]i32 { - _ = self; - 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(i32, i), @intCast(i32, j)}; - } +pub fn twoSumBruteForce(nums: []i32, target: i32) [2]i32 { + _ = self; + 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(i32, i), @intCast(i32, j)}; } } - return undefined; } -}; + return undefined; +} // 方法二:辅助哈希表 -const SolutionHashMap = struct { - pub fn twoSum(self: *SolutionHashMap, nums: []i32, target: i32) ![2]i32 { - _ = self; - 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(i32, i)}; - } - try dic.put(nums[i], @intCast(i32, i)); +pub fn twoSumHashTable(nums: []i32, target: i32) ![2]i32 { + _ = self; + 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(i32, i)}; } - return undefined; + try dic.put(nums[i], @intCast(i32, i)); } -}; + return undefined; +} + // Driver Code pub fn main() !void { @@ -50,14 +47,11 @@ pub fn main() !void { var nums = [_]i32{ 2, 7, 11, 15 }; var target: i32 = 9; // 方法一 - var slt1 = SolutionBruteForce{}; - var res = slt1.twoSum(&nums, target); + twoSumBruteForce(&nums, target); std.debug.print("方法一 res = ", .{}); inc.PrintUtil.printArray(i32, &res); // 方法二 - var slt2 = SolutionHashMap{}; - res = try slt2.twoSum(&nums, target); + twoSumHashTable(&nums, target); std.debug.print("方法二 res = ", .{}); inc.PrintUtil.printArray(i32, &res); } - diff --git a/codes/zig/chapter_computational_complexity/time_complexity.zig b/codes/zig/chapter_computational_complexity/time_complexity.zig index 047950052..564bb7b70 100644 --- a/codes/zig/chapter_computational_complexity/time_complexity.zig +++ b/codes/zig/chapter_computational_complexity/time_complexity.zig @@ -72,7 +72,7 @@ fn bubbleSort(nums: []i32) i32 { } // 指数阶(循环实现) -fn exponential(n: i32) i32{ +fn exponential(n: i32) i32 { var count: i32 = 0; var bas: i32 = 1; var i: i32 = 0; @@ -89,14 +89,13 @@ fn exponential(n: i32) i32{ } // 指数阶(递归实现) -fn expRecur(n: i32) i32{ +fn expRecur(n: i32) i32 { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } // 对数阶(循环实现) -fn logarithmic(n: f32) i32 -{ +fn logarithmic(n: f32) i32 { var count: i32 = 0; var n_var = n; while (n_var > 1) @@ -108,15 +107,13 @@ fn logarithmic(n: f32) i32 } // 对数阶(递归实现) -fn logRecur(n: f32) i32 -{ +fn logRecur(n: f32) i32 { if (n <= 1) return 0; return logRecur(n / 2) + 1; } // 线性对数阶 -fn linearLogRecur(n: f32) i32 -{ +fn linearLogRecur(n: f32) i32 { if (n <= 1) return 1; var count: i32 = linearLogRecur(n / 2) + linearLogRecur(n / 2); diff --git a/codes/zig/chapter_hashing/array_hash_map.zig b/codes/zig/chapter_hashing/array_hash_map.zig index af73bc21d..44cf02bd7 100644 --- a/codes/zig/chapter_hashing/array_hash_map.zig +++ b/codes/zig/chapter_hashing/array_hash_map.zig @@ -10,7 +10,7 @@ const Entry = struct { key: usize = undefined, val: []const u8 = undefined, - pub fn init(key: usize, val: []const u8) Entry { + pub fn init(key: usize, val: []const u8) Entry { return Entry { .key = key, .val = val, diff --git a/codes/zig/chapter_searching/hashing_search.zig b/codes/zig/chapter_searching/hashing_search.zig index 1b29276ad..ba3abba34 100644 --- a/codes/zig/chapter_searching/hashing_search.zig +++ b/codes/zig/chapter_searching/hashing_search.zig @@ -13,7 +13,7 @@ fn hashingSearchArray(comptime T: type, map: std.AutoHashMap(T, T), target: T) T 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 diff --git a/codes/zig/chapter_searching/linear_search.zig b/codes/zig/chapter_searching/linear_search.zig index 1f4c84fac..151ed5ae3 100644 --- a/codes/zig/chapter_searching/linear_search.zig +++ b/codes/zig/chapter_searching/linear_search.zig @@ -6,7 +6,7 @@ const std = @import("std"); const inc = @import("include"); // 线性查找(数组) -fn linearSearchList(comptime T: type, nums: std.ArrayList(T), target: T) T { +fn linearSearchArray(comptime T: type, nums: std.ArrayList(T), target: T) T { // 遍历数组 for (nums.items) |num, i| { // 找到目标元素, 返回其索引 @@ -38,7 +38,7 @@ pub fn main() !void { 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 = linearSearchList(i32, nums, target); + var index = linearSearchArray(i32, nums, target); std.debug.print("目标元素 3 的索引 = {}\n", .{index}); // 在链表中执行线性查找 diff --git a/codes/zig/chapter_sorting/quick_sort.zig b/codes/zig/chapter_sorting/quick_sort.zig index 1a62e3879..2b1d92115 100644 --- a/codes/zig/chapter_sorting/quick_sort.zig +++ b/codes/zig/chapter_sorting/quick_sort.zig @@ -7,6 +7,7 @@ const inc = @import("include"); // 快速排序类 const QuickSort = struct { + // 元素交换 pub fn swap(nums: []i32, i: usize, j: usize) void { var tmp = nums[i]; @@ -42,6 +43,7 @@ const QuickSort = struct { // 快速排序类(中位基准数优化) const QuickSortMedian = struct { + // 元素交换 pub fn swap(nums: []i32, i: usize, j: usize) void { var tmp = nums[i]; @@ -95,6 +97,7 @@ const QuickSortMedian = struct { // 快速排序类(尾递归优化) const QuickSortTailCall = struct { + // 元素交换 pub fn swap(nums: []i32, i: usize, j: usize) void { var tmp = nums[i]; diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index 6412c964e..a015a5389 100755 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -171,14 +171,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Zig" ```zig title="array.zig" - // 随机返回一个数组元素 - pub fn randomAccess(nums: []i32) i32 { - // 在区间 [0, nums.len) 中随机抽取一个整数 - var randomIndex = std.crypto.random.intRangeLessThan(usize, 0, nums.len); - // 获取并返回随机元素 - var randomNum = nums[randomIndex]; - return randomNum; - } + [class]{}-[func]{randomAccess} ``` ## 4.1.2. 数组缺点 @@ -242,16 +235,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Zig" ```zig title="array.zig" - // 扩展数组长度 - pub fn extend(mem_allocator: std.mem.Allocator, nums: []i32, enlarge: usize) ![]i32 { - // 初始化一个扩展长度后的数组 - var res = try mem_allocator.alloc(i32, nums.len + enlarge); - std.mem.set(i32, res, 0); - // 将原数组中的所有元素复制到新数组 - std.mem.copy(i32, res, nums); - // 返回扩展后的新数组 - return res; - } + [class]{}-[func]{extend} ``` **数组中插入或删除元素效率低下**。假设我们想要在数组中间某位置插入一个元素,由于数组元素在内存中是“紧挨着的”,它们之间没有空间再放任何数据。因此,我们不得不将此索引之后的所有元素都向后移动一位,然后再把元素赋值给该索引。删除元素也是类似,需要把此索引之后的元素都向前移动一位。总体看有以下缺点: @@ -337,25 +321,9 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Zig" ```zig title="array.zig" - // 在数组的索引 index 处插入元素 num - 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]; - } - } + [class]{}-[func]{insert} + + [class]{}-[func]{remove} ``` ## 4.1.3. 数组常用操作 @@ -419,20 +387,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Zig" ```zig title="array.zig" - // 遍历数组 - pub fn traverse(nums: []i32) void { - var count: i32 = 0; - // 通过索引遍历数组 - var i: i32 = 0; - while (i < nums.len) : (i += 1) { - count += 1; - } - count = 0; - // 直接遍历数组 - for (nums) |_| { - count += 1; - } - } + [class]{}-[func]{traverse} ``` **数组查找**。通过遍历数组,查找数组内的指定元素,并输出对应索引。 @@ -494,13 +449,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Zig" ```zig title="array.zig" - // 在数组中查找指定元素 - pub fn find(nums: []i32, target: i32) i32 { - for (nums) |num, i| { - if (num == target) return @intCast(i32, i); - } - return -1; - } + [class]{}-[func]{find} ``` ## 4.1.4. 数组典型应用 diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index 7a760186d..ae6c627c9 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -395,21 +395,9 @@ comments: true === "Zig" ```zig title="linked_list.zig" - // 在链表的结点 n0 之后插入结点 P - pub fn insert(n0: ?*inc.ListNode(i32), P: ?*inc.ListNode(i32)) void { - var n1 = n0.?.next; - n0.?.next = P; - P.?.next = n1; - } + [class]{}-[func]{insert} - // 删除链表的结点 n0 之后的首个结点 - pub fn remove(n0: ?*inc.ListNode(i32)) void { - if (n0.?.next == null) return; - // n0 -> P -> n1 - var P = n0.?.next; - var n1 = P.?.next; - n0.?.next = n1; - } + [class]{}-[func]{remove} ``` ## 4.2.2. 链表缺点 @@ -473,16 +461,7 @@ comments: true === "Zig" ```zig title="linked_list.zig" - // 访问链表中索引为 index 的结点 - pub fn access(node: ?*inc.ListNode(i32), index: i32) ?*inc.ListNode(i32) { - var head = node; - var i: i32 = 0; - while (i < index) : (i += 1) { - head = head.?.next; - if (head == null) return null; - } - return head; - } + [class]{}-[func]{access} ``` **链表的内存占用多**。链表以结点为单位,每个结点除了保存值外,还需额外保存指针(引用)。这意味着同样数据量下,链表比数组需要占用更多内存空间。 @@ -548,17 +527,7 @@ comments: true === "Zig" ```zig title="linked_list.zig" - // 在链表中查找值为 target 的首个结点 - pub fn find(node: ?*inc.ListNode(i32), target: i32) i32 { - var head = node; - var index: i32 = 0; - while (head != null) { - if (head.?.val == target) return index; - head = head.?.next; - index += 1; - } - return -1; - } + [class]{}-[func]{find} ``` ## 4.2.4. 常见链表类型 diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 1c58a0700..822551479 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -770,120 +770,5 @@ comments: true === "Zig" ```zig title="my_list.zig" - // 列表类简易实现 - pub fn MyList(comptime T: type) type { - return struct { - const Self = @This(); - - nums: []T = undefined, // 数组(存储列表元素) - numsCapacity: usize = 10, // 列表容量 - numSize: usize = 0, // 列表长度(即当前元素数量) - extendRatio: usize = 2, // 每次列表扩容的倍数 - 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.nums = try self.mem_allocator.alloc(T, self.numsCapacity); - std.mem.set(T, self.nums, @as(T, 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.numSize; - } - - // 获取列表容量 - pub fn capacity(self: *Self) usize { - return self.numsCapacity; - } - - // 访问元素 - pub fn get(self: *Self, index: usize) T { - // 索引如果越界则抛出异常,下同 - if (index < 0 or index >= self.size()) @panic("索引越界"); - return self.nums[index]; - } - - // 更新元素 - pub fn set(self: *Self, index: usize, num: T) void { - // 索引如果越界则抛出异常,下同 - if (index < 0 or index >= self.size()) @panic("索引越界"); - self.nums[index] = num; - } - - // 尾部添加元素 - pub fn add(self: *Self, num: T) !void { - // 元素数量超出容量时,触发扩容机制 - if (self.size() == self.capacity()) try self.extendCapacity(); - self.nums[self.size()] = num; - // 更新元素数量 - self.numSize += 1; - } - - // 中间插入元素 - pub fn insert(self: *Self, index: usize, num: T) !void { - if (index < 0 or index >= self.size()) @panic("索引越界"); - // 元素数量超出容量时,触发扩容机制 - if (self.size() == self.capacity()) try self.extendCapacity(); - // 索引 i 以及之后的元素都向后移动一位 - var j = self.size() - 1; - while (j >= index) : (j -= 1) { - self.nums[j + 1] = self.nums[j]; - } - self.nums[index] = num; - // 更新元素数量 - self.numSize += 1; - } - - // 删除元素 - pub fn remove(self: *Self, index: usize) T { - if (index < 0 or index >= self.size()) @panic("索引越界"); - var num = self.nums[index]; - // 索引 i 之后的元素都向前移动一位 - var j = index; - while (j < self.size() - 1) : (j += 1) { - self.nums[j] = self.nums[j + 1]; - } - // 更新元素数量 - self.numSize -= 1; - // 返回被删除元素 - return num; - } - - // 列表扩容 - pub fn extendCapacity(self: *Self) !void { - // 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组 - var newCapacity = self.capacity() * self.extendRatio; - var extend = try self.mem_allocator.alloc(T, newCapacity); - std.mem.set(T, extend, @as(T, 0)); - // 将原数组中的所有元素复制到新数组 - std.mem.copy(T, extend, self.nums); - self.nums = extend; - // 更新列表容量 - self.numsCapacity = newCapacity; - } - - // 将列表转换为数组 - pub fn toArray(self: *Self) ![]T { - // 仅转换有效长度范围内的列表元素 - var nums = try self.mem_allocator.alloc(T, self.size()); - std.mem.set(T, nums, @as(T, 0)); - for (nums) |*num, i| { - num.* = self.get(i); - } - return nums; - } - }; - } + [class]{MyList}-[func]{} ``` diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 90406e953..b55fafcc4 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -636,29 +636,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 常数阶 - fn constant(n: i32) void { - // 常量、变量、对象占用 O(1) 空间 - const a: i32 = 0; - var b: i32 = 0; - var nums = [_]i32{0}**10000; - var node = inc.ListNode(i32){.val = 0}; - var i: i32 = 0; - // 循环中的变量占用 O(1) 空间 - while (i < n) : (i += 1) { - var c: i32 = 0; - _ = c; - } - // 循环中的函数占用 O(1) 空间 - i = 0; - while (i < n) : (i += 1) { - _ = function(); - } - _ = a; - _ = b; - _ = nums; - _ = node; - } + [class]{}-[func]{constant} ``` ### 线性阶 $O(n)$ @@ -722,28 +700,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 线性阶 - fn linear(comptime n: i32) !void { - // 长度为 n 的数组占用 O(n) 空间 - var 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; - } + [class]{}-[func]{linear} ``` 以下递归函数会同时存在 $n$ 个未返回的 `algorithm()` 函数,使用 $O(n)$ 大小的栈帧空间。 @@ -805,12 +762,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 线性阶(递归实现) - fn linearRecur(comptime n: i32) void { - std.debug.print("递归 n = {}\n", .{n}); - if (n == 1) return; - linearRecur(n - 1); - } + [class]{}-[func]{linearRecur} ``` ![space_complexity_recursive_linear](space_complexity.assets/space_complexity_recursive_linear.png) @@ -878,22 +830,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 平方阶 - 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); - } - } + [class]{}-[func]{quadratic} ``` 在以下递归函数中,同时存在 $n$ 个未返回的 `algorithm()` ,并且每个函数中都初始化了一个数组,长度分别为 $n, n-1, n-2, ..., 2, 1$ ,平均长度为 $\frac{n}{2}$ ,因此总体使用 $O(n^2)$ 空间。 @@ -955,13 +892,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 平方阶(递归实现) - fn quadraticRecur(comptime n: i32) i32 { - if (n <= 0) return 0; - var nums = [_]i32{0}**n; - std.debug.print("递归 n = {} 中的 nums 长度 = {}\n", .{n, nums.len}); - return quadraticRecur(n - 1); - } + [class]{}-[func]{quadraticRecur} ``` ![space_complexity_recursive_quadratic](space_complexity.assets/space_complexity_recursive_quadratic.png) @@ -1029,15 +960,7 @@ $$ === "Zig" ```zig title="space_complexity.zig" - // 指数阶(建立满二叉树) - fn buildTree(mem_allocator: std.mem.Allocator, n: i32) !?*inc.TreeNode(i32) { - if (n == 0) return null; - const root = try mem_allocator.create(inc.TreeNode(i32)); - root.init(0); - root.left = try buildTree(mem_allocator, n - 1); - root.right = try buildTree(mem_allocator, n - 1); - return root; - } + [class]{}-[func]{buildTree} ``` ![space_complexity_exponential](space_complexity.assets/space_complexity_exponential.png) diff --git a/docs/chapter_computational_complexity/space_time_tradeoff.md b/docs/chapter_computational_complexity/space_time_tradeoff.md index 3a69adda1..0adb5c016 100755 --- a/docs/chapter_computational_complexity/space_time_tradeoff.md +++ b/docs/chapter_computational_complexity/space_time_tradeoff.md @@ -87,23 +87,7 @@ comments: true === "Zig" ```zig title="leetcode_two_sum.zig" - const SolutionBruteForce = struct { - pub fn twoSum(self: *SolutionBruteForce, nums: []i32, target: i32) [2]i32 { - _ = self; - 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(i32, i), @intCast(i32, j)}; - } - } - } - return undefined; - } - }; + [class]{}-[func]{twoSumBruteForce} ``` ### 方法二:辅助哈希表 @@ -169,22 +153,5 @@ comments: true === "Zig" ```zig title="leetcode_two_sum.zig" - const SolutionHashMap = struct { - pub fn twoSum(self: *SolutionHashMap, nums: []i32, target: i32) ![2]i32 { - _ = self; - 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(i32, i)}; - } - try dic.put(nums[i], @intCast(i32, i)); - } - return undefined; - } - }; + [class]{}-[func]{twoSumHashTable} ``` diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index a1ccb62d2..7412b3f17 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -858,17 +858,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 常数阶 - fn constant(n: i32) i32 { - _ = n; - var count: i32 = 0; - const size: i32 = 100_000; - var i: i32 = 0; - while(i 0) : (i -= 1) { - var j: usize = 0; - // 内循环:冒泡操作 - 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; - count += 3; // 元素交换包含 3 个单元操作 - } - } - } - return count; - } + [class]{}-[func]{bubbleSort} ``` ### 指数阶 $O(2^n)$ @@ -1304,22 +1247,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 指数阶(循环实现) - fn exponential(n: i32) i32{ - var count: i32 = 0; - var bas: i32 = 1; - var i: i32 = 0; - // cell 每轮一分为二,形成数列 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; - } + [class]{}-[func]{exponential} ``` ![time_complexity_exponential](time_complexity.assets/time_complexity_exponential.png) @@ -1389,11 +1317,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 指数阶(递归实现) - fn expRecur(n: i32) i32{ - if (n == 1) return 1; - return expRecur(n - 1) + expRecur(n - 1) + 1; - } + [class]{}-[func]{expRecur} ``` ### 对数阶 $O(\log n)$ @@ -1469,18 +1393,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 对数阶(循环实现) - fn logarithmic(n: f32) i32 - { - var count: i32 = 0; - var n_var = n; - while (n_var > 1) - { - n_var = n_var / 2; - count +=1; - } - return count; - } + [class]{}-[func]{logarithmic} ``` ![time_complexity_logarithmic](time_complexity.assets/time_complexity_logarithmic.png) @@ -1550,12 +1463,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 对数阶(递归实现) - fn logRecur(n: f32) i32 - { - if (n <= 1) return 0; - return logRecur(n / 2) + 1; - } + [class]{}-[func]{logRecur} ``` ### 线性对数阶 $O(n \log n)$ @@ -1630,18 +1538,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 线性对数阶 - fn linearLogRecur(n: f32) i32 - { - if (n <= 1) return 1; - var count: i32 = linearLogRecur(n / 2) + - linearLogRecur(n / 2); - var i: f32 = 0; - while (i < n) : (i += 1) { - count += 1; - } - return count; - } + [class]{}-[func]{linearLogRecur} ``` ![time_complexity_logarithmic_linear](time_complexity.assets/time_complexity_logarithmic_linear.png) @@ -1723,17 +1620,7 @@ $$ === "Zig" ```zig title="time_complexity.zig" - // 阶乘阶(递归实现) - fn factorialRecur(n: i32) i32 { - if (n == 0) return 1; - var count: i32 = 0; - var i: i32 = 0; - // 从 1 个分裂出 n 个 - while (i < n) : (i += 1) { - count += factorialRecur(n - 1); - } - return count; - } + [class]{}-[func]{factorialRecur} ``` ![time_complexity_factorial](time_complexity.assets/time_complexity_factorial.png) diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index a6e9c1a6f..1f62e01d3 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -486,7 +486,9 @@ $$ === "Zig" ```zig title="array_hash_map.zig" + [class]{Entry}-[func]{} + [class]{ArrayHashMap}-[func]{} ``` ## 6.1.4. 哈希冲突 diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index ef244b575..b5c4f7fc5 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -342,7 +342,11 @@ comments: true === "Zig" ```zig title="my_heap.zig" + [class]{MaxHeap}-[func]{left} + + [class]{MaxHeap}-[func]{right} + [class]{MaxHeap}-[func]{parent} ``` ### 访问堆顶元素 @@ -406,7 +410,7 @@ comments: true === "Zig" ```zig title="my_heap.zig" - + [class]{MaxHeap}-[func]{peek} ``` ### 元素入堆 @@ -506,7 +510,9 @@ comments: true === "Zig" ```zig title="my_heap.zig" + [class]{MaxHeap}-[func]{push} + [class]{MaxHeap}-[func]{siftUp} ``` ### 堆顶元素出堆 @@ -622,7 +628,9 @@ comments: true === "Zig" ```zig title="my_heap.zig" + [class]{MaxHeap}-[func]{poll} + [class]{MaxHeap}-[func]{siftDown} ``` ### 输入数据并建堆 * @@ -688,7 +696,7 @@ comments: true === "Zig" ```zig title="my_heap.zig" - + [class]{MaxHeap}-[func]{init} ``` 那么,第二种建堆方法的时间复杂度时多少呢?我们来做一下简单推算。 diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index ec48b21d0..12ab6aa58 100755 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -108,7 +108,7 @@ $$ === "Zig" ```zig title="binary_search.zig" - + [class]{}-[func]{binarySearch} ``` ### “左闭右开”实现 @@ -172,7 +172,7 @@ $$ === "Zig" ```zig title="binary_search.zig" - + [class]{}-[func]{binarySearch1} ``` ### 两种表示对比 diff --git a/docs/chapter_searching/hashing_search.md b/docs/chapter_searching/hashing_search.md index 1fc1410d2..2a7b00675 100755 --- a/docs/chapter_searching/hashing_search.md +++ b/docs/chapter_searching/hashing_search.md @@ -73,7 +73,7 @@ comments: true === "Zig" ```zig title="hashing_search.zig" - + [class]{}-[func]{hashingSearchArray} ``` 再比如,如果我们想要给定一个目标结点值 `target` ,获取对应的链表结点对象,那么也可以使用哈希查找实现。 @@ -137,7 +137,7 @@ comments: true === "Zig" ```zig title="hashing_search.zig" - + [class]{}-[func]{hashingSearchLinkedList} ``` ## 10.3.2. 复杂度分析 diff --git a/docs/chapter_searching/linear_search.md b/docs/chapter_searching/linear_search.md index dac32b892..bb1bf33eb 100755 --- a/docs/chapter_searching/linear_search.md +++ b/docs/chapter_searching/linear_search.md @@ -69,7 +69,7 @@ comments: true === "Zig" ```zig title="linear_search.zig" - + [class]{}-[func]{linearSearchArray} ``` 再比如,我们想要在给定一个目标结点值 `target` ,返回此结点对象,也可以在链表中进行线性查找。 @@ -131,7 +131,7 @@ comments: true === "Zig" ```zig title="linear_search.zig" - + [class]{}-[func]{linearSearchLinkedList} ``` ## 10.1.2. 复杂度分析 diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 1f02d0c6b..4581bb4fa 100755 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -120,7 +120,7 @@ comments: true === "Zig" ```zig title="bubble_sort.zig" - + [class]{}-[func]{bubbleSort} ``` ## 11.2.2. 算法特性 @@ -217,5 +217,5 @@ comments: true === "Zig" ```zig title="bubble_sort.zig" - + [class]{}-[func]{bubbleSortWithFlag} ``` diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md index f35f8bd42..ff29ecaaf 100755 --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -97,7 +97,7 @@ comments: true === "Zig" ```zig title="insertion_sort.zig" - + [class]{}-[func]{insertionSort} ``` ## 11.3.2. 算法特性 diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index 5e43221ba..ba1a32802 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -112,7 +112,9 @@ comments: true === "Zig" ```zig title="quick_sort.zig" + [class]{QuickSort}-[func]{swap} + [class]{QuickSort}-[func]{partition} ``` !!! note "快速排序的分治思想" @@ -188,7 +190,7 @@ comments: true === "Zig" ```zig title="quick_sort.zig" - + [class]{QuickSort}-[func]{quickSort} ``` ## 11.4.2. 算法特性 @@ -294,7 +296,9 @@ comments: true === "Zig" ```zig title="quick_sort.zig" + [class]{QuickSortMedian}-[func]{medianThree} + [class]{QuickSortMedian}-[func]{partition} ``` ## 11.4.5. 尾递归优化 @@ -360,5 +364,5 @@ comments: true === "Zig" ```zig title="quick_sort.zig" - + [class]{QuickSortTailCall}-[func]{quickSort} ``` diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index e6664e82d..367f25ea2 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -338,7 +338,7 @@ comments: true === "Zig" ```zig title="linkedlist_queue.zig" - + [class]{LinkedListQueue}-[func]{} ``` ### 基于数组的实现 @@ -415,7 +415,7 @@ comments: true === "Zig" ```zig title="array_queue.zig" - + [class]{ArrayQueue}-[func]{} ``` 以上代码仍存在局限性,即长度不可变。然而,我们可以通过将数组替换为列表(即动态数组)来引入扩容机制,有兴趣的同学可以尝试实现。 diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 0b13e7324..867c195af 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -341,7 +341,7 @@ comments: true === "Zig" ```zig title="linkedlist_stack.zig" - + [class]{LinkedListStack}-[func]{} ``` ### 基于数组的实现 @@ -416,7 +416,7 @@ comments: true === "Zig" ```zig title="array_stack.zig" - + [class]{ArrayStack}-[func]{} ``` ## 5.1.3. 两种实现对比 diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 51e5d4b68..29de45491 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -228,7 +228,9 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Zig" ```zig title="avl_tree.zig" + [class]{AVLTree}-[func]{height} + [class]{AVLTree}-[func]{updateHeight} ``` ### 结点平衡因子 @@ -294,7 +296,7 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Zig" ```zig title="avl_tree.zig" - + [class]{AVLTree}-[func]{balanceFactor} ``` !!! note @@ -386,7 +388,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Zig" ```zig title="avl_tree.zig" - + [class]{AVLTree}-[func]{rightRotate} ``` ### Case 2 - 左旋 @@ -460,7 +462,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Zig" ```zig title="avl_tree.zig" - + [class]{AVLTree}-[func]{leftRotate} ``` ### Case 3 - 先左后右 @@ -553,7 +555,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Zig" ```zig title="avl_tree.zig" - + [class]{AVLTree}-[func]{rotate} ``` ## 7.4.3. AVL 树常用操作 @@ -637,7 +639,9 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Zig" ```zig title="avl_tree.zig" + [class]{AVLTree}-[func]{insert} + [class]{AVLTree}-[func]{insertHelper} ``` ### 删除结点 @@ -733,7 +737,11 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Zig" ```zig title="avl_tree.zig" + [class]{AVLTree}-[func]{remove} + + [class]{AVLTree}-[func]{removeHelper} + [class]{AVLTree}-[func]{getInOrderNext} ``` ### 查找结点 diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 613a7f223..01d9160fd 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -92,7 +92,7 @@ comments: true === "Zig" ```zig title="binary_search_tree.zig" - + [class]{BinarySearchTree}-[func]{search} ``` ### 插入结点 @@ -163,7 +163,7 @@ comments: true === "Zig" ```zig title="binary_search_tree.zig" - + [class]{BinarySearchTree}-[func]{insert} ``` 为了插入结点,需要借助 **辅助结点 `pre`** 保存上一轮循环的结点,这样在遍历到 $\text{null}$ 时,我们也可以获取到其父结点,从而完成结点插入操作。 @@ -275,7 +275,9 @@ comments: true === "Zig" ```zig title="binary_search_tree.zig" + [class]{BinarySearchTree}-[func]{remove} + [class]{BinarySearchTree}-[func]{getInOrderNext} ``` ### 排序 diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 013477243..5458be7b0 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -75,7 +75,7 @@ comments: true === "Zig" ```zig title="binary_tree_bfs.zig" - + [class]{}-[func]{hierOrder} ``` ## 7.2.2. 前序、中序、后序遍历 @@ -187,7 +187,11 @@ comments: true === "Zig" ```zig title="binary_tree_dfs.zig" + [class]{}-[func]{preOrder} + [class]{}-[func]{inOrder} + + [class]{}-[func]{postOrder} ``` !!! note diff --git a/docs/utils/build_markdown.py b/docs/utils/build_markdown.py index 480d2700c..5af0194f8 100755 --- a/docs/utils/build_markdown.py +++ b/docs/utils/build_markdown.py @@ -17,6 +17,7 @@ from docs.utils.extract_code_jsts import ExtractCodeBlocksJSTS from docs.utils.extract_code_swift import ExtractCodeBlocksSwift from docs.utils.extract_code_csharp import ExtractCodeBlocksCSharp from docs.utils.extract_code_go import ExtractCodeBlocksGo +from docs.utils.extract_code_zig import ExtractCodeBlocksZig def build_markdown(md_path): @@ -41,6 +42,12 @@ def build_markdown(md_path): # Get the coresponding language code extractor lang = file_match[1] file_name = file_match[2] + + if lang not in extractor_dict: + print(f"warning: {lang} is not in the extractor_dict") + i += 1 + continue + extractor = extractor_dict[lang] # Get code blocks if file_name not in code_blocks_dict: @@ -98,6 +105,7 @@ extractor_dict = { "typescript": ExtractCodeBlocksJSTS(), "swift": ExtractCodeBlocksSwift(), "csharp": ExtractCodeBlocksCSharp(), + "zig": ExtractCodeBlocksZig(), } diff --git a/docs/utils/extract_code_go.py b/docs/utils/extract_code_go.py index a96bcb6b4..194dfbf39 100644 --- a/docs/utils/extract_code_go.py +++ b/docs/utils/extract_code_go.py @@ -21,12 +21,6 @@ class ExtractCodeBlocksGo(ExtractCodeBlocksJava): self.func_pattern_keys = ["total", "ind", "class", "label", "params", "return"] self.class_pattern_keys = ["total", "ind", "label"] - - # Pattern to match the start and end of a block - self.block_end_pattern = '^\s{ind}\}' - self.block_start_pattern = '^\s{ind}\/\*.+\*\/' - self.block_start_shift = 0 - self.block_end_shift = 0 def extract(self, file_path): """ diff --git a/docs/utils/extract_code_java.py b/docs/utils/extract_code_java.py index 41b09b6ab..699bcc42d 100644 --- a/docs/utils/extract_code_java.py +++ b/docs/utils/extract_code_java.py @@ -22,8 +22,8 @@ class ExtractCodeBlocksJava: self.class_pattern_keys = ["total", "scope", "label"] # Pattern to match the start and end of a block - self.block_end_pattern = '^\s{ind}\}' self.block_start_pattern = '^\s{ind}\/\*.+\*\/' + self.block_end_pattern = '^\s{ind}\}' self.block_start_shift = 0 self.block_end_shift = 0 @@ -156,8 +156,9 @@ class ExtractCodeBlocksJava: header_line = func["line_number"]["header"] - \ func["line_number"]["start"] block[header_line] = block[header_line] \ - .replace("static ", "").replace("public ", "").replace("private ", "") + .replace("static ", "", 1).replace("public ", "", 1).replace("private ", "", 1) for clas in classes.values(): + remove_keyword(clas) for func in clas["funcs"].values(): remove_keyword(func) for func in funcs.values(): diff --git a/docs/utils/extract_code_zig.py b/docs/utils/extract_code_zig.py new file mode 100644 index 000000000..6de189b3a --- /dev/null +++ b/docs/utils/extract_code_zig.py @@ -0,0 +1,90 @@ +""" +File: extract_code_zig.py +Created Time: 2023-02-07 +Author: Krahets (krahets@163.com) +""" + +import re +import glob +import sys, os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__))))) +from docs.utils.extract_code_java import ExtractCodeBlocksJava + + +class ExtractCodeBlocksZig(ExtractCodeBlocksJava): + def __init__(self) -> None: + super().__init__() + + self.ind = 4 + + # Pattern to match function names and class names + self.func_pattern = r'(\s*)(pub|)\s*fn\s+(\w+)\(.+\)\s*(.+)\s*{\n' + self.class_pattern = r'(\s*)(pub|)\s*(fn|const)\s+(\w+)\(*.+\)*\s*(type|struct)\s*{\n' + + self.func_pattern_keys = ["total", "ind", "scope", "label", "return"] + self.class_pattern_keys = ["total", "ind", "scope", "type", "label", "struct"] + + # Pattern to match the start and end of a block + self.block_start_pattern = '^\s*\n' + self.block_start_shift = 1 + + def extract_class_blocks(self): + """ + Extract all the classes with given indentation + """ + classes = {} + class_pattern = re.compile(self.class_pattern) + + for line_num, line in enumerate(self.lines): + # Search the class header + class_match = class_pattern.match(line) + if class_match is None: + continue + header_line = line_num + + # Search the block from the header line + start_line, end_line, class_block = self.search_block( + header_line, 0) + # Construct the classes dict + class_label = class_match.group(self.class_pattern_keys.index("label")) + # Define the indentation by the class type + class_type = class_match.group(self.class_pattern_keys.index("type")) + self.ind = 8 if class_type == "fn" else 4 + classes[class_label] = { + "indentation": 0, + "line_number": { + "start": start_line, + "end": end_line, + "header": header_line, + }, + "block": class_block, + "funcs": self.extract_function_blocks( + indentation=self.ind, start_line=start_line, end_line=end_line) + } + + return classes + + def post_process(self, classes, funcs): + """ + Process the classes and functions + """ + def remove_keyword(func): + block = func["block"] + header_line = func["line_number"]["header"] - \ + func["line_number"]["start"] + block[header_line] = block[header_line].replace("pub ", "", 1) + + for clas in classes.values(): + remove_keyword(clas) + for func in clas["funcs"].values(): + remove_keyword(func) + if func["indentation"] == 8: + for i, line in enumerate(func["block"]): + func["block"][i] = line[4:] + for func in funcs.values(): + remove_keyword(func) + +# for code_path in glob.glob("codes/*/chapter_*/my_heap.zig"): +# ext = ExtractCodeBlocksZig() +# res = ext.extract(code_path) +# pass \ No newline at end of file