You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rust中使用Rc实现红黑树的嵌套匹配等效逻辑

在Rust中用Rc实现纯函数式红黑树的平衡(等效Haskell嵌套匹配)

我刚好也复刻过Okasaki的纯函数式红黑树,用Rc的时候确实要处理嵌套结构的匹配问题——毕竟Haskell的模式匹配可以直接拆多层嵌套的Node,但Rust里Rc是智能指针,得先拿到内部的Tree引用才能匹配。下面给你一步步拆解实现思路和代码:

先明确基础结构

首先我们得定义和Okasaki一致的红黑树结构,用Rc包裹子节点来实现不可变共享:

use std::rc::Rc;

#[derive(Debug, Clone, PartialEq, Eq)]
enum Color {
    Red,
    Black,
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum Tree<A: Ord> {
    Empty,
    Node(Color, Rc<Tree<A>>, A, Rc<Tree<A>>),
}

impl<A: Ord> Tree<A> {
    // 辅助函数:快速创建空树的Rc实例
    fn empty() -> Rc<Self> {
        Rc::new(Tree::Empty)
    }

    // 辅助函数:快速创建节点的Rc实例
    fn node(color: Color, left: Rc<Self>, value: A, right: Rc<Self>) -> Rc<Self> {
        Rc::new(Tree::Node(color, left, value, right))
    }
}

核心:复刻Haskell的嵌套匹配

Okasaki的Haskell平衡函数是通过四层模式匹配直接捕获四种不平衡的情况(左左、左右、右左、右右),在Rust里我们可以通过**嵌套的if let或者带嵌套判断的match**来实现完全等效的逻辑:

实现方式1:用嵌套if let(直观对应Haskell的模式)

这种方式最贴近Haskell的写法,逐层级匹配嵌套的Node结构:

fn balance<A: Ord>(
    color: Color,
    left: Rc<Tree<A>>,
    value: A,
    right: Rc<Tree<A>>,
) -> Rc<Tree<A>> {
    // 只需要处理黑色根节点下的红-红冲突
    if let Color::Black = color {
        // 情况1:左左型冲突(黑->红->红)
        if let Tree::Node(Color::Red, left_left, left_val, left_right) = left.as_ref() {
            if let Tree::Node(Color::Red, ll_left, ll_val, ll_right) = left_left.as_ref() {
                return Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, ll_left.clone(), ll_val.clone(), ll_right.clone()),
                    left_val.clone(),
                    Tree::node(Color::Black, left_right.clone(), value, right),
                );
            }
        }

        // 情况2:左右型冲突(黑->红->红)
        if let Tree::Node(Color::Red, left_left, left_val, left_right) = left.as_ref() {
            if let Tree::Node(Color::Red, lr_left, lr_val, lr_right) = left_right.as_ref() {
                return Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, left_left.clone(), left_val.clone(), lr_left.clone()),
                    lr_val.clone(),
                    Tree::node(Color::Black, lr_right.clone(), value, right),
                );
            }
        }

        // 情况3:右左型冲突(黑->红->红)
        if let Tree::Node(Color::Red, right_left, right_val, right_right) = right.as_ref() {
            if let Tree::Node(Color::Red, rl_left, rl_val, rl_right) = right_left.as_ref() {
                return Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, left, value, rl_left.clone()),
                    rl_val.clone(),
                    Tree::node(Color::Black, rl_right.clone(), right_val.clone(), right_right.clone()),
                );
            }
        }

        // 情况4:右右型冲突(黑->红->红)
        if let Tree::Node(Color::Red, right_left, right_val, right_right) = right.as_ref() {
            if let Tree::Node(Color::Red, rr_left, rr_val, rr_right) = right_right.as_ref() {
                return Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, left, value, right_left.clone()),
                    right_val.clone(),
                    Tree::node(Color::Black, rr_left.clone(), rr_val.clone(), rr_right.clone()),
                );
            }
        }
    }

    // 没有冲突,直接返回原结构的新节点(纯函数式不可变要求)
    Tree::node(color, left, value, right)
}

实现方式2:用match做更紧凑的匹配

如果你更喜欢用match来统一处理所有情况,可以把顶层的颜色和子树引用先匹配,再嵌套if let处理深层结构:

fn balance<A: Ord>(
    color: Color,
    left: Rc<Tree<A>>,
    value: A,
    right: Rc<Tree<A>>,
) -> Rc<Tree<A>> {
    match (color, left.as_ref(), right.as_ref()) {
        // 左左型冲突
        (Color::Black, Tree::Node(Color::Red, ll, lv, lr), _) => {
            if let Tree::Node(Color::Red, lll, llv, llr) = ll.as_ref() {
                Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, lll.clone(), llv.clone(), llr.clone()),
                    lv.clone(),
                    Tree::node(Color::Black, lr.clone(), value, right),
                )
            } else {
                Tree::node(color, left, value, right)
            }
        }
        // 左右型冲突
        (Color::Black, Tree::Node(Color::Red, ll, lv, lr), _) => {
            if let Tree::Node(Color::Red, lrl, lrv, lrr) = lr.as_ref() {
                Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, ll.clone(), lv.clone(), lrl.clone()),
                    lrv.clone(),
                    Tree::node(Color::Black, lrr.clone(), value, right),
                )
            } else {
                Tree::node(color, left, value, right)
            }
        }
        // 右左型冲突
        (Color::Black, _, Tree::Node(Color::Red, rl, rv, rr)) => {
            if let Tree::Node(Color::Red, rll, rlv, rlr) = rl.as_ref() {
                Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, left, value, rll.clone()),
                    rlv.clone(),
                    Tree::node(Color::Black, rlr.clone(), rv.clone(), rr.clone()),
                )
            } else {
                Tree::node(color, left, value, right)
            }
        }
        // 右右型冲突
        (Color::Black, _, Tree::Node(Color::Red, rl, rv, rr)) => {
            if let Tree::Node(Color::Red, rrl, rrv, rrr) = rr.as_ref() {
                Tree::node(
                    Color::Red,
                    Tree::node(Color::Black, left, value, rl.clone()),
                    rv.clone(),
                    Tree::node(Color::Black, rrl.clone(), rrv.clone(), rrr.clone()),
                )
            } else {
                Tree::node(color, left, value, right)
            }
        }
        // 所有无需平衡的情况
        _ => Tree::node(color, left, value, right),
    }
}

关键细节说明

  1. Rc的使用技巧:用Rc::as_ref()获取内部Tree的引用,这样我们可以匹配Node结构而不需要提前克隆;只有在构建新节点的时候才调用clone(),而Rc的clone只是增加引用计数,开销极小,完全符合纯函数式的性能要求。
  2. 纯函数式不可变性:所有操作都是创建新的Rc包裹的节点,原有的树结构不会被修改,这和Okasaki的Haskell实现逻辑完全一致。
  3. 类型约束:Tree的类型参数A必须实现Ord,因为红黑树需要比较元素大小来维护有序性。

内容的提问来源于stack exchange,提问作者xuq01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:04:05