mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-24 09:36:28 +08:00
Replace "结点" with "节点".
This commit is contained in:
parent
7605cab160
commit
5385057993
7 changed files with 24 additions and 24 deletions
|
@ -215,7 +215,7 @@ void removeVertex(GraphAdjList *graph, unsigned int index) {
|
|||
printf("Out of range in %s:%d\n", __FILE__, __LINE__);
|
||||
return;
|
||||
}
|
||||
// 遍历待删除顶点的链表,将所有与待删除结点有关的边删除
|
||||
// 遍历待删除顶点的链表,将所有与待删除节点有关的边删除
|
||||
Node *temp = vet->list->head->next;
|
||||
while (temp != 0) {
|
||||
removeLink(temp->val->list, vet); // 删除与该顶点有关的边
|
||||
|
|
|
@ -12,19 +12,19 @@ use tree_node::{vec_to_tree, TreeNode};
|
|||
|
||||
/* 层序遍历 */
|
||||
fn level_order(root: &Rc<RefCell<TreeNode>>) -> Vec<i32> {
|
||||
// 初始化队列,加入根结点
|
||||
// 初始化队列,加入根节点
|
||||
let mut que = VecDeque::new();
|
||||
que.push_back(Rc::clone(&root));
|
||||
// 初始化一个列表,用于保存遍历序列
|
||||
let mut vec = Vec::new();
|
||||
|
||||
while let Some(node) = que.pop_front() { // 队列出队
|
||||
vec.push(node.borrow().val); // 保存结点值
|
||||
vec.push(node.borrow().val); // 保存节点值
|
||||
if let Some(left) = node.borrow().left.as_ref() {
|
||||
que.push_back(Rc::clone(left)); // 左子结点入队
|
||||
que.push_back(Rc::clone(left)); // 左子节点入队
|
||||
}
|
||||
if let Some(right) = node.borrow().right.as_ref() {
|
||||
que.push_back(Rc::clone(right)); // 右子结点入队
|
||||
que.push_back(Rc::clone(right)); // 右子节点入队
|
||||
};
|
||||
}
|
||||
vec
|
||||
|
@ -40,5 +40,5 @@ fn main() {
|
|||
|
||||
/* 层序遍历 */
|
||||
let vec = level_order(&root);
|
||||
print!("\n层序遍历的结点打印序列 = {:?}", vec);
|
||||
print!("\n层序遍历的节点打印序列 = {:?}", vec);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ fn pre_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
|||
let mut result = vec![];
|
||||
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:根结点 -> 左子树 -> 右子树
|
||||
// 访问优先级:根节点 -> 左子树 -> 右子树
|
||||
result.push(node.borrow().val);
|
||||
result.append(&mut pre_order(node.borrow().left.as_ref()));
|
||||
result.append(&mut pre_order(node.borrow().right.as_ref()));
|
||||
|
@ -28,7 +28,7 @@ fn in_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
|||
let mut result = vec![];
|
||||
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:左子树 -> 根结点 -> 右子树
|
||||
// 访问优先级:左子树 -> 根节点 -> 右子树
|
||||
result.append(&mut in_order(node.borrow().left.as_ref()));
|
||||
result.push(node.borrow().val);
|
||||
result.append(&mut in_order(node.borrow().right.as_ref()));
|
||||
|
@ -41,7 +41,7 @@ fn post_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
|||
let mut result = vec![];
|
||||
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:左子树 -> 右子树 -> 根结点
|
||||
// 访问优先级:左子树 -> 右子树 -> 根节点
|
||||
result.append(&mut post_order(node.borrow().left.as_ref()));
|
||||
result.append(&mut post_order(node.borrow().right.as_ref()));
|
||||
result.push(node.borrow().val);
|
||||
|
@ -59,13 +59,13 @@ fn main() {
|
|||
|
||||
/* 前序遍历 */
|
||||
let vec = pre_order(root.as_ref());
|
||||
println!("\n前序遍历的结点打印序列 = {:?}", vec);
|
||||
println!("\n前序遍历的节点打印序列 = {:?}", vec);
|
||||
|
||||
/* 中序遍历 */
|
||||
let vec = in_order(root.as_ref());
|
||||
println!("\n中序遍历的结点打印序列 = {:?}", vec);
|
||||
println!("\n中序遍历的节点打印序列 = {:?}", vec);
|
||||
|
||||
/* 后序遍历 */
|
||||
let vec = post_order(root.as_ref());
|
||||
print!("\n后序遍历的结点打印序列 = {:?}", vec);
|
||||
print!("\n后序遍历的节点打印序列 = {:?}", vec);
|
||||
}
|
|
@ -22,9 +22,9 @@
|
|||
```python title="list.py"
|
||||
# 初始化列表
|
||||
# 无初始值
|
||||
nums1: nums[int] = []
|
||||
nums1: list[int] = []
|
||||
# 有初始值
|
||||
nums: nums[int] = [1, 3, 2, 5, 4]
|
||||
nums: list[int] = [1, 3, 2, 5, 4]
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
|
@ -677,7 +677,7 @@
|
|||
|
||||
```python title="list.py"
|
||||
# 拼接两个列表
|
||||
nums1: nums[int] = [6, 8, 7, 10, 9]
|
||||
nums1: list[int] = [6, 8, 7, 10, 9]
|
||||
nums += nums1 # 将列表 nums1 拼接到 nums 之后
|
||||
```
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
!!! question "为什么数组要求相同类型的元素,而在链表中却没有强调同类型呢?"
|
||||
|
||||
链表由结点组成,结点之间通过引用(指针)连接,各个结点可以存储不同类型的数据,例如 int、double、string、object 等。
|
||||
链表由节点组成,节点之间通过引用(指针)连接,各个节点可以存储不同类型的数据,例如 int、double、string、object 等。
|
||||
|
||||
相对地,数组元素则必须是相同类型的,这样才能通过计算偏移量来获取对应元素位置。例如,如果数组同时包含 int 和 long 两种类型,单个元素分别占用 4 bytes 和 8 bytes ,那么此时就不能用以下公式计算偏移量了,因为数组中包含了两种长度的元素。
|
||||
|
||||
|
@ -31,19 +31,19 @@
|
|||
|
||||
!!! question "删除节点后,是否需要把 `P.next` 设为 $\text{None}$ 呢?"
|
||||
|
||||
不修改 `P.next` 也可以。从该链表的角度看,从头结点遍历到尾结点已经遇不到 `P` 了。这意味着结点 `P` 已经从链表中删除了,此时结点 `P` 指向哪里都不会对这条链表产生影响了。
|
||||
不修改 `P.next` 也可以。从该链表的角度看,从头节点遍历到尾节点已经遇不到 `P` 了。这意味着节点 `P` 已经从链表中删除了,此时节点 `P` 指向哪里都不会对这条链表产生影响了。
|
||||
|
||||
从垃圾回收的角度看,对于 Java、Python、Go 等拥有自动垃圾回收的语言来说,节点 `P` 是否被回收取决于是否有仍存在指向它的引用,而不是 `P.next` 的值。在 C 和 C++ 等语言中,我们需要手动释放节点内存。
|
||||
|
||||
!!! question "在链表中插入和删除操作的时间复杂度是 $O(1)$ 。但是增删之前都需要 $O(n)$ 查找元素,那为什么时间复杂度不是 $O(n)$ 呢?"
|
||||
|
||||
如果是先查找元素、再删除元素,确实是 $O(n)$ 。然而,链表的 $O(1)$ 增删的优势可以在其他应用上得到体现。例如,双向队列适合使用链表实现,我们维护一个指针变量始终指向头结点、尾结点,每次插入与删除操作都是 $O(1)$ 。
|
||||
如果是先查找元素、再删除元素,确实是 $O(n)$ 。然而,链表的 $O(1)$ 增删的优势可以在其他应用上得到体现。例如,双向队列适合使用链表实现,我们维护一个指针变量始终指向头节点、尾节点,每次插入与删除操作都是 $O(1)$ 。
|
||||
|
||||
!!! question "图片“链表定义与存储方式”中,浅蓝色的存储结点指针是占用一块内存地址吗?还是和结点值各占一半呢?"
|
||||
!!! question "图片“链表定义与存储方式”中,浅蓝色的存储节点指针是占用一块内存地址吗?还是和节点值各占一半呢?"
|
||||
|
||||
文中的示意图只是定性表示,定量表示需要根据具体情况进行分析。
|
||||
|
||||
- 不同类型的结点值占用的空间是不同的,比如 int、long、double 和实例对象等。
|
||||
- 不同类型的节点值占用的空间是不同的,比如 int、long、double 和实例对象等。
|
||||
- 指针变量占用的内存空间大小根据所使用的操作系统及编译环境而定,大多为 8 字节或 4 字节。
|
||||
|
||||
!!! question "在列表末尾添加元素是否时时刻刻都为 $O(1)$ ?"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
**之所以称之为回溯算法,是因为该算法在搜索解空间时会采用“尝试”与“回退”的策略**。当算法在搜索过程中遇到某个状态无法继续前进或无法得到满足条件的解时,它会撤销上一步的选择,退回到之前的状态,并尝试其他可能的选择。
|
||||
|
||||
对于例题一,访问每个节点都代表一次“尝试”,而越过叶结点或返回父节点的 `return` 则表示“回退”。
|
||||
对于例题一,访问每个节点都代表一次“尝试”,而越过叶节点或返回父节点的 `return` 则表示“回退”。
|
||||
|
||||
值得说明的是,**回退并不仅仅包括函数返回**。为解释这一点,我们对例题一稍作拓展。
|
||||
|
||||
|
@ -407,7 +407,7 @@
|
|||
| 约束条件 Constraint | 约束条件是问题中限制解的可行性的条件,通常用于剪枝 | 路径中不包含节点 $3$ |
|
||||
| 状态 State | 状态表示问题在某一时刻的情况,包括已经做出的选择 | 当前已访问的节点路径,即 `path` 节点列表 |
|
||||
| 尝试 Attempt | 尝试是根据可用选择来探索解空间的过程,包括做出选择,更新状态,检查是否为解 | 递归访问左(右)子节点,将节点添加进 `path` ,判断节点的值是否为 $7$ |
|
||||
| 回退 Backtracking | 回退指遇到不满足约束条件的状态时,撤销前面做出的选择,回到上一个状态 | 当越过叶结点、结束结点访问、遇到值为 $3$ 的节点时终止搜索,函数返回 |
|
||||
| 回退 Backtracking | 回退指遇到不满足约束条件的状态时,撤销前面做出的选择,回到上一个状态 | 当越过叶节点、结束节点访问、遇到值为 $3$ 的节点时终止搜索,函数返回 |
|
||||
| 剪枝 Pruning | 剪枝是根据问题特性和约束条件避免无意义的搜索路径的方法,可提高搜索效率 | 当遇到值为 $3$ 的节点时,则终止继续搜索 |
|
||||
|
||||
!!! tip
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
!!! question "为什么 DFS 遍历二叉树有前、中、后三种顺序,分别有什么用呢?"
|
||||
|
||||
DFS 的前、中、后序遍历和访问数组的顺序类似,是遍历二叉树的基本方法,利用这三种遍历方法,我们可以得到一个特定顺序的遍历结果。例如在二叉搜索树中,由于结点大小满足 `左子结点值 < 根结点值 < 右子结点值` ,因此我们只要按照 `左->根->右` 的优先级遍历树,就可以获得有序的节点序列。
|
||||
DFS 的前、中、后序遍历和访问数组的顺序类似,是遍历二叉树的基本方法,利用这三种遍历方法,我们可以得到一个特定顺序的遍历结果。例如在二叉搜索树中,由于节点大小满足 `左子节点值 < 根节点值 < 右子节点值` ,因此我们只要按照 `左->根->右` 的优先级遍历树,就可以获得有序的节点序列。
|
||||
|
||||
!!! question "右旋操作是处理失衡节点 `node`、`child`、`grand_child` 之间的关系,那 `node` 的父节点和 `node` 原来的连接不需要维护吗?右旋操作后岂不是断掉了?"
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
!!! question "在 C++ 中,函数被划分到 `private` 和 `public` 中,这方面有什么考量吗?为什么要将 `height()` 函数和 `updateHeight()` 函数分别放在 `public` 和 `private` 中呢?"
|
||||
|
||||
主要看方法的使用范围,如果方法只在类内部使用,那么就设计为 `private` 。例如,用户单独调用 `updateHeight()` 是没有意义的,它只是插入、删除操作中的一步。而 `height()` 是访问结点高度,类似于 `vector.size()` ,因此设置成 `public` 以便使用。
|
||||
主要看方法的使用范围,如果方法只在类内部使用,那么就设计为 `private` 。例如,用户单独调用 `updateHeight()` 是没有意义的,它只是插入、删除操作中的一步。而 `height()` 是访问节点高度,类似于 `vector.size()` ,因此设置成 `public` 以便使用。
|
||||
|
||||
!!! question "请问如何从一组输入数据构建一个二叉搜索树?根节点的选择是不是很重要?"
|
||||
|
||||
|
|
Loading…
Reference in a new issue