mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-24 04:06:28 +08:00
Update .gitignore
Add build script for Zig.
This commit is contained in:
parent
3465b300e9
commit
ec25970e8e
30 changed files with 226 additions and 532 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -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/
|
||||
site/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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});
|
||||
|
||||
// 在链表中执行线性查找
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
[class]{}-[func]{insert}
|
||||
|
||||
// 删除索引 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]{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. 数组典型应用
|
||||
|
|
|
@ -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. 常见链表类型
|
||||
|
|
|
@ -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]{}
|
||||
```
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
|
|
@ -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<size) : (i += 1) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{constant}
|
||||
```
|
||||
|
||||
### 线性阶 $O(n)$
|
||||
|
@ -939,15 +929,7 @@ $$
|
|||
=== "Zig"
|
||||
|
||||
```zig title="time_complexity.zig"
|
||||
// 线性阶
|
||||
fn linear(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
while (i < n) : (i += 1) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{linear}
|
||||
```
|
||||
|
||||
「遍历数组」和「遍历链表」等操作,时间复杂度都为 $O(n)$ ,其中 $n$ 为数组或链表的长度。
|
||||
|
@ -1021,15 +1003,7 @@ $$
|
|||
=== "Zig"
|
||||
|
||||
```zig title="time_complexity.zig"
|
||||
// 线性阶(遍历数组)
|
||||
fn arrayTraversal(nums: []i32) i32 {
|
||||
var count: i32 = 0;
|
||||
// 循环次数与数组长度成正比
|
||||
for (nums) |_| {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{arrayTraversal}
|
||||
```
|
||||
|
||||
### 平方阶 $O(n^2)$
|
||||
|
@ -1103,19 +1077,7 @@ $$
|
|||
=== "Zig"
|
||||
|
||||
```zig title="time_complexity.zig"
|
||||
// 平方阶
|
||||
fn quadratic(n: i32) i32 {
|
||||
var count: i32 = 0;
|
||||
var i: i32 = 0;
|
||||
// 循环次数与数组长度成平方关系
|
||||
while (i < n) : (i += 1) {
|
||||
var j: i32 = 0;
|
||||
while (j < n) : (j += 1) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
[class]{}-[func]{quadratic}
|
||||
```
|
||||
|
||||
![time_complexity_constant_linear_quadratic](time_complexity.assets/time_complexity_constant_linear_quadratic.png)
|
||||
|
@ -1204,26 +1166,7 @@ $$
|
|||
=== "Zig"
|
||||
|
||||
```zig title="time_complexity.zig"
|
||||
// 平方阶(冒泡排序)
|
||||
fn bubbleSort(nums: []i32) i32 {
|
||||
var count: i32 = 0; // 计数器
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
var i: i32 = @intCast(i32, nums.len ) - 1;
|
||||
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)
|
||||
|
|
|
@ -486,7 +486,9 @@ $$
|
|||
=== "Zig"
|
||||
|
||||
```zig title="array_hash_map.zig"
|
||||
[class]{Entry}-[func]{}
|
||||
|
||||
[class]{ArrayHashMap}-[func]{}
|
||||
```
|
||||
|
||||
## 6.1.4. 哈希冲突
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
||||
那么,第二种建堆方法的时间复杂度时多少呢?我们来做一下简单推算。
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
||||
### 两种表示对比
|
||||
|
|
|
@ -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. 复杂度分析
|
||||
|
|
|
@ -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. 复杂度分析
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
|
|
@ -97,7 +97,7 @@ comments: true
|
|||
=== "Zig"
|
||||
|
||||
```zig title="insertion_sort.zig"
|
||||
|
||||
[class]{}-[func]{insertionSort}
|
||||
```
|
||||
|
||||
## 11.3.2. 算法特性
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
|
|
@ -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]{}
|
||||
```
|
||||
|
||||
以上代码仍存在局限性,即长度不可变。然而,我们可以通过将数组替换为列表(即动态数组)来引入扩容机制,有兴趣的同学可以尝试实现。
|
||||
|
|
|
@ -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. 两种实现对比
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
||||
### 查找结点
|
||||
|
|
|
@ -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}
|
||||
```
|
||||
|
||||
### 排序
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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():
|
||||
|
|
90
docs/utils/extract_code_zig.py
Normal file
90
docs/utils/extract_code_zig.py
Normal file
|
@ -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
|
Loading…
Reference in a new issue