09 二叉搜索树
09 二叉搜索树
作者:abnb250/山中鹤鸣
博客:https://www.cnblogs.com/abnb250
交流群:1062464078
点击返回目录
前情提要
这一节用模板实现 BST
注释版集中在删除节点、克隆异常、移动语义三处:
删除叶子节点时不能 return n(已 delete),删除单孩子节点时必须先保存孩子再 delete n,双孩子删除的 dummy 参数只接收递归里的 erased;
cloneRec 的 catch 里不能只 delete tmp,左子树可能已克隆,必须 clearRec(tmp);
移动构造/移动赋值必须把源的 root_ 置空,否则源析构会二次释放整棵树。
代码(加注释版)
注释解释了两种场景:
- 代码有反直觉痕迹,自然写法就在旁边。
- 代码看起来自然,但背后有隐形决策。
BST.h
#ifndef BST_H
#define BST_H
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include <utility>
#include <cstddef>
#include <queue>
template<class T>
class BST{
private:
struct Node{
T v;
Node* left = nullptr;
Node* right = nullptr;
explicit Node(const T& val) : v(val) {}
explicit Node(T&& val) : v(std::move(val)) {}
};
Node* root_ = nullptr;
std::size_t size_ = 0;
void clearRec(Node* n) noexcept;
Node* minNode(Node* n) const;
Node* maxNode(Node* n) const;
Node* insertRec(Node* n, const T& val, bool& inserted);
Node* insertRec(Node* n, T&& val, bool& inserted);
Node* eraseRec(Node* n, const T& val, bool& erased);
Node* findNode(const T& val) const;
std::size_t heightRec(const Node* n) const;
Node* cloneRec(const Node* n);
template<class Fn> void inorderRec(Node* n, Fn& fn) const;
template<class Fn> void preorderRec(Node* n, Fn& fn) const;
template<class Fn> void postorderRec(Node* n, Fn& fn) const;
public:
BST() noexcept = default;
~BST() noexcept;
BST(const BST& other);
BST& operator=(const BST& other);
BST(BST&& other) noexcept;
BST& operator=(BST&& other) noexcept;
void swap(BST& other) noexcept;
friend void swap(BST& a, BST& b) noexcept {a.swap(b);}
bool insert(const T& val);
bool insert(T&& val);
bool contains(const T& val) const;
const T* find(const T& val) const;
const T& minimum() const;
const T& maximum() const;
bool erase(const T& val);
template<class Fn> void inorder(Fn&& fn) const;
template<class Fn> void preorder(Fn&& fn) const;
template<class Fn> void postorder(Fn&& fn) const;
template<class Fn> void levelorder(Fn&& fn) const;
std::size_t size() const noexcept {return size_;}
bool empty() const noexcept {return size_ == 0;}
std::size_t height() const;
void clear() noexcept;
};
template <typename T>
void BST<T>::clearRec(Node *n) noexcept
{
if (n == nullptr)
return;
if (n->left)
clearRec(n->left);
if (n->right)
clearRec(n->right);
delete n;
}
template <typename T>
typename BST<T>::Node* BST<T>::minNode(Node *n) const
{
if (n == nullptr)
{
throw std::out_of_range("nullptr pointer");
}
if (n->left)
return minNode(n->left);
return n;
}
template <typename T>
typename BST<T>::Node* BST<T>::maxNode(Node *n) const
{
if (n == nullptr)
{
throw std::out_of_range("nullptr pointer");
}
if (n->right)
return maxNode(n->right);
return n;
}
template <typename T>
typename BST<T>::Node* BST<T>::insertRec(Node *n, const T &val, bool &inserted)
{
if (n == nullptr)
{
inserted = true;
n = new Node(val);
return n;
}
if (val > n->v)
n->right = insertRec(n->right, val, inserted);
else if (val < n->v)
n->left = insertRec(n->left, val, inserted);
if (val == n->v) return n;
return n;
}
template <typename T>
typename BST<T>::Node* BST<T>::insertRec(Node *n, T&& val, bool &inserted)
{
if (n == nullptr)
{
inserted = true;
return new Node(std::move(val));
}
if (val < n->v)
n->left = insertRec(n->left, std::move(val), inserted);
else if (val > n->v)
n->right = insertRec(n->right, std::move(val), inserted);
return n;
}
template <typename T>
typename BST<T>::Node* BST<T>::eraseRec(Node *n, const T &val, bool &erased)
{
if (n == nullptr)
return nullptr;
if (val < n->v)
{
n->left = eraseRec(n->left, val, erased);
return n;
}
else if (val > n->v)
{
n->right = eraseRec(n->right, val, erased);
return n;
}
erased = true;
if (!n->left && !n->right)
{
// 不能 return n,n 已 delete,父节点会挂悬空指针
delete n;
return nullptr;
}
if (!(n->left))
{
// 不能直接 delete n; return n->right;,delete 后访问 n->right 是 UB;必须先保存孩子
Node* tmp = n->right;
delete n;
return tmp;
}
if (!(n->right))
{
// 同上,单孩子删除必须先保存孩子再 delete n
Node* tmp = n->left;
delete n;
return tmp;
}
Node *tmp = minNode(n->right);
std::swap(n->v, tmp->v);
// dummy 只用于接收递归里的 erased;外层 erased 已为 true,不需要再改
bool dummy = false;
n->right = eraseRec(n->right, tmp->v, dummy);
return n;
}
template <typename T>
typename BST<T>::Node* BST<T>::findNode(const T &val) const
{
Node *tmp = root_;
while (tmp)
{
if (val > tmp->v)
tmp = tmp->right;
else if (val < tmp->v)
tmp = tmp->left;
else
return tmp;
}
return nullptr;
}
template <typename T>
std::size_t BST<T>::heightRec(const Node *n) const
{
if (n == nullptr)
return static_cast<std::size_t>(0);
return std::max(heightRec(n->left), heightRec(n->right)) + 1;
}
template <typename T>
typename BST<T>::Node* BST<T>::cloneRec(const Node *n)
{
if (n == nullptr)
return nullptr;
Node *tmp = new Node(n->v);
try
{
tmp->left = cloneRec(n->left);
tmp->right = cloneRec(n->right);
}
catch (...)
{
// 不能只 delete tmp,左子树可能已克隆,会泄漏
clearRec(tmp);
throw;
}
return tmp;
}
template <typename T>
template <class Fn>
void BST<T>::inorderRec(Node *n, Fn &fn) const
{
if (n == nullptr)
return;
inorderRec(n->left, fn);
fn(n->v);
inorderRec(n->right, fn);
}
template <typename T>
template <class Fn>
void BST<T>::preorderRec(Node *n, Fn &fn) const
{
if (n == nullptr)
return;
fn(n->v);
preorderRec(n->left, fn);
preorderRec(n->right, fn);
}
template <typename T>
template <class Fn>
void BST<T>::postorderRec(Node *n, Fn &fn) const
{
if (n == nullptr)
return;
postorderRec(n->left, fn);
postorderRec(n->right, fn);
fn(n->v);
}
template<typename T>
BST<T>::~BST() noexcept {
clear();
}
template<typename T>
BST<T>::BST(const BST& other):
root_(cloneRec(other.root_)), size_(other.size_) {
}
template<typename T>
BST<T>& BST<T>::operator=(const BST& other) {
if(this == &other) return *this;
// 不能先 clear 再 cloneRec,拷贝抛异常时原树已丢
BST tmp(other);
swap(tmp);
return *this;
}
template<typename T>
BST<T>::BST(BST&& other) noexcept : root_(other.root_), size_(other.size_){
// 不能省略置空 other,否则 other 析构会删除同一棵树,双重释放
other.root_ = nullptr;
other.size_ = 0;
}
template<typename T>
BST<T>& BST<T>::operator=(BST&& other) noexcept {
if(this == &other) return *this;
clear();
root_ = other.root_;
size_ = other.size_;
// 不能省略置空 other,否则 other 析构会删除已转移的树,双重释放
other.root_ = nullptr;
other.size_ = 0;
return *this;
}
template<typename T>
void BST<T>::swap(BST& other) noexcept {
std::swap(root_, other.root_);
std::swap(size_, other.size_);
}
template<typename T>
bool BST<T>::insert(const T& val) {
bool dummy = false;
root_ = insertRec(root_, val, dummy);
if(dummy) size_++;
return dummy;
}
template<typename T>
bool BST<T>::insert(T&& val) {
bool dummy = false;
root_ = insertRec(root_, std::move(val), dummy);
if(dummy) size_++;
return dummy;
}
template<typename T>
bool BST<T>::contains(const T& val) const {
return findNode(val) != nullptr;
}
template<typename T>
const T* BST<T>::find(const T& val) const {
Node* tmp = findNode(val);
if(tmp == nullptr) return nullptr;
return &tmp->v;
}
template<typename T>
const T& BST<T>::minimum() const {
const Node* tmp = minNode(root_);
return tmp->v;
}
template<typename T>
const T& BST<T>::maximum() const {
const Node* tmp = maxNode(root_);
return tmp->v;
}
template<typename T>
bool BST<T>::erase(const T& val) {
bool dummy = false;
root_ = eraseRec(root_, val, dummy);
if(dummy) size_--;
return dummy;
}
template<typename T>
template<class Fn>
void BST<T>::inorder(Fn&& fn) const {
inorderRec(root_, fn);
}
template<typename T>
template<class Fn>
void BST<T>::preorder(Fn&& fn) const {
preorderRec(root_, fn);
}
template<typename T>
template<class Fn>
void BST<T>::postorder(Fn&& fn) const {
postorderRec(root_, fn);
}
template<typename T>
template<class Fn>
void BST<T>::levelorder(Fn&& fn) const {
if(root_ == nullptr) return;
std::queue<Node*> q;
q.push(root_);
while(!q.empty()){
Node* tmp = q.front();
q.pop();
fn(tmp->v);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
}
template<typename T>
std::size_t BST<T>::height() const {
return heightRec(root_);
}
template<typename T>
void BST<T>::clear() noexcept {
clearRec(root_);
root_ = nullptr;
size_ = 0;
}
#endif
/*
我要这天再遮不住我眼,我要这地再埋不住我心。
交流群:1062464078
*/

浙公网安备 33010602011771号