二叉搜索树(BST)

13 阅读10分钟

说明

BST树称作二叉搜索树(Binary Search Tree)或者二叉排序树(Binary Sort Tree),它或者是一颗空 树;或者是具有下列性质的二叉树:

  • 若左子树不为空,则左子树上所有节点的值均小于它的根节点的值
  • 若右子树不为空,则右子树上所有节点的值均大于它的根节点的值
  • 左右子树也分别满足二叉搜索树性质

特点: 每一个节点都满足 左孩子的值(不为空) < 父节点的值 < 右孩子的值(不为空)

非递归方式插入、删除、查询

代码

#include <iostream>
#include <functional>
using namespace std;



// BST树代码实现
template<typename T, typename Compare=less<T>>
class BSTree {
public:
  BSTree() : root_(nullptr) {
    
  }

  ~BSTree() {
    
  }

  // 非递归删除操作
  void n_remove(const T &val) {
    if (root_ == nullptr) {
      return;
    }

    Node* parent = nullptr;
    Node* cur = root_;

    while (cur != nullptr) {
      if (cur->data_ == val) {
        break; // 相等。找到待删除节点
      } else if (compare_(cur->data_, val)) {
        parent = cur;
        cur = cur->right_;
      } else {
        parent = cur;
        cur = cur->left_;
      }
    }

    // 没找到待删除节点
    if (cur == nullptr) {
      return;
    }

    // 先处理有两个子节点的情况
    if (cur->left_ != nullptr && cur->right_ != nullptr) {
      Node *pre = cur->left_;
      while (pre->right_ != nullptr) {
        pre = pre->right_;   // 找到左子树中最大的节点(找到前驱)
      }

      cur->data_ = pre->data_;

      cur = pre;  // 让cur指向前驱节点
    }

    // 当节点有一个子节点或者两个子节点的话
    // cur指向删除节点,parent指向其父节点

    Node* child = cur->left_;
    if (child == nullptr) {
      child = cur->right_;
    }

    if (parent == nullptr) {  // 表示删除的是根节点
      root_ = child;

    } else {
      // 把待删除节点的孩子(nullptr,或者不空) ,写入其父节点相应的地址域中
      if (parent->left_ == cur) {
        parent->left_ = child;
      } else {
        parent->right_ = child;
      }

    }

    // cur指向的是待删除节点
    delete cur;  // 删除当前节点

  };

  // 非递归插入操作
  void n_insert(const T &val) {

    if (root_ == nullptr) {  // 树为空, 生成根节点
      root_ = new Node(val);
      return;
    }

    // 从根节点往下找,为了找到合适的parent
    Node* parent = nullptr;
    Node* cur = root_;

    while (cur != nullptr) {
      if (cur->data_ == val) {
        return; // 相等,不插入相同值
      } else if (compare_(cur->data_, val)) {
        // 插入的值大于节点元素值,往右走
        parent = cur;
        cur = cur->right_;
      } else {
        // 插入的值小于节点元素值,往左走
        parent = cur;
        cur = cur->left_;
      }
    }

    // 把新节点插入到parent节点的孩子上
    if (compare_(parent->data_, val)) {  // 比较插入的值与parant的大小后进行插入
      parent->right_ = new Node(val);
    } else {
      parent->left_ = new Node(val);
    }

  }

  // 非递归查询操作
  bool n_query(const T& val) {
      Node* cur = root_;
      while (cur != nullptr) {
          if (cur->data_ == val) {
              return true;
          }
          else if (compare_(cur->data_, val)) {
              cur = cur->right_;
          }
          else {
              cur = cur->left_;
          }
      }

      return false;
  }

private:
  // 节点定义
  struct Node {

    Node(T data = T())
      : data_(data)
      , left_(nullptr)
      , right_(nullptr) {

    }

    T data_;  // 节点的数据域
    Node* left_;  // 左孩子
    Node* right_;  // 右孩子
  };

  Node* root_;  // 指向BST树的根节点
  Compare compare_; // 定义一个函数对象

};

int main() {

  int arr[] = {58, 24, 67, 0, 34, 62, 69, 5, 41, 64, 78};

  BSTree<int> bst;
  for (int v : arr) {
    bst.n_insert(v);
  }

  bst.n_insert(12);
  bst.n_remove(12);

  // 测试查询
  cout << bst.n_query(34) << endl;
  cout << bst.n_query(99) << endl;


  return 0;
}

测试

我们使用调试方式查看下树的结构

image.png

Untitled1.gif

递归前序遍历,中序遍历,后序遍历,层序遍历

#include <iostream>
#include <functional>
using namespace std;



// BST树代码实现
template<typename T, typename Compare=less<T>>
class BSTree {
public:
  BSTree() : root_(nullptr) {
    
  }

  ~BSTree() {
    
  }

  // 非递归删除操作
  void n_remove(const T &val) {
    if (root_ == nullptr) {
      return;
    }

    Node* parent = nullptr;
    Node* cur = root_;

    while (cur != nullptr) {
      if (cur->data_ == val) {
        break; // 相等。找到待删除节点
      } else if (compare_(cur->data_, val)) {
        parent = cur;
        cur = cur->right_;
      } else {
        parent = cur;
        cur = cur->left_;
      }
    }

    // 没找到待删除节点
    if (cur == nullptr) {
      return;
    }

    // 先处理有两个子节点的情况
    if (cur->left_ != nullptr && cur->right_ != nullptr) {
      Node *pre = cur->left_;
      while (pre->right_ != nullptr) {
        pre = pre->right_;   // 找到左子树中最大的节点(找到前驱)
      }

      cur->data_ = pre->data_;

      cur = pre;  // 让cur指向前驱节点
    }

    // 当节点有一个子节点或者两个子节点的话
    // cur指向删除节点,parent指向其父节点

    Node* child = cur->left_;
    if (child == nullptr) {
      child = cur->right_;
    }

    if (parent == nullptr) {  // 表示删除的是根节点
      root_ = child;

    } else {
      // 把待删除节点的孩子(nullptr,或者不空) ,写入其父节点相应的地址域中
      if (parent->left_ == cur) {
        parent->left_ = child;
      } else {
        parent->right_ = child;
      }

    }

    // cur指向的是待删除节点
    delete cur;  // 删除当前节点

  };

  // 非递归插入操作
  void n_insert(const T &val) {

    if (root_ == nullptr) {  // 树为空, 生成根节点
      root_ = new Node(val);
      return;
    }

    // 从根节点往下找,为了找到合适的parent
    Node* parent = nullptr;
    Node* cur = root_;

    while (cur != nullptr) {
      if (cur->data_ == val) {
        return; // 相等,不插入相同值
      } else if (compare_(cur->data_, val)) {
        // 插入的值大于节点元素值,往右走
        parent = cur;
        cur = cur->right_;
      } else {
        // 插入的值小于节点元素值,往左走
        parent = cur;
        cur = cur->left_;
      }
    }

    // 把新节点插入到parent节点的孩子上
    if (compare_(parent->data_, val)) {  // 比较插入的值与parant的大小后进行插入
      parent->right_ = new Node(val);
    } else {
      parent->left_ = new Node(val);
    }

  }

  // 非递归查询操作
  bool n_query(const T& val) {
      Node* cur = root_;
      while (cur != nullptr) {
          if (cur->data_ == val) {
              return true;
          }
          else if (compare_(cur->data_, val)) {
              cur = cur->right_;
          }
          else {
              cur = cur->left_;
          }
      }

      return false;
  }

  // 递归前序遍历
  void preOrder() {
    cout << "[递归]前序遍历";
    preOrder(root_);
    cout << endl;
  }

  // 递归中序遍历
  void inOrder() {
    cout << "[递归]中序遍历";
    inOrder(root_);
    cout << endl;
  }

  // 递归后序遍历
  void postOrder() {
    cout << "[递归后序遍历]";
    postOrder(root_);
    cout << endl;
  }

  // 递归层序遍历
  void levelOrder() {
    cout << "递归层序遍历";

    int h = high();  // 树的层数
    for (int i = 0; i < h; i++) {
      levelOrder(root_, i);
    }

    cout << endl;
  }

  // 递归求二叉树层数
  int high() {
    return high(root_);
  }

  // 递归求二叉树节点个数
  int number() {
    return number(root_);
  }



private:
  // 节点定义
  struct Node {

    Node(T data = T())
      : data_(data)
      , left_(nullptr)
      , right_(nullptr) {

    }

    T data_;  // 节点的数据域
    Node* left_;  // 左孩子
    Node* right_;  // 右孩子
  };

  Node* root_;  // 指向BST树的根节点
  Compare compare_; // 定义一个函数对象

  // 递归前序遍历的实现 VLR
  void preOrder(Node* node) {
    if (node != nullptr) {
      cout << node->data_ << " ";  // 操作V
      preOrder(node->left_);  // 访问左孩子L
      preOrder(node->right_);  // 访问右孩子R
    }
  }

  // 递归中序遍历实现 LVR
  void inOrder(Node* node) {
    if (node != nullptr) {
      inOrder(node->left_);  // 访问左孩子L
      cout << node->data_ << " ";  // 操作V
      inOrder(node->right_);  // 访问右孩子R
    }
  }

  // 递归后序遍历 LRV
  void postOrder(Node* node) {
    if (node != nullptr) {
      postOrder(node->left_);  // 访问左孩子L
      postOrder(node->right_);  // 访问右孩子R
      cout << node->data_ << " ";  // 操作V
    }
  }

  // 递归求二叉树层数
  int high(Node* node) {
    if (node == nullptr) {
      return 0;
    }
    int left = high(node->left_);
    int right = high(node->right_);

    return left > right ? left + 1 : right + 1;
  }

  // 递归求二叉树节点个数
  int number(Node* node) {
    if (node == nullptr) {
      return 0;
    }

    int left = number(node->left_);
    int right = number(node->right_);
    return left + right + 1;
  }

  // 递归层序遍历的实现
  void levelOrder(Node* node, int i) {
    if (node == nullptr) {
      return;
    }

    // 到了要打印的层数了,
    if (i == 0) {
      cout << node->data_ << " ";
      return;
    }

    levelOrder(node->left_, i - 1);
    levelOrder(node->right_, i - 1);
  }


};

int main() {

  int arr[] = {58, 24, 67, 0, 34, 62, 69, 5, 41, 64, 78};

  BSTree<int> bst;
  for (int v : arr) {
    bst.n_insert(v);
  }

  bst.n_insert(12);
  bst.n_remove(12);

  // 测试查询
  cout << bst.n_query(34) << endl;
  cout << bst.n_query(99) << endl;

  // 测试递归遍历
  bst.preOrder();
  bst.inOrder();
  bst.postOrder();
  bst.levelOrder();


  return 0;
}

测试结果

image.png

中序遍历是从小到大排序的。

image.png

递归插入,查询,删除

#include <iostream>
#include <functional>
using namespace std;


// BST树代码实现
template<typename T, typename Compare=less<T>>
class BSTree {
public:
  BSTree() : root_(nullptr) {
    
  }

  ~BSTree() {
    
  }


  // 递归前序遍历
  void preOrder() {
    cout << "[递归前序遍历]";
    preOrder(root_);
    cout << endl;
  }

  // 递归中序遍历
  void inOrder() {
    cout << "[递归中序遍历]";
    inOrder(root_);
    cout << endl;
  }

  // 递归后序遍历
  void postOrder() {
    cout << "[递归后序遍历]";
    postOrder(root_);
    cout << endl;
  }

  // 递归层序遍历
  void levelOrder() {
    cout << "[递归层序遍历]";

    int h = high();  // 树的层数
    for (int i = 0; i < h; i++) {
      levelOrder(root_, i);
    }

    cout << endl;
  }

  // 递归求二叉树层数
  int high() {
    return high(root_);
  }

  // 递归求二叉树节点个数
  int number() {
    return number(root_);
  }

  // 递归插入操作
  void insert(const T &val) {
    root_ = insert(root_, val);
  }

  // 递归查询操作
  bool query(const T& val) {
    return nullptr != query(root_, val);
  }

  // 递归删除操作
  void remove(const T& val) {
    root_ = remove(root_, val);
  }


private:
  // 节点定义
  struct Node {

    Node(T data = T())
      : data_(data)
      , left_(nullptr)
      , right_(nullptr) {

    }

    T data_;  // 节点的数据域
    Node* left_;  // 左孩子
    Node* right_;  // 右孩子
  };

  Node* root_;  // 指向BST树的根节点
  Compare compare_; // 定义一个函数对象

  // 递归前序遍历的实现 VLR
  void preOrder(Node* node) {
    if (node != nullptr) {
      cout << node->data_ << " ";  // 操作V
      preOrder(node->left_);  // 访问左孩子L
      preOrder(node->right_);  // 访问右孩子R
    }
  }

  // 递归中序遍历实现 LVR
  void inOrder(Node* node) {
    if (node != nullptr) {
      inOrder(node->left_);  // 访问左孩子L
      cout << node->data_ << " ";  // 操作V
      inOrder(node->right_);  // 访问右孩子R
    }
  }

  // 递归后序遍历 LRV
  void postOrder(Node* node) {
    if (node != nullptr) {
      postOrder(node->left_);  // 访问左孩子L
      postOrder(node->right_);  // 访问右孩子R
      cout << node->data_ << " ";  // 操作V
    }
  }

  // 递归求二叉树层数
  int high(Node* node) {
    if (node == nullptr) {
      return 0;
    }
    int left = high(node->left_);
    int right = high(node->right_);

    return left > right ? left + 1 : right + 1;
  }

  // 递归求二叉树节点个数
  int number(Node* node) {
    if (node == nullptr) {
      return 0;
    }

    int left = number(node->left_);
    int right = number(node->right_);
    return left + right + 1;
  }

  // 递归层序遍历的实现
  void levelOrder(Node* node, int i) {
    if (node == nullptr) {
      return;
    }

    // 到了要打印的层数了,
    if (i == 0) {
      cout << node->data_ << " ";
      return;
    }

    levelOrder(node->left_, i - 1);
    levelOrder(node->right_, i - 1);
  }

  // 递归插入操作
  Node* insert(Node* node,  const T &val) {
    if (node == nullptr) {
      // 递归结束,找到插入val的位置,生成新节点并返回其节点地址
      return new Node(val);
    }

    if (node->data_ == val) {
      return node;
    } else if (compare_(node->data_, val)) {
      // 插入的元素比当前节点的值大,往右边进行插入
      node->right_ = insert(node->right_, val);
      return node;
    } else {
      node->left_ = insert(node->left_, val);
      return node;
    }

  }

  // 递归查询
  Node* query(Node* node, const T& val) {
    if (node == nullptr) {
      return nullptr;
    }

    if (node->data_ == val) {
      return node;
    } else if (compare_(node->data_, val)) {
      return query(node->right_, val);
    } else {
      return query(node->left_, val);
    }
  }

  // 递归删除操作
  Node* remove(Node* node, const T& val) {
    if (node == nullptr) {
      return nullptr;
    }

    if (node->data_ == val) {  // 找到待删除节点
      // 有两个孩子
      if (node->left_ != nullptr && node->right_ != nullptr) {
        // 找前驱结点
        Node* pre = node->left_;
        while (pre->right_ != nullptr) {
          pre = pre->right_;
        }

        node->data_ = pre->data_;

        // 通过递归直接删除前驱节点
        node->left_ = remove(node->left_, pre->data_);
      } else {
        if (node->left_ != nullptr) {
          Node* left = node->left_;
          delete node;
          return left;
        } else if (node->right_ != nullptr) {
          Node* right = node->right_;
          delete node;
          return right;
        } else {
          // 删除的是没有孩子的节点, 删除叶子节点
          delete node;
          return nullptr;
        }
      }

    } else if (compare_(node->data_, val)) {
      node->right_ = remove(node->right_, val);
    } else {
      node->left_ = remove(node->left_, val);
    }

    return node;  // 把当前节点返回给父节点, 更新父节点相应的地址域

  }

};

int main() {

  int arr[] = {58, 24, 67, 0, 34, 62, 69, 5, 41, 64, 78};

  BSTree<int> bst;
  // for (int v : arr) {
  //   bst.n_insert(v);
  // }

  for (int v : arr) {
    bst.insert(v);
  }
  
  // // 测试递归遍历
  // bst.preOrder();
  // bst.inOrder();
  // bst.postOrder();
  // bst.levelOrder();

  // 测试递归查询
  // cout << bst.query(58) << endl;
  bst.remove(24);


  return 0;
}

测试删除结果

Peek 2025-06-10 21-18.gif

非递归前序遍历,中序遍历,后续遍历,层序遍历

#include <iostream>
#include <functional>
#include <stack>
#include <queue>
using namespace std;



// BST树代码实现
template<typename T, typename Compare=less<T>>
class BSTree {
public:
  BSTree() : root_(nullptr) {
    
  }

  ~BSTree() {
    
  }


  // 非递归插入操作
  void n_insert(const T &val) {

    if (root_ == nullptr) {  // 树为空, 生成根节点
      root_ = new Node(val);
      return;
    }

    // 从根节点往下找,为了找到合适的parent
    Node* parent = nullptr;
    Node* cur = root_;

    while (cur != nullptr) {
      if (cur->data_ == val) {
        return; // 相等,不插入相同值
      } else if (compare_(cur->data_, val)) {
        // 插入的值大于节点元素值,往右走
        parent = cur;
        cur = cur->right_;
      } else {
        // 插入的值小于节点元素值,往左走
        parent = cur;
        cur = cur->left_;
      }
    }

    // 把新节点插入到parent节点的孩子上
    if (compare_(parent->data_, val)) {  // 比较插入的值与parant的大小后进行插入
      parent->right_ = new Node(val);
    } else {
      parent->left_ = new Node(val);
    }

  }




  // 非递归前序遍历, 借助一个栈
  void n_preOrder() {
    cout << "[非递归前序遍历]";

    if (root_ == nullptr) {
      return;
    }

    stack<Node*> s;

    s.push(root_);

    while (!s.empty()) {
      Node* top = s.top();
      s.pop();

      cout << top->data_ << " ";  // V处理了

      if (top->right_ != nullptr) {
        s.push(top->right_);  // 入栈R
      }

      if (top->left_ != nullptr) {
        s.push(top->left_);   // 入栈L, 后入栈的先访问
      }
    }

    cout << endl;
  }

  // 非递归中序遍历
  void n_inOrder() {
    cout << "[非递归中序遍历]";

    if (root_ == nullptr) {
      return;
    }


    stack<Node*> s;

    Node* cur = root_;

    while (cur != nullptr) {
      s.push(cur);
      cur = cur->left_;
    }

    while (!s.empty()) {
      Node* top = s.top();
      s.pop();

      cout << top->data_ << " ";

      cur = top->right_;
      while (cur != nullptr) {
        s.push(cur);
        cur = cur->left_;
      }
    }

    cout << endl;
  }

  // 非递归后续遍历
  // 使用两个栈,LRV遍历的方式转为VRL, 最后使用一个栈将VRL转为LRV
  void n_postOrder() {
    cout << "[非递归后续遍历]";

    if (root_ == nullptr) {
      return;
    }

    stack<Node*> s1;
    stack<Node*> s2;

    s1.push(root_);

    while (!s1.empty()) {
      Node* top = s1.top();
      s1.pop();

      s2.push(top);  // V

      if (top->left_ != nullptr) {
        s1.push(top->left_);  // L
      }

      if (top->right_ != nullptr) {
        s1.push(top->right_);  // R
      }
    }

    // 栈2打印出来即是LRV
    while (!s2.empty()) {
      cout << s2.top()->data_ << " ";
      s2.pop();
    }

    cout << endl;
  }

  // 非递归层序遍历
  // 使用一个队列queue
  void n_levelOrder() {
    cout << "[非递归层序遍历]";

    if (root_ == nullptr) {
      return;
    }

    queue<Node*> que;

    que.push(root_);

    while (!que.empty()) {
      Node * front = que.front();
      que.pop();

      cout << front->data_ << " ";
      if (front->left_ != nullptr) {
        que.push(front->left_);
      }

      if (front->right_ != nullptr) {
        que.push(front->right_);
      }
    }

    cout << endl;
  }


private:
  // 节点定义
  struct Node {

    Node(T data = T())
      : data_(data)
      , left_(nullptr)
      , right_(nullptr) {

    }

    T data_;  // 节点的数据域
    Node* left_;  // 左孩子
    Node* right_;  // 右孩子
  };

  Node* root_;  // 指向BST树的根节点
  Compare compare_; // 定义一个函数对象



};

int main() {

  int arr[] = {58, 24, 67, 0, 34, 62, 69, 5, 41, 64, 78};


  for (int v : arr) {
    bst.n_insert(v);
  }

  // 测试非递归查询
  bst.n_preOrder();
  bst.n_inOrder();
  bst.n_postOrder();
  bst.n_levelOrder();

  return 0;
}

测试代码

image.png

image.png