js递归遍历树结构_二分搜索树(BST)的前/中/后序遍历-递归+非递归

二分搜索树(BST)

树结构是一种常见的组织结构,树结构效率出奇的高。

ecbf50781a1c69bef053bcf95de0d49d.png

认识二叉树

二叉树是和链表一样,都是动态数据结构。

二叉树具有唯一的根节点,每个节点最多有一个父节点,最多有两个孩子节点。

dccf56dd9f8c6b0bbc1c2f4864fca2aa.png

二叉树具有天然的递归结构:每个节点的左/右子树也是一棵二叉树。

1884ce84e8fbc604307d07a6e127ad97.png

二叉树不一定是满的,一个节点也是二叉树,空树也是二叉树。

e1df6b93d0594fccc804386471b5f352.png

二分搜索树(Binary Search Tree)

二分搜索树中存储的元素必须就有可比较性。

58cb71c11e391b7973848c5f1bb71119.png

中序遍历(In-Order Traverse)二分搜索树得到的是一个升序序列。

向二分搜索树中插入节点

插入新节点时,先寻找到合适的位置,不能破坏二分搜索树的性质,然后执行插入操作。

af6f9794fd307e2fbb5a601cca986d7d.png

de73330d1c9c69d67a0e0d35b226e98d.png

二分搜索树的遍历

二分搜索树的遍历需要掌握: 先序、中序、后序遍历的递归和非递归实现以及层序遍历。

先/中/后序遍历的递归实现

先序遍历的顺序是:根->左->右。 中序遍历的顺序是:左->根->右。 后序遍历的顺序是:左->右->根

16d02014b16856a031fc0d67ed9955f9.png

先序遍历的非递归实现

通过使用一个栈来实现先序遍历非递归算法。

d3324e779ddca84f0a2932c7cb4db425.png

7dbaa8f9ac6c846590981025302d4763.png

中序遍历的非递归实现

中序遍历非递归算法同样需要使用一个栈来实现。

bd8465f2a09e6187ed7547e6d5f20567.png

0fce84df4d7a9bd991cd8a49c9c0a258.png

d6c61836cb68225009600577a1f522c4.png

后序遍历的非递归实现

后序遍历的顺序为:左->右->根。根节点最后访问,也就是说,只有当为空或者已经被访问,根节点才可以被访问。

ff68aa1cba163c041fbd6d2516fd0b38.png

d17e35e85c4f9b8194c323f68d340af4.png

d53412c9eb37e204c4b38a20902a8932.png

bc19a3475e22df69b7a14eaa52ec35a6.png

二分搜索树的层序遍历

5ba300e3addcb3c419fb83e0fb3830ac.png

二叉树的层序遍历需要使用队列辅助。

9ae430cae77e817449c17bd1e22b85d7.png

773d3ef662d035386bad45717ea44e34.png

二分搜索树的实现

#ifndef BST_H
#define BST_H

#include <iostream>
#include <stack>
#include <queue>

using namespace std;

template <typename T>
class bst
{
 private:
  struct node
  {
    T e;
    node* left;
    node* right;
    node() : e(), left(nullptr), right(nullptr) {}
    node(T e) : e(e), left(nullptr), right(nullptr) {}
    node(T e, node* left, node* right) : e(e), left(left), right(right) {}
  };

 public:
  bst()
  {
    root_ = nullptr;
    size_ = 0;
  }

  ~bst()
  {
    destroy_tree(root_);
  }

  void add(T e)
  {
    root_ = add(root_, e);
  }

  int get_size()
  {
    return size_;
  }

  void pre_order_traverse()
  {
    pre_order_traverse(root_);
    cout << endl;
  }

  void in_order_traverse()
  {
    in_order_traverse(root_);
    cout << endl;
  }

  void post_order_traverse()
  {
    post_order_traverse(root_);
    cout << endl;
  }

  // previous order traverse no recursion
  void pre_order_traverse_nr()
  {
    pre_order_traverse_nr(root_);
  }

  void in_order_traverse_nr()
  {
    in_order_traverse_nr(root_);
  }

  void post_order_traverse_nr()
  {
    post_order_traverse_nr(root_);
  }

  void level_order_traverse()
  {
    level_order_traverse(root_);
  }

 private:
  node* root_;
  int size_;

  void destroy_tree(node* root)
  {
    if (root == nullptr)
      return;
    destroy_tree(root->left);
    destroy_tree(root->right);
    cout << “delete: “ << root->e << endl;
    delete root;
    root = nullptr;
  }

  node* add(node* root, T e);
  void pre_order_traverse(node* root);
  void in_order_traverse(node* root);
  void post_order_traverse(node* root);

  // 非递归算法
  void pre_order_traverse_nr(node* root);
  void in_order_traverse_nr(node* root);
  void post_order_traverse_nr(node* root);

  void level_order_traverse(node* root);
};

template <typename T>
typename bst<T>::node* bst<T>::add(node* root, T e)
{
  if (root == nullptr)
  {
    size_++;
    return new node(e);
  }
  if (root->e > e)
    root->left = add(root->left, e);
  else if (root->e < e)
    root->right = add(root->right, e);
  else
    root->e = e;  // do nothing
  return root;
}

template <typename T>
void bst<T>::pre_order_traverse(node* root)
{
  if (root == nullptr)
    return;
  cout << root->e << “ “;
  pre_order_traverse(root->left);
  pre_order_traverse(root->right);
}

template <typename T>
void bst<T>::in_order_traverse(node* root)
{
  if (root == nullptr)
    return;
  in_order_traverse(root->left);
  cout << root->e << “ “;
  in_order_traverse(root->right);
}

template <typename T>
void bst<T>::post_order_traverse(node* root)
{
  if (root == nullptr)
    return;
  post_order_traverse(root->left);
  post_order_traverse(root->right);
  cout << root->e << " ";
}

template <typename T>
void bst<T>::pre_order_traverse_nr(node* root)
{
  if (root == nullptr)
    return;
  stack<node*> st;
  st.push(root);
  while (!st.empty())
  {
    node* curr = st.top();
    cout << curr->e << “ “;
    st.pop();
    if (curr->right != nullptr)
      st.push(curr->right);
    if (curr->left != nullptr)
      st.push(curr->left);
  }
  cout << endl;
}

template <typename T>
void bst<T>::in_order_traverse_nr(node* root)
{
  stack<node*> st;
  node* curr = root;
  while (curr != nullptr || !st.empty())
  {
    while (curr != nullptr)
    {
      st.push(curr);
      curr = curr->left;
    }
    if (!st.empty())
    {
      curr = st.top();
      cout << curr->e << “ “;
      st.pop();
      curr = curr->right;
    }
  }
  cout << endl;
}

template <typename T>
void bst<T>::post_order_traverse_nr(node* root)
{
  stack<node*> st;
  node* curr = root;
  node* visited = nullptr;
  while (curr != nullptr || !st.empty())
  {
    while (curr != nullptr)
    {
      st.push(curr);
      curr = curr->left;
    }
    if (!st.empty())
    {
      curr = st.top();
      if (curr->right == visited || curr->right == nullptr)
      {
        cout << curr->e << “ “;
        st.pop();
        visited = curr;
        curr = nullptr;
      }
      else
        curr = curr->right;
    }
  }
  cout << endl;
}

template <typename T>
void bst<T>::level_order_traverse(node* root)
{
  if (root == nullptr)
    return;
  queue<node*> q;
  q.push(root);
  while (!q.empty())
  {
    node* curr = q.front();
    q.pop();
    if (curr->left != nullptr)
      q.push(curr->left);
    if (curr->right != nullptr)
      q.push(curr->right);
    cout << curr->e << “ “;

  }
  cout << endl;
}


#endif // BST_H

测试程序

#include “bst.h”
#include <cstdlib>

int main()
{
  bst<int>* my_bst = new bst<int>();
  srand(time(nullptr));
  my_bst->add(54);
  my_bst->add(32);
  my_bst->add(77);
  my_bst->add(18);
  my_bst->add(45);
  my_bst->add(66);
  my_bst->add(81);

  cout << “Pre-Order Traverse: “ << endl;
  my_bst->pre_order_traverse();
  my_bst->pre_order_traverse_nr();
  cout << endl;

  cout << “In-Order Traverse: “ << endl;
  my_bst->in_order_traverse();
  my_bst->in_order_traverse_nr();
  cout << endl;

  cout << “Post-Order Traverse: “ << endl;
  my_bst->post_order_traverse();
  my_bst->post_order_traverse_nr();
  cout << endl;

  cout << “Lever Order Traverse: “ << endl;
  my_bst->level_order_traverse();
  delete my_bst;
  return 0;
}

测试结果。通过观察法可以看出,二叉树的遍历结果是正确的。

f965620fa9eedd434c295d5a324554ac.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值