mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-13 15:56:05 +00:00
build
This commit is contained in:
@@ -116,6 +116,12 @@ comments: true
|
||||
List<int?> tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 任意类型二叉树的数组表示 </p>
|
||||
@@ -620,6 +626,107 @@ comments: true
|
||||
[class]{ArrayBinaryTree}-[func]{}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="array_binary_tree.rs"
|
||||
/* 数组表示下的二叉树类 */
|
||||
struct ArrayBinaryTree {
|
||||
tree: Vec<Option<i32>>,
|
||||
}
|
||||
|
||||
impl ArrayBinaryTree {
|
||||
/* 构造方法 */
|
||||
fn new(arr: Vec<Option<i32>>) -> Self {
|
||||
Self { tree: arr }
|
||||
}
|
||||
|
||||
/* 节点数量 */
|
||||
fn size(&self) -> i32 {
|
||||
self.tree.len() as i32
|
||||
}
|
||||
|
||||
/* 获取索引为 i 节点的值 */
|
||||
fn val(&self, i: i32) -> Option<i32> {
|
||||
// 若索引越界,则返回 None ,代表空位
|
||||
if i < 0 || i >= self.size() {
|
||||
None
|
||||
} else {
|
||||
self.tree[i as usize]
|
||||
}
|
||||
}
|
||||
|
||||
/* 获取索引为 i 节点的左子节点的索引 */
|
||||
fn left(&self, i: i32) -> i32 {
|
||||
2 * i + 1
|
||||
}
|
||||
|
||||
/* 获取索引为 i 节点的右子节点的索引 */
|
||||
fn right(&self, i: i32) -> i32 {
|
||||
2 * i + 2
|
||||
}
|
||||
|
||||
/* 获取索引为 i 节点的父节点的索引 */
|
||||
fn parent(&self, i: i32) -> i32 {
|
||||
(i - 1) / 2
|
||||
}
|
||||
|
||||
/* 层序遍历 */
|
||||
fn level_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
// 直接遍历数组
|
||||
for i in 0..self.size() {
|
||||
if let Some(val) = self.val(i) {
|
||||
res.push(val)
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/* 深度优先遍历 */
|
||||
fn dfs(&self, i: i32, order: &str, res: &mut Vec<i32>) {
|
||||
if self.val(i).is_none() {
|
||||
return;
|
||||
}
|
||||
let val = self.val(i).unwrap();
|
||||
// 前序遍历
|
||||
if order == "pre" {
|
||||
res.push(val);
|
||||
}
|
||||
self.dfs(self.left(i), order, res);
|
||||
// 中序遍历
|
||||
if order == "in" {
|
||||
res.push(val);
|
||||
}
|
||||
self.dfs(self.right(i), order, res);
|
||||
// 后序遍历
|
||||
if order == "post" {
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
/* 前序遍历 */
|
||||
fn pre_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "pre", &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
/* 中序遍历 */
|
||||
fn in_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "in", &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
/* 后序遍历 */
|
||||
fn post_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "post", &mut res);
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7.3.3. 优势与局限性
|
||||
|
||||
二叉树的数组表示的优点包括:
|
||||
|
||||
@@ -190,6 +190,12 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
|
||||
```
|
||||
|
||||
「节点高度」是指从该节点到最远叶节点的距离,即所经过的“边”的数量。需要特别注意的是,叶节点的高度为 0 ,而空节点的高度为 -1 。我们将创建两个工具函数,分别用于获取和更新节点的高度。
|
||||
|
||||
=== "Java"
|
||||
@@ -388,6 +394,29 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 获取节点高度 */
|
||||
fn height(node: OptionTreeNodeRc) -> i32 {
|
||||
// 空节点高度为 -1 ,叶节点高度为 0
|
||||
match node {
|
||||
Some(node) => node.borrow().height,
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
/* 更新节点高度 */
|
||||
fn update_height(node: OptionTreeNodeRc) {
|
||||
if let Some(node) = node {
|
||||
let left = node.borrow().left.clone();
|
||||
let right = node.borrow().right.clone();
|
||||
// 节点高度等于最高子树高度 + 1
|
||||
node.borrow_mut().height = std::cmp::max(Self::height(left), Self::height(right)) + 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 节点平衡因子
|
||||
|
||||
节点的「平衡因子 Balance Factor」定义为节点左子树的高度减去右子树的高度,同时规定空节点的平衡因子为 0 。我们同样将获取节点平衡因子的功能封装成函数,方便后续使用。
|
||||
@@ -530,6 +559,22 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 获取平衡因子 */
|
||||
fn balance_factor(node: OptionTreeNodeRc) -> i32 {
|
||||
match node {
|
||||
// 空节点平衡因子为 0
|
||||
None => 0,
|
||||
// 节点平衡因子 = 左子树高度 - 右子树高度
|
||||
Some(node) => {
|
||||
Self::height(node.borrow().left.clone()) - Self::height(node.borrow().right.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
设平衡因子为 $f$ ,则一棵 AVL 树的任意节点的平衡因子皆满足 $-1 \le f \le 1$ 。
|
||||
@@ -762,6 +807,29 @@ AVL 树的特点在于「旋转 Rotation」操作,它能够在不影响二叉
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 右旋操作 */
|
||||
fn right_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(node) => {
|
||||
let child = node.borrow().left.clone().unwrap();
|
||||
let grand_child = child.borrow().right.clone();
|
||||
// 以 child 为原点,将 node 向右旋转
|
||||
child.borrow_mut().right = Some(node.clone());
|
||||
node.borrow_mut().left = grand_child;
|
||||
// 更新节点高度
|
||||
Self::update_height(Some(node));
|
||||
Self::update_height(Some(child.clone()));
|
||||
// 返回旋转后子树的根节点
|
||||
Some(child)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 左旋
|
||||
|
||||
相应的,如果考虑上述失衡二叉树的“镜像”,则需要执行「左旋」操作。
|
||||
@@ -976,6 +1044,29 @@ AVL 树的特点在于「旋转 Rotation」操作,它能够在不影响二叉
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 左旋操作 */
|
||||
fn left_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(node) => {
|
||||
let child = node.borrow().right.clone().unwrap();
|
||||
let grand_child = child.borrow().left.clone();
|
||||
// 以 child 为原点,将 node 向左旋转
|
||||
child.borrow_mut().left = Some(node.clone());
|
||||
node.borrow_mut().right = grand_child;
|
||||
// 更新节点高度
|
||||
Self::update_height(Some(node));
|
||||
Self::update_height(Some(child.clone()));
|
||||
// 返回旋转后子树的根节点
|
||||
Some(child)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 先左旋后右旋
|
||||
|
||||
对于下图中的失衡节点 3,仅使用左旋或右旋都无法使子树恢复平衡。此时需要先左旋后右旋,即先对 `child` 执行「左旋」,再对 `node` 执行「右旋」。
|
||||
@@ -1385,6 +1476,45 @@ AVL 树的特点在于「旋转 Rotation」操作,它能够在不影响二叉
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 执行旋转操作,使该子树重新恢复平衡 */
|
||||
fn rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
// 获取节点 node 的平衡因子
|
||||
let balance_factor = Self::balance_factor(node.clone());
|
||||
// 左偏树
|
||||
if balance_factor > 1 {
|
||||
let node = node.unwrap();
|
||||
if Self::balance_factor(node.borrow().left.clone()) >= 0 {
|
||||
// 右旋
|
||||
Self::right_rotate(Some(node))
|
||||
} else {
|
||||
// 先左旋后右旋
|
||||
let left = node.borrow().left.clone();
|
||||
node.borrow_mut().left = Self::left_rotate(left);
|
||||
Self::right_rotate(Some(node))
|
||||
}
|
||||
}
|
||||
// 右偏树
|
||||
else if balance_factor < -1 {
|
||||
let node = node.unwrap();
|
||||
if Self::balance_factor(node.borrow().right.clone()) <= 0 {
|
||||
// 左旋
|
||||
Self::left_rotate(Some(node))
|
||||
} else {
|
||||
// 先右旋后左旋
|
||||
let right = node.borrow().right.clone();
|
||||
node.borrow_mut().right = Self::right_rotate(right);
|
||||
Self::left_rotate(Some(node))
|
||||
}
|
||||
} else {
|
||||
// 平衡树,无需旋转,直接返回
|
||||
node
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7.5.3. AVL 树常用操作
|
||||
|
||||
### 插入节点
|
||||
@@ -1697,6 +1827,48 @@ AVL 树的特点在于「旋转 Rotation」操作,它能够在不影响二叉
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 插入节点 */
|
||||
fn insert(&mut self, val: i32) {
|
||||
self.root = Self::insert_helper(self.root.clone(), val);
|
||||
}
|
||||
|
||||
/* 递归插入节点(辅助方法) */
|
||||
fn insert_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(mut node) => {
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
match {
|
||||
let node_val = node.borrow().val;
|
||||
node_val
|
||||
}
|
||||
.cmp(&val)
|
||||
{
|
||||
Ordering::Greater => {
|
||||
let left = node.borrow().left.clone();
|
||||
node.borrow_mut().left = Self::insert_helper(left, val);
|
||||
}
|
||||
Ordering::Less => {
|
||||
let right = node.borrow().right.clone();
|
||||
node.borrow_mut().right = Self::insert_helper(right, val);
|
||||
}
|
||||
Ordering::Equal => {
|
||||
return Some(node); // 重复节点不插入,直接返回
|
||||
}
|
||||
}
|
||||
Self::update_height(Some(node.clone())); // 更新节点高度
|
||||
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
|
||||
node = Self::rotate(Some(node)).unwrap();
|
||||
// 返回子树的根节点
|
||||
Some(node)
|
||||
}
|
||||
None => Some(TreeNode::new(val)),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 删除节点
|
||||
|
||||
类似地,在二叉搜索树的删除节点方法的基础上,需要从底至顶地执行旋转操作,使所有失衡节点恢复平衡。
|
||||
@@ -2198,6 +2370,64 @@ AVL 树的特点在于「旋转 Rotation」操作,它能够在不影响二叉
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="avl_tree.rs"
|
||||
/* 删除节点 */
|
||||
fn remove(&self, val: i32) {
|
||||
Self::remove_helper(self.root.clone(), val);
|
||||
}
|
||||
|
||||
/* 递归删除节点(辅助方法) */
|
||||
fn remove_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(mut node) => {
|
||||
/* 1. 查找节点,并删除之 */
|
||||
if val < node.borrow().val {
|
||||
let left = node.borrow().left.clone();
|
||||
node.borrow_mut().left = Self::remove_helper(left, val);
|
||||
} else if val > node.borrow().val {
|
||||
let right = node.borrow().right.clone();
|
||||
node.borrow_mut().right = Self::remove_helper(right, val);
|
||||
} else if node.borrow().left.is_none() || node.borrow().right.is_none() {
|
||||
let child = if node.borrow().left.is_some() {
|
||||
node.borrow().left.clone()
|
||||
} else {
|
||||
node.borrow().right.clone()
|
||||
};
|
||||
match child {
|
||||
// 子节点数量 = 0 ,直接删除 node 并返回
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
// 子节点数量 = 1 ,直接删除 node
|
||||
Some(child) => node = child,
|
||||
}
|
||||
} else {
|
||||
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点
|
||||
let mut temp = node.borrow().right.clone().unwrap();
|
||||
loop {
|
||||
let temp_left = temp.borrow().left.clone();
|
||||
if temp_left.is_none() {
|
||||
break;
|
||||
}
|
||||
temp = temp_left.unwrap();
|
||||
}
|
||||
let right = node.borrow().right.clone();
|
||||
node.borrow_mut().right = Self::remove_helper(right, temp.borrow().val);
|
||||
node.borrow_mut().val = temp.borrow().val;
|
||||
}
|
||||
Self::update_height(Some(node.clone())); // 更新节点高度
|
||||
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
|
||||
node = Self::rotate(Some(node)).unwrap();
|
||||
// 返回子树的根节点
|
||||
Some(node)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 查找节点
|
||||
|
||||
AVL 树的节点查找操作与二叉搜索树一致,在此不再赘述。
|
||||
|
||||
@@ -271,6 +271,33 @@ comments: true
|
||||
[class]{BinarySearchTree}-[func]{search}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_search_tree.rs"
|
||||
/* 查找节点 */
|
||||
pub fn search(&self, num: i32) -> Option<TreeNodeRc> {
|
||||
let mut cur = self.root.clone();
|
||||
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while let Some(node) = cur.clone() {
|
||||
// 目标节点在 cur 的右子树中
|
||||
if node.borrow().val < num {
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
// 目标节点在 cur 的左子树中
|
||||
else if node.borrow().val > num {
|
||||
cur = node.borrow().left.clone();
|
||||
}
|
||||
// 找到目标节点,跳出循环
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 返回目标节点
|
||||
cur
|
||||
}
|
||||
```
|
||||
|
||||
### 插入节点
|
||||
|
||||
给定一个待插入元素 `num` ,为了保持二叉搜索树“左子树 < 根节点 < 右子树”的性质,插入操作分为两步:
|
||||
@@ -614,6 +641,44 @@ comments: true
|
||||
[class]{BinarySearchTree}-[func]{insert}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_search_tree.rs"
|
||||
/* 插入节点 */
|
||||
pub fn insert(&mut self, num: i32) {
|
||||
// 若树为空,直接提前返回
|
||||
if self.root.is_none() {
|
||||
return;
|
||||
}
|
||||
let mut cur = self.root.clone();
|
||||
let mut pre = None;
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while let Some(node) = cur.clone() {
|
||||
// 找到重复节点,直接返回
|
||||
if node.borrow().val == num {
|
||||
return;
|
||||
}
|
||||
// 插入位置在 cur 的右子树中
|
||||
pre = cur.clone();
|
||||
if node.borrow().val < num {
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
// 插入位置在 cur 的左子树中
|
||||
else {
|
||||
cur = node.borrow().left.clone();
|
||||
}
|
||||
}
|
||||
// 插入节点
|
||||
let node = TreeNode::new(num);
|
||||
let pre = pre.unwrap();
|
||||
if pre.borrow().val < num {
|
||||
pre.borrow_mut().right = Some(Rc::clone(&node));
|
||||
} else {
|
||||
pre.borrow_mut().left = Some(Rc::clone(&node));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
为了插入节点,我们需要利用辅助节点 `pre` 保存上一轮循环的节点,这样在遍历至 $\text{None}$ 时,我们可以获取到其父节点,从而完成节点插入操作。
|
||||
|
||||
与查找节点相同,插入节点使用 $O(\log n)$ 时间。
|
||||
@@ -1217,6 +1282,76 @@ comments: true
|
||||
[class]{BinarySearchTree}-[func]{remove}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_search_tree.rs"
|
||||
/* 删除节点 */
|
||||
pub fn remove(&mut self, num: i32) {
|
||||
// 若树为空,直接提前返回
|
||||
if self.root.is_none() {
|
||||
return;
|
||||
}
|
||||
let mut cur = self.root.clone();
|
||||
let mut pre = None;
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while let Some(node) = cur.clone() {
|
||||
// 找到待删除节点,跳出循环
|
||||
if node.borrow().val == num {
|
||||
break;
|
||||
}
|
||||
// 待删除节点在 cur 的右子树中
|
||||
pre = cur.clone();
|
||||
if node.borrow().val < num {
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
// 待删除节点在 cur 的左子树中
|
||||
else {
|
||||
cur = node.borrow().left.clone();
|
||||
}
|
||||
}
|
||||
// 若无待删除节点,则直接返回
|
||||
if cur.is_none() {
|
||||
return;
|
||||
}
|
||||
let cur = cur.unwrap();
|
||||
// 子节点数量 = 0 or 1
|
||||
if cur.borrow().left.is_none() || cur.borrow().right.is_none() {
|
||||
// 当子节点数量 = 0 / 1 时, child = nullptr / 该子节点
|
||||
let child = cur.borrow().left.clone().or_else(|| cur.borrow().right.clone());
|
||||
let pre = pre.unwrap();
|
||||
let left = pre.borrow().left.clone().unwrap();
|
||||
// 删除节点 cur
|
||||
if !Rc::ptr_eq(&cur, self.root.as_ref().unwrap()) {
|
||||
if Rc::ptr_eq(&left, &cur) {
|
||||
pre.borrow_mut().left = child;
|
||||
} else {
|
||||
pre.borrow_mut().right = child;
|
||||
}
|
||||
} else {
|
||||
// 若删除节点为根节点,则重新指定根节点
|
||||
self.root = child;
|
||||
}
|
||||
}
|
||||
// 子节点数量 = 2
|
||||
else {
|
||||
// 获取中序遍历中 cur 的下一个节点
|
||||
let mut tmp = cur.borrow().right.clone();
|
||||
while let Some(node) = tmp.clone() {
|
||||
if node.borrow().left.is_some() {
|
||||
tmp = node.borrow().left.clone();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let tmpval = tmp.unwrap().borrow().val;
|
||||
// 递归删除节点 tmp
|
||||
self.remove(tmpval);
|
||||
// 用 tmp 覆盖 cur
|
||||
cur.borrow_mut().val = tmpval;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 排序
|
||||
|
||||
我们知道,二叉树的中序遍历遵循“左 $\rightarrow$ 根 $\rightarrow$ 右”的遍历顺序,而二叉搜索树满足“左子节点 $<$ 根节点 $<$ 右子节点”的大小关系。因此,在二叉搜索树中进行中序遍历时,总是会优先遍历下一个最小节点,从而得出一个重要性质:**二叉搜索树的中序遍历序列是升序的**。
|
||||
|
||||
@@ -159,6 +159,12 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
|
||||
```
|
||||
|
||||
节点的两个指针分别指向「左子节点」和「右子节点」,同时该节点被称为这两个子节点的「父节点」。当给定一个二叉树的节点时,我们将该节点的左子节点及其以下节点形成的树称为该节点的「左子树」,同理可得「右子树」。
|
||||
|
||||
**在二叉树中,除叶节点外,其他所有节点都包含子节点和非空子树**。例如,在以下示例中,若将“节点 2”视为父节点,则其左子节点和右子节点分别是“节点 4”和“节点 5”,左子树是“节点 4 及其以下节点形成的树”,右子树是“节点 5 及其以下节点形成的树”。
|
||||
@@ -366,6 +372,12 @@ comments: true
|
||||
n2.right = n5;
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_tree.rs"
|
||||
|
||||
```
|
||||
|
||||
**插入与删除节点**。与链表类似,通过修改指针来实现插入与删除节点。
|
||||
|
||||

|
||||
@@ -496,6 +508,12 @@ comments: true
|
||||
n1.left = n2;
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_tree.rs"
|
||||
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
需要注意的是,插入节点可能会改变二叉树的原有逻辑结构,而删除节点通常意味着删除该节点及其所有子树。因此,在二叉树中,插入与删除操作通常是由一套操作配合完成的,以实现有实际意义的操作。
|
||||
|
||||
@@ -298,6 +298,30 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_tree_bfs.rs"
|
||||
/* 层序遍历 */
|
||||
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); // 保存结点值
|
||||
if let Some(left) = node.borrow().left.as_ref() {
|
||||
que.push_back(Rc::clone(left)); // 左子结点入队
|
||||
}
|
||||
if let Some(right) = node.borrow().right.as_ref() {
|
||||
que.push_back(Rc::clone(right)); // 右子结点入队
|
||||
};
|
||||
}
|
||||
vec
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度**:所有节点被访问一次,使用 $O(n)$ 时间,其中 $n$ 为节点数量。
|
||||
|
||||
**空间复杂度**:在最差情况下,即满二叉树时,遍历到最底层之前,队列中最多同时存在 $\frac{n + 1}{2}$ 个节点,占用 $O(n)$ 空间。
|
||||
@@ -682,6 +706,49 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="binary_tree_dfs.rs"
|
||||
/* 前序遍历 */
|
||||
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()));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/* 中序遍历 */
|
||||
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()));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/* 后序遍历 */
|
||||
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);
|
||||
}
|
||||
result
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度**:所有节点被访问一次,使用 $O(n)$ 时间,其中 $n$ 为节点数量。
|
||||
|
||||
**空间复杂度**:在最差情况下,即树退化为链表时,递归深度达到 $n$ ,系统占用 $O(n)$ 栈帧空间。
|
||||
|
||||
Reference in New Issue
Block a user