Update .gitignore

Add build script for Zig.
pull/356/head^2
krahets 2 years ago
parent 3465b300e9
commit ec25970e8e

3
.gitignore vendored

@ -1,10 +1,9 @@
# MacOS Desktop Services Store
# macOS
.DS_Store
# Editor
.vscode/
.idea/
hello-algo.iml
# mkdocs files
.cache/

@ -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;
}
// 删除索引 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. 数组典型应用

@ -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(),
}

@ -22,12 +22,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):
"""
Extract classes and functions from a markdown document

@ -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():

@ -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…
Cancel
Save