Skip to content

Commit

Permalink
copy zig codes of chapter_array_and_linkedlist and chapter_computatio… (
Browse files Browse the repository at this point in the history
krahets#319)

* copy zig codes of chapter_array_and_linkedlist and chapter_computational_complexity to markdown files

* Update time_complexity.md

---------

Co-authored-by: Yudong Jin <[email protected]>
  • Loading branch information
coderonion and krahets authored Feb 3, 2023
1 parent b39b84a commit 15efaca
Show file tree
Hide file tree
Showing 8 changed files with 568 additions and 43 deletions.
19 changes: 10 additions & 9 deletions codes/zig/chapter_array_and_linkedlist/array.zig
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,27 @@ pub fn find(nums: []i32, target: i32) i32 {

// Driver Code
pub fn main() !void {
// 初始化内存分配器
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer mem_arena.deinit();
const mem_allocator = mem_arena.allocator();

// 初始化数组
const size: i32 = 5;
var arr = [_]i32{0} ** size;
var arr = [_]i32{0} ** 5;
std.debug.print("数组 arr = ", .{});
inc.PrintUtil.printArray(i32, &arr);

var array = [_]i32{ 1, 3, 2, 5, 4 };
var known_at_runtime_zero: usize = 0;
var nums = array[known_at_runtime_zero..];
std.debug.print("\n数组 nums = ", .{});
inc.PrintUtil.printArray(i32, &array);
inc.PrintUtil.printArray(i32, nums);

// 随机访问
var randomNum = randomAccess(&array);
var randomNum = randomAccess(nums);
std.debug.print("\n在 nums 中获取随机元素 {}", .{randomNum});

// 长度扩展
var known_at_runtime_zero: usize = 0;
var nums: []i32 = array[known_at_runtime_zero..array.len];
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer mem_arena.deinit();
const mem_allocator = mem_arena.allocator();
nums = try extend(mem_allocator, nums, 3);
std.debug.print("\n将数组长度扩展至 8 ,得到 nums = ", .{});
inc.PrintUtil.printArray(i32, nums);
Expand Down
3 changes: 1 addition & 2 deletions codes/zig/chapter_array_and_linkedlist/list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ pub fn main() !void {
inc.PrintUtil.printList(i32, list);

// 删除元素
var value = list.orderedRemove(3);
_ = value;
_ = list.orderedRemove(3);
std.debug.print("\n删除索引 3 处的元素,得到 list = ", .{});
inc.PrintUtil.printList(i32, list);

Expand Down
65 changes: 60 additions & 5 deletions docs/chapter_array_and_linkedlist/array.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ comments: true
=== "Zig"

```zig title="array.zig"

// 初始化数组
var arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }
var nums = [_]i32{ 1, 3, 2, 5, 4 };
```

## 4.1.1. 数组优点
Expand Down Expand Up @@ -226,7 +228,14 @@ 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;
}
```

## 4.1.2. 数组缺点
Expand Down Expand Up @@ -374,7 +383,16 @@ 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;
}
```

**数组中插入或删除元素效率低下**。假设我们想要在数组中间某位置插入一个元素,由于数组元素在内存中是“紧挨着的”,它们之间没有空间再放任何数据。因此,我们不得不将此索引之后的所有元素都向后移动一位,然后再把元素赋值给该索引。删除元素也是类似,需要把此索引之后的元素都向前移动一位。总体看有以下缺点:
Expand Down Expand Up @@ -572,7 +590,25 @@ 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];
}
}
```

## 4.1.3. 数组常用操作
Expand Down Expand Up @@ -720,7 +756,20 @@ 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;
}
}
```

**数组查找**。通过遍历数组,查找数组内的指定元素,并输出对应索引。
Expand Down Expand Up @@ -842,7 +891,13 @@ 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;
}
```

## 4.1.4. 数组典型应用
Expand Down
84 changes: 79 additions & 5 deletions docs/chapter_array_and_linkedlist/linked_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,21 @@ comments: true
=== "Zig"

```zig title=""

// 链表结点类
pub fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
val: T = 0, // 结点值
next: ?*Self = null, // 指向下一结点的指针(引用)

// 构造函数
pub fn init(self: *Self, x: i32) void {
self.val = x;
self.next = null;
}
};
}
```

**尾结点指向什么?** 我们一般将链表的最后一个结点称为「尾结点」,其指向的是「空」,在 Java / C++ / Python 中分别记为 `null` / `nullptr` / `None` 。在不引起歧义下,本书都使用 `null` 来表示空。
Expand Down Expand Up @@ -286,7 +300,18 @@ comments: true
=== "Zig"

```zig title="linked_list.zig"

// 初始化链表
// 初始化各个结点
var n0 = inc.ListNode(i32){.val = 1};
var n1 = inc.ListNode(i32){.val = 3};
var n2 = inc.ListNode(i32){.val = 2};
var n3 = inc.ListNode(i32){.val = 5};
var n4 = inc.ListNode(i32){.val = 4};
// 构建引用指向
n0.next = &n1;
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
```

## 4.2.1. 链表优点
Expand Down Expand Up @@ -480,7 +505,21 @@ 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;
}

// 删除链表的结点 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;
}
```

## 4.2.2. 链表缺点
Expand Down Expand Up @@ -612,7 +651,16 @@ 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;
}
```

**链表的内存占用多**。链表以结点为单位,每个结点除了保存值外,还需额外保存指针(引用)。这意味着同样数据量下,链表比数组需要占用更多内存空间。
Expand Down Expand Up @@ -763,7 +811,17 @@ 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;
}
```

## 4.2.4. 常见链表类型
Expand Down Expand Up @@ -897,7 +955,23 @@ comments: true
=== "Zig"

```zig title=""

// 双向链表结点类
pub fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
val: T = 0, // 结点值
next: ?*Self = null, // 指向后继结点的指针(引用)
prev: ?*Self = null, // 指向前驱结点的指针(引用)

// 构造函数
pub fn init(self: *Self, x: i32) void {
self.val = x;
self.next = null;
self.prev = null;
}
};
}
```

![linkedlist_common_types](linked_list.assets/linkedlist_common_types.png)
Expand Down
Loading

0 comments on commit 15efaca

Please sign in to comment.