数据结构|二叉树

完成阅读您将会了解二叉树的:

  1. 概念
  2. 构建方法
  3. 基本操作
  4. C++实现
  5. Rust实现

1. 概念

二叉树Binary Tree)是最基本的树形结构,属于图论Graph Theory)的有向无环图Directed Acyclic Graph)范畴。一棵完整的二叉树,如图1 [1],以根节点Root)作为整树访问入口,自上而下按层次不断分支,左分支被称作左子树Left Sub-tree),右分支被称作右子树Right Sub-tree)。两个拥有共同母节点的节点被称为兄弟节点Sibling Nodes)。如一个节点没有下层子节点,则称之为叶节点Leaf Node)。

图1:二叉树基本结构

图1:二叉树基本结构
二叉树存两个特殊的情况,**完全二叉树**(*Complete Binary Tree*)与**满二叉树**(*Full Binary Tree*)。满二叉树,如图2,要求每一层节点都达到**饱和**。若层数从0起始,满二叉树第k层节点数为$2^k$。完全二叉树,如图3,较满二叉树而言,最后一层不要求饱和,但需要**连续**。

图2:完全二叉树

图2:完全二叉树

图3:满二叉树

图3:满二叉树

2. 构建方法

一般情况下使用链式数据结构来存储一棵二叉树,便于操作,节约空间。通过数组表达或构建二叉树,需要带有空位标记的字符串序列或两种异序遍历序列,而对稀疏树Sparse Tree)而言,前者会产生较大的空间浪费。但完全二叉树满二叉树由于具有空间连续性,适合数组表达,如图4[2]

图4:二叉树数组表达

图4:二叉树数组表达

数组表达时,若下标位置为\([i]\)的节点存在子节点,那么其左右子节点下标为\([2i+1]\)\([2i+2]\),如非根节点,其母节点下标为\([\lfloor\frac{i-1}{2}\rfloor]\)

3. 基本操作

操作 描述 时间复杂度 空间复杂度
CREATE(A) 从序列构建树 \(\Theta(n)\) \(\Theta(n)\)
PREORDER() 前序遍历 \(\Theta(n)\) \(\Theta(n)\)
INORDER() 中序遍历 \(\Theta(n)\) \(\Theta(n)\)
POSTORDER() 后序遍历 \(\Theta(n)\) \(\Theta(n)\)
LEVEL() 层次遍历 \(\Theta(n)\) \(\Theta(n)\)
DEPTH() 获取树的深度 \(\Theta(n)\) \(\Theta(1)\)

二叉树的不同遍历方式对应的不同的遍历次序如下。

  1. 前序遍历Pre-order Traversal):根节点\(\rightarrow\)左子树\(\rightarrow\)右子树
  2. 中序遍历In-order Traversal):左子树\(\rightarrow\)根节点\(\rightarrow\)右子树
  3. 后序遍历Post-order Traversal):左子树\(\rightarrow\)右子树\(\rightarrow\)根节点
  4. 层次遍历Level Traversal):按层次从左到右

其中,前、中、后序为深度优先遍历,层次遍历为广度优先遍历。


伪代码:从字符串序列创建树辅助函数
变量说明:root \(\rightarrow\) 根节点;strs\(\rightarrow\)树的字符串数组表达;i\(\rightarrow\)当前节点下标;N \(\rightarrow\) 空位标记

\[\begin{aligned} &HELPER(node,strs,i) \\ &~~~~~~left\leftarrow 2\times i+1 \\ &~~~~~~right\leftarrow left+1 \\ &~~~~~~if~~~l<strs.size ~~~and~~~strs[l] \neq N \\ &~~~~~~~~~~~~node.left=new~~~node~~~with~~~value~~~of~~~strs[l] \\ &~~~~~~~~~~~~HELPER(node.left,strs,l) \\ &~~~~~~if~~~r<strs.size~~~and~~~strs[r]\neq N \\ &~~~~~~~~~~~~node.right=new~~~node~~~with~~~value~~~of~~~strs[r] \\ &~~~~~~~~~~~~HELPER(node.right,strs,r) \\ \end{aligned} \]

伪代码:从字符串序列创建树
变量说明:root \(\rightarrow\) 根节点;strs\(\rightarrow\)树的字符串数组表达

\[\begin{aligned} &CREATE(strs)\\ &~~~~~~if~~~strs~~~isn't~~~empty \\ &~~~~~~~~~~~~root \leftarrow new~~~node~~~ with~~~ value ~~~of~~~strs[0] \\ &~~~~~~~~~~~~HELPER(root,strs,0) \end{aligned} \]

伪代码:前序遍历树
变量说明:root \(\rightarrow\) 根节点

\[\begin{aligned} &PREORDER(root)\\ &~~~~~~new~~~ stack~~~ as~~~ s \\ &~~~~~~new ~~~collector~~~ as ~~~c \\ &~~~~~~iter\leftarrow root \\ &~~~~~~while ~~~iter ~~~isn't ~~~none~~~ or~~~ s~~~ isn't~~~ empty \\ &~~~~~~~~~~~~while~~~ iter~~~ isn't~~~ none \\ &~~~~~~~~~~~~~~~~~~c.push(iter.val) \\ &~~~~~~~~~~~~~~~~~~s.push(iter) \\ &~~~~~~~~~~~~~~~~~~iter \leftarrow iter.left \\ &~~~~~~~~~~~~iter \leftarrow s.top.right \\ &~~~~~~~~~~~~s.pop \\ &~~~~~~return ~~~c \end{aligned} \]

伪代码:中序遍历树
变量说明:root \(\rightarrow\) 根节点

\[\begin{aligned} &INORDER(root)\\ &~~~~~~new~~~stack~~~as~~~ s \\ &~~~~~~new ~~~collector~~~ as ~~~c \\ &~~~~~~iter \leftarrow root \\ &~~~~~~while~~~iter ~~~isn't ~~~none~~~ or~~~ s~~~ isn't~~~ empty \\ &~~~~~~~~~~~~while~~~ iter~~~ isn't~~~ none \\ &~~~~~~~~~~~~~~~~~~s.push(iter) \\ &~~~~~~~~~~~~~~~~~~iter \leftarrow iter.left \\ &~~~~~~~~~~~~iter \leftarrow s.top \\ &~~~~~~~~~~~~c.push(iter.val) \\ &~~~~~~~~~~~~iter\leftarrow iter.right \\ &~~~~~~~~~~~~s.pop \\ &~~~~~~return~~~c \end{aligned} \]

伪代码:后序遍历树
变量说明:root \(\rightarrow\) 根节点

\[\begin{aligned} &POSTORDER(root)\\ &~~~~~~new ~~~collector~~~ as ~~~c \\ &~~~~~~if~~~root~~~isn't~~~none \\ &~~~~~~~~~~~~new~~~ stack~~~ as~~~ s \\ &~~~~~~~~~~~~iter \leftarrow root \\ &~~~~~~~~~~~~s.push(none) \\ &~~~~~~~~~~~~while ~~~iter ~~~isn't ~~~none~~~ or~~~ s~~~ isn't~~~ empty \\ &~~~~~~~~~~~~~~~~~~if~~~iter~~~isn't~~~none \\ &~~~~~~~~~~~~~~~~~~~~~~~~s.push(iter) \\ &~~~~~~~~~~~~~~~~~~~~~~~~s.push(none) \\ &~~~~~~~~~~~~~~~~~~~~~~~~if~~~iter.right~~~isn't~~~none \\ &~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s.push(iter.right) \\ &~~~~~~~~~~~~~~~~~~~~~~~~if~~~iter.left~~~isn't ~~~none \\ &~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s.push(iter.left) \\ &~~~~~~~~~~~~~~~~~~else \\ &~~~~~~~~~~~~~~~~~~~~~~~~c.push(s.top.val) \\ &~~~~~~~~~~~~~~~~~~~~~~~~s.pop \\ &~~~~~~~~~~~~~~~~~~iter\leftarrow s.top \\ &~~~~~~~~~~~~~~~~~~s.pop \\ &~~~~~~return~~~c \end{aligned} \]

伪代码:层次遍历树
变量说明:root \(\rightarrow\) 根节点

\[\begin{aligned} &LEVEL(root)\\ &~~~~~~new~~~collector~~~as~~~c \\ &~~~~~~new~~~queue~~~as~~~q \\ &~~~~~~iter\leftarrow root \\ &~~~~~~while~~~iter~~~isn't~~~none \\ &~~~~~~~~~~~~c.push(iter.val) \\ &~~~~~~~~~~~~if~~~iter.left~~~isn't~~~none \\ &~~~~~~~~~~~~~~~~~~q.push(iter.left) \\ &~~~~~~~~~~~~if~~~iter.right~~~isn't~~~none \\ &~~~~~~~~~~~~~~~~~~q.push(iter.right) \\ &~~~~~~~~~~~~if~~~q~~~is~~~empty \\ &~~~~~~~~~~~~~~~~~~break \\ &~~~~~~~~~~~~iter\leftarrow q.front \\ &~~~~~~~~~~~~q.pop \\ &~~~~~~return~~~c \end{aligned} \]

伪代码:获取树深度
变量说明:root \(\rightarrow\) 根节点

\[\begin{aligned} &DEPTH(root) \\ &~~~~~~if~~~root~~~is~~~none\\ &~~~~~~~~~~~~return~~~0 \\ &~~~~~~return~~~1+max(DEPTH(root.left),DEPTH(root.right)) \end{aligned} \]


4. C++实现

template <class T> struct Node {
  T val;
  Node *left, *right;
  Node(auto val) : val(val), left(nullptr), right(nullptr) {}
  Node() : Node(0) {}
};

template <class T> class Bitree {
  Node<T> *root;
  constexpr size_t _depth(auto *node) const noexcept {
    return node ? 1 + std::max(_depth(node->left), _depth(node->right)) : 0;
  }
  void _Bitree(auto *node, const auto &strs, auto i) noexcept {
    auto l = (i << 1) + 1, r = l + 1;
    auto len = strs.size();
    if (l < len && strs[l] != "N") {
      node->left = new Node<T>(std::stof(strs[l]));
      _Bitree(node->left, strs, l);
    }
    if (r < len && strs[r] != "N") {
      node->right = new Node<T>(std::stof(strs[r]));
      _Bitree(node->right, strs, r);
    }
  }
  void __Bitree(auto *node) noexcept {
    if (node) {
      __Bitree(node->left);
      __Bitree(node->right);
      delete node;
    }
  }

public:
  Bitree(const auto &strs) {
    if (strs.size()) {
      root = new Node<T>(std::stof(strs[0]));
      _Bitree(root, strs, 0);
    } else
      root = nullptr;
  }
  ~Bitree() { __Bitree(root); }
  constexpr auto preorder() const noexcept {
    auto iter = root;
    std::vector<T> c;
    std::stack<Node<T> *> s;
    while (iter || !s.empty()) {
      while (iter) {
        s.emplace(iter);
        c.emplace_back(iter->val);
        iter = iter->left;
      }
      iter = s.top()->right;
      s.pop();
    }
    return c;
  }
  constexpr auto inorder() const noexcept {
    auto iter = root;
    std::vector<T> c;
    std::stack<Node<T> *> s;
    while (iter || !s.empty()) {
      while (iter) {
        s.emplace(iter);
        iter = iter->left;
      }
      iter = s.top();
      c.emplace_back(iter->val);
      iter = iter->right;
      s.pop();
    }
    return c;
  }
  constexpr auto postorder() const noexcept {
    std::vector<T> c;
    if (root) {
      auto iter = root;
      std::stack<Node<T> *> s;
      s.emplace(nullptr);
      while (iter || !s.empty()) {
        if (iter) {
          s.emplace(iter);
          s.emplace(nullptr);
          if (iter->right)
            s.emplace(iter->right);
          if (iter->left)
            s.emplace(iter->left);
        } else {
          c.emplace_back(s.top()->val);
          s.pop();
        }
        iter = s.top();
        s.pop();
      }
    }
    return c;
  }
  constexpr auto level() const noexcept {
    std::vector<T> c;
    std::queue<Node<T> *> q;
    auto iter = root;
    while (iter) {
      c.emplace_back(iter->val);
      if (iter->left)
        q.emplace(iter->left);
      if (iter->right)
        q.emplace(iter->right);
      if (q.empty())
        break;
      iter = q.front();
      q.pop();
    }
    return c;
  }
  constexpr auto depth() const noexcept { return _depth(root); }
};

5. Rust实现

type TNode<T> = Rc<RefCell<Node<T>>>;

impl<T: Clone> Bitree<T> {
    pub fn new() -> Self { Self { root: None } }
    pub fn from(strs: &[&str]) -> Self where T: std::str::FromStr, <T as std::str::FromStr>::Err: Debug {
        fn _Bitree<T>(node: Option<&mut TNode<T>>, strs: &[&str], i: usize) where T: std::str::FromStr, <T as std::str::FromStr>::Err: Debug {
            let (l, size, mut n) = ((i << 1) + 1, strs.len(), node.unwrap().borrow_mut());
            let r = l + 1;
            if l < size && strs[l] != "N" {
                n.left = Some(Rc::new(RefCell::new(Node { val: strs[l].parse::<T>().unwrap(), left: None, right: None })));
                _Bitree(n.left.as_mut(), strs, l);
            }
            if r < size && strs[r] != "N" {
                n.right = Some(Rc::new(RefCell::new(Node { val: strs[r].parse::<T>().unwrap(), left: None, right: None })));
                _Bitree(n.right.as_mut(), strs, r);
            }
        }
        let mut tree: Self = Self { root: None };
        if !strs.is_empty() {
            tree.root = Some(Rc::new(RefCell::new(Node { val: strs[0].parse::<T>().unwrap(), left: None, right: None })));
            _Bitree(tree.root.as_mut(), strs, 0);
        }
        tree
    }
    pub fn preorder(&self) -> Vec<T> {
        let (mut s, mut c, mut iter) = (vec![], vec![], self.root.clone());
        while !s.is_empty() || iter.is_some() {
            while let Some(node) = iter {
                c.push(node.borrow().val.clone());
                iter = node.borrow().left.clone();
                s.push(node);
            }
            iter = s.pop().unwrap().borrow().right.clone();
        }
        c
    }
    pub fn inorder(&self) -> Vec<T> {
        let (mut s, mut c, mut iter) = (vec![], vec![], self.root.clone());
        while !s.is_empty() || iter.is_some() {
            while let Some(node) = iter {
                iter = node.borrow().left.clone();
                s.push(node);
            }
            let node = s.pop().clone().unwrap();
            c.push(node.borrow().val.clone());
            iter = node.borrow().right.clone();
        }
        c
    }
    pub fn postorder(&self) -> Vec<T> {
        let mut c = vec![];
        if self.root.is_some() {
            let (mut s, mut iter) = (vec![], self.root.clone());
            s.push(None);
            while !s.is_empty() || iter.is_some() {
                match iter {
                    Some(node) => {
                        s.push(Some(node.clone()));
                        s.push(None);
                        if let Some(right) = node.borrow().right.clone() { s.push(Some(right)); }
                        if let Some(left) = node.borrow().left.clone() { s.push(Some(left)); }
                    }
                    _ => c.push(s.pop().unwrap().unwrap().borrow().val.clone())
                }
                iter = s.pop().unwrap();
            }
        }
        c
    }
    pub fn level(&self) -> Vec<T> {
        let (mut c, mut q, mut iter) = (vec![], VecDeque::new(), self.root.clone());
        while let Some(node) = iter {
            c.push(node.borrow().val.clone());
            if let Some(left) = node.borrow().left.clone() { q.push_back(left); }
            if let Some(right) = node.borrow().right.clone() { q.push_back(right); }
            if q.is_empty() { break; }
            iter = q.pop_front();
        }
        c
    }
    #[inline]
    pub fn depth(&self) -> usize {
        fn helper<T>(node: Option<&TNode<T>>) -> usize {
            match node {
                Some(n) => 1 + max(helper(n.borrow().left.as_ref()), helper(n.borrow().right.as_ref())),
                _ => 0
            }
        }
        helper(self.root.as_ref())
    }
}

struct Node<T> {
    val: T,
    left: Option<TNode<T>>,
    right: Option<TNode<T>>,
}

struct Bitree<T> {
    root: Option<TNode<T>>,
}

6. 自我测试

伪代码实践

  1. 递归方式求树的深度十分简单,请用迭代方式实现。

LeetCode选荐

  1. Construct Binary Tree from Inorder ans Postorder Traversal
  2. Serialize and Deserialize Binary Tree
  3. House Robber III
  4. Binary Tree Paths
  5. Lowest Common Ancestor of a Binary Tree
  6. Invert Binary Tree
  7. Binary Tree Right Side View
  8. Binary Tree Maximum Path Sum
  9. Path Sum II

测试参考解答

让每一天足够精致,期待与您的再次相遇! ^_^


  1. 图片引自tutorialspoint,在此鸣谢。 ↩︎

  2. 图片引自Wikipedia,在此鸣谢。 ↩︎

posted @ 2021-07-06 18:07  我的名字被占用  阅读(132)  评论(0)    收藏  举报