Binary Tree Traverse Collection

树是图的一个子集,二叉树是树的一个子集。

因此相对来说,套路还是比较集中的,leetcode上的题目也很多,所以在这做一个专题集。

Basic Traverse

绝大部分树的算法都可以基于暴力遍历来去解决,所以遍历方式即是基础中的基础。

既然是图,那么二叉树的遍历也是分为bfs和dfs这两种最基本的方式。

DFS

DFS写出来的代码总是比BFS的短很多,这也是为什么我一直觉得DFS比BFS简单的原因。

不过其实,两者的本质都是要依托于数据结构。DFS使用了栈的数据结构,在一条树的线路上入栈到底,然后出栈计算,然后继续入栈。而刚好对于大部分的编程语言而言,函数调用即是以栈的形式。

时间复杂度O(n), 空间复杂度O(n). 首先,每个节点都要被遍历一次,内存开销主要是函数栈的开销,平均情况下为 O(log n),最坏情况下树呈现链状,为 O(n).

fn dfs<F: FnMut(i32)>(_root: Option<Rc<RefCell<TreeNode<i32>>>>, cb: &mut F) {
    if let Some(n) = _root {
        let node = n.borrow();
        cb(node.val);
        dfs(node.left.clone(), cb);
        dfs(node.right.clone(), cb);
    }
}

BFS

BFS使用了队列的数据结构。每一次的节点都会在被遍历的同时,把自己的子节点推入队列,根据队列FIFO的特点,会在本层的节点都完成之后,再进行下一层的节点,所以可以以层的顺序去遍历。

时间复杂度O(n), 空间复杂度O(n).

fn bfs<F: FnMut(i32)>(root: Option<Rc<RefCell<TreeNode>>>, cb: &mut F) {
    use std::collections::VecDeque;
    if root.is_none() {
        return;
    }
    let mut queue = VecDeque::<Option<Rc<RefCell<TreeNode>>>>::new();
    queue.push_front(root);

    while !queue.is_empty() {
        if let Some(node) = queue.pop_front() {
            if let Some(unwrapped_node) = node {
                let borrow_unwrapped_node = unwrapped_node.borrow();
                cb(borrow_unwrapped_node.val);
                queue.push_back(borrow_unwrapped_node.left.clone());
                queue.push_back(borrow_unwrapped_node.right.clone());
            }
        }
    }
}

BST Serialization

from tree level order

No.297, source: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/

为方便二叉树的测试,所以先选取了二叉树的构建这一道题目。这道题目其实和二叉树的层次遍历非常相似。

序列化就是正常的bfs,只要注意把数组尾部多余的空值清空就好。

值得注意的是反序列化,如何跟着一个数组去构建树。这里是使用了一个指针,每遍历一个节点,就把他的子节点推入队列,同时根据指针从数组中获取值。完成之后,因为一个二叉树有两个节点,所以指针+2。

use std::collections::VecDeque;
static NULL_LOCAL: &str = "x";
static SEPARATOR_LOCAL: &str = ",";
struct Codec {}
impl Codec {
    
    fn new() -> Self {
        Self {}
    }

    fn serialize(&self, root: Option<Rc<RefCell<TreeNode>>>) -> String {
        let mut ret = vec![];
        let mut queue = VecDeque::<Option<Rc<RefCell<TreeNode>>>>::new();
        queue.push_front(root);

        while !queue.is_empty() {
            if let Some(node) = queue.pop_front() {
                if let Some(unwrapped_node) = node {
                    let borrow_unwrapped_node = unwrapped_node.borrow();
                    ret.push(borrow_unwrapped_node.val.to_string());
                    queue.push_back(borrow_unwrapped_node.left.clone());
                    queue.push_back(borrow_unwrapped_node.right.clone());
                } else {
                    ret.push(NULL_LOCAL.to_string());
                }
            }
        }

        let mut finished = false;
        while !finished {
            if let Some(v) = ret.pop() {
                if v != NULL_LOCAL {
                    finished = true;
                    ret.push(v);
                }
            } else {
                finished = true;
            }
        }

        return format!("[{}]", ret.join(SEPARATOR_LOCAL));
    }

    fn deserialize(&self, data: String) -> Option<Rc<RefCell<TreeNode>>> {
        if data == "[]" {
            return None;
        }
        let raw_str = data.replace("[", "").replace("]", "");
        let list: Vec<&str> = raw_str.split(SEPARATOR_LOCAL).collect();
        let nodes: Vec<Option<Rc<RefCell<TreeNode>>>> = list.iter().map(|item| {
            if item == &NULL_LOCAL {
                return None;
            }
            Some(Rc::from(RefCell::from(TreeNode {
                val: item.parse::<i32>().unwrap(),
                left: None,
                right: None,
            })))
        }).collect();
        let mut queue = VecDeque::<usize>::new();
        queue.push_back(0);

        let mut cursor = 1;
        while !queue.is_empty() {
            if let Some(index) = queue.pop_front() {
                if let Some(unwrapped_node) = nodes[index].clone() {
                    let mut borrow_unwrapped_node = unwrapped_node.borrow_mut();
                    if nodes.get(cursor).is_some() {
                        borrow_unwrapped_node.left = nodes[cursor].clone();
                        queue.push_back(cursor);
                    }
                    if nodes.get(cursor + 1).is_some() {
                        borrow_unwrapped_node.right = nodes[cursor + 1].clone();
                        queue.push_back(cursor + 1);
                    }
                 }
                cursor += 2;
            }
        }
        return nodes[0].clone();
    }
}

Traverse Order

tree level order

No.102, source: https://leetcode.com/problems/binary-tree-level-order-traversal/ No.107, source: https://leetcode.com/problems/binary-tree-level-order-traversal-ii/

二叉树的层次遍历,其实和构建二叉树是一样的,而且更简单。dfs和bfs都可以,但是感觉用bfs会更加自然。

如果是从bottom开始,只要reverse一下从top开始的结果就可以。

pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
    use std::collections::VecDeque;

    let mut ret = vec![];
    if root.is_none() {
        return ret;
    }
 
    let mut queue = VecDeque::<Option<Rc<RefCell<TreeNode>>>>::new();
    queue.push_front(root);
    while !queue.is_empty() {
        let num = queue.len() as i32;
        let mut level_arr = vec![];
        let mut i = 0;
        while i < num {
            i += 1;
            if let Some(node) = queue.pop_front() {
                if let Some(unwrapped_node) = node {
                    let borrow_unwrapped_node = unwrapped_node.borrow();
                    level_arr.push(borrow_unwrapped_node.val); 
                    queue.push_back(borrow_unwrapped_node.left.clone());
                    queue.push_back(borrow_unwrapped_node.right.clone());
                }
            }
        }
        if level_arr.len() != 0 {
            ret.push(level_arr);
        }
    }
    return ret;
}

preorder

No.144, source: https://leetcode.com/problems/binary-tree-preorder-traversal/

preorder: 根在前,从左往右,一棵树的根永远在左子树前面,左子树又永远在右子树前面

栈符合前序遍历的要求,先进后出,深度到底。

值得一提的是,如果不用函数栈,即递归的形式,那么可以自己构造栈,把右节点先入栈,左边一口气到底, 个人感觉虽然比递归代码量大,但是更加的直观。

pub fn preorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
  let mut ret = vec![];
  let mut stack = vec![root];
  while let Some(node) = stack.pop() {
    if let Some(n) = node {
      let borrow_node = n.borrow_mut();
      ret.push(borrow_node.val);
      stack.push(borrow_node.right.clone());
      stack.push(borrow_node.left.clone());
    }
  }
  return ret;
}

inorde

No.94, source: https://leetcode.com/problems/binary-tree-inorder-traversal/

inorder: 根在中,从左往右,一棵树的左子树永远在根前面,根永远在右子树前面.

递归实现比较简单,比较难的是用自己用栈结构实现。

思路是对于一个节点而言,要先把所有的左节点都入栈,然后在出栈的过程中,收集值然后再把右节点入栈。

pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
  let mut ret = vec![];
  let mut stack = vec![];
  let mut current_root_wrap = root;

  while current_root_wrap.is_some() || !stack.is_empty() {
    while let Some(node) = current_root_wrap {
      current_root_wrap = node.borrow().left.clone();
      stack.push(node);
    }
    if let Some(node) = stack.pop() {
      ret.push(node.borrow().val);
      current_root_wrap = node.borrow().right.clone();
    }
  }

  return ret;
}

postorder

No. 145, source: https://leetcode.com/problems/binary-tree-postorder-traversal/

postorder: 根在后,从左往右,一棵树的左子树永远在右子树前面,右子树永远在根前面.

值得一提的是,前序稍微改一下然后reverse,就是后序:

前序:中 -> 左 -> 右
稍微改一下前序顺序: 中 -> 右 -> 左
然后翻转: 左 -> 右 -> 中

用栈结构实现是前中后最难的:左节点一撸到底,然后去检查右节点,每个节点处理完就值为空,当右节点也不存在时,就可以把此时的节点值推入。

pub fn postorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
    let mut ret = vec![];
    let mut stack = vec![];
    let mut current_root_wrap = root;

    while current_root_wrap.is_some() || !stack.is_empty() {
        while let Some(node) = current_root_wrap {
            current_root_wrap = node.borrow_mut().left.take();
            stack.push(node);
        }
        if let Some(node) = stack.pop() {
            if node.borrow().right.is_some() {
                current_root_wrap = node.borrow_mut().right.take();
                stack.push(node);
            } else {
                ret.push(node.borrow().val);
            }
        }
    }
    ret
}

zigzag level order

No.103, source: https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/

其实是层序遍历的变种,只要每行reverse数组即可。

pub fn zigzag_level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
    use std::collections::VecDeque;

    let mut ret = vec![];
    if root.is_none() {
        return ret;
    }
    let mut queue = VecDeque::<Option<Rc<RefCell<TreeNode>>>>::new();
    queue.push_front(root);
    let mut current_level = 0;
    while !queue.is_empty() {
        let num = queue.len() as i32;
        let mut level_arr = vec![];
        let mut i = 0;
        while i < num {
            i += 1;
            if let Some(node) = queue.pop_front() {
                if let Some(unwrapped_node) = node {
                    let borrow_unwrapped_node = unwrapped_node.borrow();
                    level_arr.push(borrow_unwrapped_node.val);
                    queue.push_back(borrow_unwrapped_node.left.clone());
                    queue.push_back(borrow_unwrapped_node.right.clone());
                }
            }
        }
        if level_arr.len() != 0 {
            if current_level % 2 == 0 {
                ret.push(level_arr);
            } else {
                level_arr.reverse();
                ret.push(level_arr);
            }
        }
        current_level = current_level + 1;
    }
    ret
}

vertical order

No. 987, source: https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/

记录下各节点坐标,然后进行数组遍历,算出结果。这题的特性,用dfs去做会更加的简便。

    let mut node_coordinate: Vec<(i32, i32, i32)> = Vec::new();
    let mut ans: Vec<Vec<i32>> = Vec::new();
    let mut last_col = i32::MIN;

    fn dfs(
        root: Option<Rc<RefCell<TreeNode<i32>>>>,
        (row, col): (i32, i32),
        node_coordinate: &mut Vec<(i32, i32, i32)>,
    ) {
        let left = root.as_ref().unwrap().borrow_mut().left.take();
        let right = root.as_ref().unwrap().borrow_mut().right.take();
        let value = root.as_ref().unwrap().borrow().val;

        node_coordinate.push((row, col, value));
        if left.is_some() {
            dfs(left, (row + 1, col - 1), node_coordinate);
        }
        if right.is_some() {
            dfs(right, (row + 1, col + 1), node_coordinate);
        }
    }
    dfs(root, (0, 0), &mut node_coordinate);
    node_coordinate.sort_unstable_by(|a, b| {
        if a.1 != b.1 {
            a.1.cmp(&b.1)
        } else if a.0 != b.0 {
            a.0.cmp(&b.0)
        } else {
            a.2.cmp(&b.2)
        }
    });

    for (_row, col, val) in node_coordinate {
        if last_col != col {
            ans.push(Vec::new());
            last_col = col;
        }
        ans.last_mut().unwrap().push(val);
    }

    ans

总结