Revisit the English version (#1835)

* Review the English version using Claude-4.5.

* Update mkdocs.yml

* Align the section titles.

* Bug fixes
This commit is contained in:
Yudong Jin
2025-12-30 17:54:01 +08:00
committed by GitHub
parent 091afd38b4
commit 45e1295241
106 changed files with 4195 additions and 3398 deletions
+21 -21
View File
@@ -13,7 +13,7 @@ We encapsulate the binary search tree as a class `BinarySearchTree` and declare
### Searching for a node
Given a target node value `num`, one can search according to the properties of the binary search tree. As shown in the figure below, we declare a node `cur`, start from the binary tree's root node `root`, and loop to compare the size between the node value `cur.val` and `num`.
Given a target node value `num`, we can search according to the properties of the binary search tree. As shown in the figure below, we declare a node `cur` and start from the binary tree's root node `root`, looping to compare the node value `cur.val` with `num`.
- If `cur.val < num`, it means the target node is in `cur`'s right subtree, thus execute `cur = cur.right`.
- If `cur.val > num`, it means the target node is in `cur`'s left subtree, thus execute `cur = cur.left`.
@@ -31,7 +31,7 @@ Given a target node value `num`, one can search according to the properties of t
=== "<4>"
![bst_search_step4](binary_search_tree.assets/bst_search_step4.png)
The search operation in a binary search tree works on the same principle as the binary search algorithm, eliminating half of the cases in each round. The number of loops is at most the height of the binary tree. When the binary tree is balanced, it uses $O(\log n)$ time. The example code is as follows:
The search operation in a binary search tree works on the same principle as the binary search algorithm, both eliminating half of the cases in each round. The number of loop iterations is at most the height of the binary tree. When the binary tree is balanced, it uses $O(\log n)$ time. The example code is as follows:
```src
[file]{binary_search_tree}-[class]{binary_search_tree}-[func]{search}
@@ -39,17 +39,17 @@ The search operation in a binary search tree works on the same principle as the
### Inserting a node
Given an element `num` to be inserted, to maintain the property of the binary search tree "left subtree < root node < right subtree," the insertion operation proceeds as shown in the figure below.
Given an element `num` to be inserted, in order to maintain the property of the binary search tree "left subtree < root node < right subtree," the insertion process is as shown in the figure below.
1. **Finding insertion position**: Similar to the search operation, start from the root node, loop downwards according to the size relationship between the current node value and `num`, until the leaf node is passed (traversed to `None`), then exit the loop.
2. **Insert the node at this position**: Initialize the node `num` and place it where `None` was.
1. **Finding the insertion position**: Similar to the search operation, start from the root node and loop downward searching according to the size relationship between the current node value and `num`, until passing the leaf node (traversing to `None`) and then exit the loop.
2. **Insert the node at that position**: Initialize node `num` and place it at the `None` position.
![Inserting a node into a binary search tree](binary_search_tree.assets/bst_insert.png)
In the code implementation, note the following two points.
In the code implementation, note the following two points:
- The binary search tree does not allow duplicate nodes to exist; otherwise, its definition would be violated. Therefore, if the node to be inserted already exists in the tree, the insertion is not performed, and the node returns directly.
- To perform the insertion operation, we need to use the node `pre` to save the node from the previous loop. This way, when traversing to `None`, we can get its parent node, thus completing the node insertion operation.
- Binary search trees do not allow duplicate nodes; otherwise, it would violate its definition. Therefore, if the node to be inserted already exists in the tree, the insertion is not performed and it returns directly.
- To implement the node insertion, we need to use node `pre` to save the node from the previous loop iteration. This way, when traversing to `None`, we can obtain its parent node, thereby completing the node insertion operation.
```src
[file]{binary_search_tree}-[class]{binary_search_tree}-[func]{insert}
@@ -59,7 +59,7 @@ Similar to searching for a node, inserting a node uses $O(\log n)$ time.
### Removing a node
First, find the target node in the binary tree, then remove it. Similar to inserting a node, we need to ensure that after the removal operation is completed, the property of the binary search tree "left subtree < root node < right subtree" is still satisfied. Therefore, based on the number of child nodes of the target node, we divide it into three cases: 0, 1, and 2, and perform the corresponding node removal operations.
First, find the target node in the binary tree, then remove it. Similar to node insertion, we need to ensure that after the removal operation is completed, the binary search tree's property of "left subtree $<$ root node $<$ right subtree" is still maintained. Therefore, depending on the number of child nodes the target node has, we divide it into 0, 1, and 2 three cases, and execute the corresponding node removal operations.
As shown in the figure below, when the degree of the node to be removed is $0$, it means the node is a leaf node and can be directly removed.
@@ -69,12 +69,12 @@ As shown in the figure below, when the degree of the node to be removed is $1$,
![Removing a node in a binary search tree (degree 1)](binary_search_tree.assets/bst_remove_case2.png)
When the degree of the node to be removed is $2$, we cannot remove it directly, but need to use a node to replace it. To maintain the property of the binary search tree "left subtree $<$ root node $<$ right subtree," **this node can be either the smallest node of the right subtree or the largest node of the left subtree**.
When the degree of the node to be removed is $2$, we cannot directly remove it; instead, we need to use a node to replace it. To maintain the binary search tree's property of "left subtree $<$ root node $<$ right subtree," **this node can be either the smallest node in the right subtree or the largest node in the left subtree**.
Assuming we choose the smallest node of the right subtree (the next node in in-order traversal), then the removal operation proceeds as shown in the figure below.
Assuming we choose the smallest node in the right subtree (the next node in the inorder traversal), the removal process is as shown in the figure below.
1. Find the next node in the "in-order traversal sequence" of the node to be removed, denoted as `tmp`.
2. Replace the value of the node to be removed with `tmp`'s value, and recursively remove the node `tmp` in the tree.
1. Find the next node of the node to be removed in the "inorder traversal sequence," denoted as `tmp`.
2. Replace the value of the node to be removed with the value of `tmp`, and recursively remove node `tmp` in the tree.
=== "<1>"
![Removing a node in a binary search tree (degree 2)](binary_search_tree.assets/bst_remove_case3_step1.png)
@@ -88,25 +88,25 @@ Assuming we choose the smallest node of the right subtree (the next node in in-o
=== "<4>"
![bst_remove_case3_step4](binary_search_tree.assets/bst_remove_case3_step4.png)
The operation of removing a node also uses $O(\log n)$ time, where finding the node to be removed requires $O(\log n)$ time, and obtaining the in-order traversal successor node requires $O(\log n)$ time. Example code is as follows:
The node removal operation also uses $O(\log n)$ time, where finding the node to be removed requires $O(\log n)$ time, and obtaining the inorder successor node requires $O(\log n)$ time. Example code is as follows:
```src
[file]{binary_search_tree}-[class]{binary_search_tree}-[func]{remove}
```
### In-order traversal is ordered
### Inorder traversal is ordered
As shown in the figure below, the in-order traversal of a binary tree follows the traversal order of "left $\rightarrow$ root $\rightarrow$ right," and a binary search tree satisfies the size relationship of "left child node $<$ root node $<$ right child node."
As shown in the figure below, the inorder traversal of a binary tree follows the "left $\rightarrow$ root $\rightarrow$ right" traversal order, while the binary search tree satisfies the "left child node $<$ root node $<$ right child node" size relationship.
This means that when performing in-order traversal in a binary search tree, the next smallest node will always be traversed first, thus leading to an important property: **The sequence of in-order traversal in a binary search tree is ascending**.
This means that when performing an inorder traversal in a binary search tree, the next smallest node is always traversed first, thus yielding an important property: **The inorder traversal sequence of a binary search tree is ascending**.
Using the ascending property of in-order traversal, obtaining ordered data in a binary search tree requires only $O(n)$ time, without the need for additional sorting operations, which is very efficient.
Using the property of inorder traversal being ascending, we can obtain ordered data in a binary search tree in only $O(n)$ time, without the need for additional sorting operations, which is very efficient.
![In-order traversal sequence of a binary search tree](binary_search_tree.assets/bst_inorder_traversal.png)
![Inorder traversal sequence of a binary search tree](binary_search_tree.assets/bst_inorder_traversal.png)
## Efficiency of binary search trees
Given a set of data, we consider using an array or a binary search tree for storage. Observing the table below, the operations on a binary search tree all have logarithmic time complexity, which is stable and efficient. Arrays are more efficient than binary search trees only in scenarios involving frequent additions and infrequent searches or removals.
Given a set of data, we consider using an array or a binary search tree for storage. Observing the table below, all operations in a binary search tree have logarithmic time complexity, providing stable and efficient performance. Arrays are more efficient than binary search trees only in scenarios with high-frequency additions and low-frequency searches and deletions.
<p align="center"> Table <id> &nbsp; Efficiency comparison between arrays and search trees </p>
@@ -116,7 +116,7 @@ Given a set of data, we consider using an array or a binary search tree for stor
| Insert element | $O(1)$ | $O(\log n)$ |
| Remove element | $O(n)$ | $O(\log n)$ |
Ideally, the binary search tree is "balanced," allowing any node can be found within $\log n$ loops.
In the ideal case, a binary search tree is "balanced," such that any node can be found within $\log n$ loop iterations.
However, if we continuously insert and remove nodes in a binary search tree, it may degenerate into a linked list as shown in the figure below, where the time complexity of various operations also degrades to $O(n)$.