Skip to content

Commit 500a445

Browse files
committed
chinese translation complete
1 parent cf50f79 commit 500a445

File tree

2 files changed

+185
-21
lines changed

2 files changed

+185
-21
lines changed

app/content/posts/20240629-rust-via-bst-zh-tw.mdx

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,170 @@ tags:
1111
- rust
1212
---
1313

14-
Awaiting translation.
14+
自我上一篇關於 Rust 的文章已有一段時日了,而且它沒有談到 Rust 的理念與原理,因此這篇文章會是一個對於已有 C 系列語言經驗的工程師而言的 Rust 簡介,再者,
15+
如果你不知道二元搜尋樹(BST)的話,我強烈建議先去查查。
16+
17+
# 所有權
18+
19+
在實作 BST 前,我們必須解釋所有權,在 Rust 中,物件必須由某個東西擁有,而且只能是那個東西擁有,舉例來說,對於無法複製型別`A`,下列程式碼會產生錯誤。
20+
21+
```rust
22+
let x: A = ...; // ...由x擁有
23+
let y = x; // 轉移到y
24+
x...; // 錯誤
25+
```
26+
27+
因此要使用`x`而且不讓`x`失去擁有權會用到「借用」,分成兩類:分享參考(&)與獨有參考(可變參考、&mut),前者是一個指向常數不可變記憶的指標,
28+
後者指向可變記憶指標。對於`x`,在同個變數範圍,最多只能有一個獨有參考,而且如果有獨有參考就不能有分享參考。
29+
30+
# 節點與葉子
31+
32+
在 C,我們可以將節點定義為:
33+
34+
```c
35+
struct node {
36+
int key;
37+
struct node *left, *right;
38+
};
39+
```
40+
41+
一個`node`有兩個指標指向其他`node`,注意這些其他節點的記憶分配沒有被具體地定義出來,如果左或右節點是空的,那其值會被設為`(struct node*)NULL`
42+
這方法有些缺點,最主要是你所分配的堆記憶(heap memory)需要手動清理,不然會造成記憶外洩。
43+
44+
在 Rust,由於一個節點只能由父母存取,而且知道它的父母無關上下文,我們可以定義為此:
45+
46+
```rust
47+
struct BSTNode<T> {
48+
left: BST<T>,
49+
right: BST<T>,
50+
pub key: i32,
51+
pub val: T,
52+
}
53+
54+
pub struct BST<T> {
55+
node: Option<Box<BSTNode<T>>>,
56+
}
57+
```
58+
59+
我們顯然定義了一個間接架構`BST<T>`,用來裝在可有可無的`Box<node>`。一個`Box`是一個指向特定堆記憶的獨特指標,如果沒有人指向、擁有`Box`
60+
則此記憶會被清理,如果`node`這個性質是`None`,那 BST 就是單純的空樹,除此之外,有些人會這樣寫:
61+
62+
```rust
63+
pub struct BST<T> {
64+
left: Option<Box<BST<T>>>,
65+
right: Option<Box<BST<T>>>,
66+
pub key: i32,
67+
pub val: T,
68+
}
69+
```
70+
71+
,精簡化程式碼,它是可行的,不過你需要在頂層使用`Option`來表示空樹,因此我們在此文章會使用第一個實作。接下來,我們來定義幾個簡單的功能。
72+
73+
```rust
74+
impl<T> BST<T> {
75+
// an empty BST
76+
pub fn new_empty() -> Self {
77+
Self { node: None }
78+
}
79+
// a BST with one node
80+
pub fn new(key: i32, val: T) -> Self {
81+
Self {
82+
node: Some(Box::new(BSTNode::new(key, val))),
83+
}
84+
}
85+
pub fn is_empty(&self) -> bool {
86+
self.node.is_none()
87+
}
88+
pub fn insert(&mut self, key: i32, val: T) {
89+
if let Some(root) = &mut self.node {
90+
// match is a way to split and pattern match results
91+
match root.key.cmp(&key) {
92+
Ordering::Equal => {
93+
panic!("BST should not have same id!");
94+
// bad practice ^
95+
}
96+
Ordering::Greater => { // root.key > key
97+
root.left.insert(key, val);
98+
}
99+
Ordering::Less => {
100+
root.right.insert(key, val);
101+
}
102+
}
103+
} else {
104+
self.node = Some(Box::new(BSTNode::new(key, val)));
105+
}
106+
}
107+
}
108+
```
109+
110+
此處,`Box::new`是分配堆記憶的方法。
111+
112+
# 二元搜尋樹刪除
113+
114+
接下來,我們來定義 BST 刪除節點的方法。要刪除節點`n`,我們會分開討論:
115+
116+
1. `n`是葉子:使`n`成為空樹。
117+
2. `n`只有一個孩子:使孩子取代`n`
118+
3. `n`有兩個孩子:使`n`的中敘式相鄰後者取代`n`,並不改變原先`n`與孩子的連結。
119+
120+
接下來,把想法寫出來。
121+
122+
```rust
123+
impl<T: Clone> BST<T> {
124+
fn extract_min(&mut self) -> Option<Box<BSTNode<T>>> {
125+
let Some(root) = &mut self.node {
126+
return None;
127+
};
128+
129+
if !root.left.is_empty() {
130+
return root.left.extract_min();
131+
}
132+
133+
// 找到中敘式相鄰後者,並轉移記憶
134+
return self.node.take();
135+
}
136+
137+
pub fn remove(&mut self, key: i32) {
138+
let Some(root) = &mut self.node else {
139+
return;
140+
};
141+
match root.key.cmp(&key) {
142+
Ordering::Equal => match (root.left.node.as_ref(), root.right.node.as_ref()) {
143+
(None, None) => {
144+
self.node.take();
145+
// 轉移自己記憶,丟掉自己
146+
}
147+
(Some(_), None) => {
148+
self.node = root.left.node.take();
149+
// 轉移左節點至自己
150+
// 使左節點變為空樹,沒有擁有者,丟掉
151+
}
152+
(None, Some(_)) => {
153+
self.node = root.right.node.take();
154+
// 轉移右節點至自己
155+
// 使右節點變為空樹,沒有擁有者,丟掉
156+
}
157+
(Some(_), Some(_)) => {
158+
if let Some(x) = root.right.extract_min() {
159+
root.key = x.key;
160+
root.val = x.val.clone();
161+
}
162+
}
163+
},
164+
Ordering::Greater => {
165+
root.left.remove(key);
166+
}
167+
Ordering::Less => {
168+
root.right.remove(key);
169+
}
170+
}
171+
}
172+
}
173+
```
174+
175+
`Option::take`用來將`Some(x)`中的記憶換成`None`,並將`Some(x)`複製到輸出,如果`Option<Box<T>>``take`,原先的`Box<T>`會被丟掉,
176+
而全新的`Box`會產生,雖然這些最後通常會被優化掉。被拿走的節點造成 BST 成為空樹。
177+
178+
# 一小步
179+
180+
在這篇文章中,我們對於 Rust 的所有權系統有些見解,不過我們還沒看到 Rust 另一個重要的觀念——生命時長!下篇文章見。

app/content/posts/20240629-rust-via-bst.mdx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct node {
4646
```
4747

4848
A `node` has two pointers pointing to other `node`s. Note that their allocation is not concretely defined by our struct
49-
itself. If the left/right child is a leave, then the value of it is set to `nullptr`. This approach has some downsides,
49+
itself. If the left/right child is empty, then the value of it is set to `(struct node*)NULL`. This approach has some downsides,
5050
though, most notably the fact that you have to free the memory itself if you allocate heap memory. This would result in
5151
memory leaks should you forget to do so.
5252

@@ -55,14 +55,14 @@ BST tree and a BST node like is:
5555

5656
```rust
5757
struct BSTNode<T> {
58-
left: BST<T>,
59-
right: BST<T>,
60-
pub key: i32,
61-
pub val: T,
58+
left: BST<T>,
59+
right: BST<T>,
60+
pub key: i32,
61+
pub val: T,
6262
}
6363

6464
pub struct BST<T> {
65-
node: Option<Box<BSTNode<T>>>,
65+
node: Option<Box<BSTNode<T>>>,
6666
}
6767
```
6868

@@ -72,16 +72,15 @@ property is a `None`, then the BST is simply an empty tree. Some people might do
7272

7373
```rust
7474
pub struct BST<T> {
75-
left: Option<Box<BST<T>>>,
76-
right: Option<Box<BST<T>>>,
77-
pub key: i32,
78-
pub val: T,
75+
left: Option<Box<BST<T>>>,
76+
right: Option<Box<BST<T>>>,
77+
pub key: i32,
78+
pub val: T,
7979
}
8080
```
8181

8282
to make their code more succinct, and it does work, but you can't represent an empty tree without using `Option` on the
8383
top level, so we'll stick to the first implementation for the rest of this article.
84-
8584
Let's implement some simple functions for our BST.
8685

8786
```rust
@@ -136,17 +135,16 @@ Then, we write down the code.
136135
```rust
137136
impl<T: Clone> BST<T> {
138137
fn extract_min(&mut self) -> Option<Box<BSTNode<T>>> {
139-
let Some(root) = &mut self.node {
140-
return None;
141-
};
142-
143-
if !root.left.is_empty() {
144-
return root.left.extract_min();
145-
}
138+
let Some(root) = &mut self.node {
139+
return None;
140+
};
146141

147-
// find the inorder successor and take it in the process
148-
return self.node.take();
142+
if !root.left.is_empty() {
143+
return root.left.extract_min();
149144
}
145+
146+
// find the inorder successor and take it in the process
147+
return self.node.take();
150148
}
151149

152150
pub fn remove(&mut self, key: i32) {

0 commit comments

Comments
 (0)