文章目录
前言
本文总结学习搜索二叉树模拟实现-C++。
一、基本框架构建
// 搜索二叉树节点
template <class K, class V>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
V _val;
BSTreeNode(K key = K(), V val = V())
: _left(nullptr)
, _right(nullptr)
, _key(key)
, _val(val)
{}
};
// 搜索二叉树模拟实现
template <class K, class V>
class BSTree
{
public:
typedef BSTreeNode<K, V> node;
// 构造函数
BSTree()
: _root(new node())
{}
// 拷贝构造 bs2(bs1)!!!!!!!!!!忘记~~~
BSTree(const BSTree<K, V>& tree)
{
_root = _copyTree(tree._root);
}
// 赋值运算符重载(现代写法) bs2 = bs1
BSTree<K, V>& operator=(const BSTree<K, V> tree)
{
std::swap(_root, tree._root);
return *this;
}
// 析构函数
~BSTree()
{
_Destroy(_root);
_root = nullptr;
}
private:
node* _root;
};
二、成员函数实现(非递归版本)
2.1 插入元素
时复:o(n)
bool Insert(const K& key, const V& val)
{
// 如果树目前为空
if (nullptr == _root)
{
_root = new Node(key, val);
return true;
}
// 如果树不为空,从根结点开始找合适的位置(不破环搜索二叉树的结构)
// 找不到合适的位置,则插入失败
Node* par = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
par = cur;
cur = cur->_left;
}
else if(cur->_key < key)
{
par = cur;
cur = cur->_right;
}
else
{
// 不允许插入相同值结点
return false;
}
}
Node* newnode = new Node(key);
if (par->_key > key)
{
par->_left = newnode;
return true;
}
else
{
par->_right = newnode;
return true;
}
}
2.2 查找元素
时复:o(n)
bool Find(const K& key)
{
if (nullptr == _root)
{
return false;
}
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
cur = cur->_left;
}
else if (cur->_key > key)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
2.3 删除元素
// 用特殊场景套用才可以写出完整正确+画图!!!!!!!!!!
bool Earse(const K& key)
{
if (nullptr == _root)
{
return false;
}
Node* par = nullptr;
Node* cur = _root;
while (cur)
{
if (key < cur->_key)
{
par = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
par = cur;
cur = cur->_right;
}
else
{
// 找到待删结点
//if (nullptr == cur->_left && nullptr != cur->_right) // 叶子结点可以归并为单侧空的情况
if (nullptr == cur->_left)
{
// 待删结点左为空
// 如果待删结点为根结点,且根结点左为空
if (nullptr == par)
{
_root = cur->_right;
}
else
{
if (cur == par->_left)
{
par->_left = cur->_right;
}
else
{
par->_right = cur->_right;
}
}
delete cur;
}
else if(nullptr == cur->_right)
{
// 待删结点右为空
// 如果待删结点为根结点,且根结点右为空
if (nullptr == par)
{
_root = cur->_left;
}
else
{
if (cur == par->_left)
{
par->_left = cur->_left;
}
else
{
par->_right = cur->_left;
}
}
delete cur;
}
else
{
// 待删节点左右都不为空,使用替换法
// 1-找待删结点右子树的最小结点(即最左结点)来替换
// 不能赋值nullptr,因为可能删的是类似下图结构的根结点!!!!!!!!!!!!!
// 3
//2 4
Node* maxpar = cur;
Node* maxcur = cur->_right;
while (maxcur->_left)
{
maxpar = maxcur;
maxcur = maxcur->_left;
}
swap(cur->_key, maxcur->_key); // 仅是交换结点的值
// maxcur的左子树必为空,但是右子树不确定
// 所以统一处理将maxcur的右子树链接在maxpar和maxcur相对应的一边
if (maxcur == maxpar->_right)
{
maxpar->_right = maxcur->_right;
}
if (maxcur == maxpar->_left)
{
maxpar->_left = maxcur->_right;
}
delete maxcur;
// 2-找待删结点左子树的最大结点来替换(同理)
}
return true;
}
}
return false;
}
2.4 交换节点值
void swap(node* left, node* right)
{
std::swap(left->_key, right->_key);
std::swap(left->_val, right->_val);
}
2.5 中序遍历
// 中序遍历
void InOrder()
{
_InOrder(_root);
}
// 中序遍历子函数(权限为private)
void _InOrder(node* root)
{
if (nullptr == root)
{
return;
}
_InOrder(root->_left);
cout << root->_key << "::" << root->_val << " ";
_InOrder(root->_right);
}
2.6 销毁
// 销毁
void _Destroy(node* root)
{
if (nullptr == root)
{
return;
}
// 后序销毁
_Destroy(root->_left);
_Destroy(root->_right);
delete root; // 调用后置空
}
2.7 拷贝树
// 拷贝树
node* _copyTree(node* root)
{
if (nullptr == root)
{
return nullptr;
}
// 深拷贝,否则会出错
// 前序拷贝
node* newnode = new node(root->_key, root->_val);
newnode->_left = _copyTree(root->_left);
newnode->_right = _copyTree(root->_right);
return newnode;
}
三、成员函数实现(递归版本)
3.1 插入元素
// 插入
bool Insert(const K& key, const V& val)
{
return _Insert(_root, key, val);
}
// 插入子函数(递归)
bool _Insert(node*& root, const K& key, const V& val) // 传参_root必须要引用接收
{
if (nullptr == root)
{
// root是当前函数栈帧的root,也是上一个函数栈帧的root->左/右子节点!!!
root = new node(key, val);
return true;
}
if (key < root->_key)
{
return _Insert(root->_left, key);
}
else if (key > root->_key)
{
return _Insert(root->_right, key);
}
else
{
return false;
}
}
3.2 查找元素
// 查找
bool Find(const K& key)
{
return _Find(_root, key);
}
// 查找子函数(递归)
bool _Find(node*& root, const K& key) // 传参_root必须要引用接收
{
if (nullptr == root)
{
return false;
}
// 借助搜索二叉树特性来分类递归
if (key < root->_key)
{
return _Find(root->_left, key); // 加return,否则之后的递归返回值无法接收
}
else if (key > root->_key)
{
return _Find(root->_right, key); // 加return,否则之后的递归返回值无法接收
}
else
{
return true;
}
}
3.3 删除元素
// 删除
bool Erase(const K& key)
{
return _Erase(_root, key);
}
// 删除元素子函数(递归)
bool _Erase(node*& root, const K& key) // 传参_root必须要引用接收
{
if (nullptr == root)
{
return false;
}
if (key < root->_key)
{
return _Erase(root->_left, key);
}
else if (key > root->_key)
{
return _Erase(root->_right, key);
}
else
{
// 找到待删元素
if (nullptr == root->_key)
{
// 左子树为空
root = root->_right; // root还代表着上一个栈帧中其父节点的左/右子节点!!!
delete root;
}
else if (nullptr == root->_right)
{
// 右子树为空
root = root->_left; // root还代表着上一个栈帧中其父节点的左/右子节点!!!
delete root;
}
else
{
// 左右子树都不为空
// 找其右子树最左节点
node* minP = root;
node* minR = root->_right;
while (minR->_left)
{
minP = minR;
minR = minR->_left;
}
// 交换待删节点和右子树最左节点的值
swap(root, minR);
// 删除
// 此时minR左子树必为空
if (minR == minP->_left)
{
minP->_left = minR->_right;
}
else
{
minP->_right = minR->_right;
}
delete minR;
// 方法2:
// 这样就可以复用删除
// 如果在初始根节点开始使用_Erase会找不到待删节点,因为已经交换,此时整颗树不是搜索二叉树!!!~
// 转换为在root->_left中去删除key,这里删除这个key一定会找到!!!!~
// return _EraseR(root->_left, key);
}
// 统一返回
return true;
}
}
总结
这里对文章进行总结:
以上就是今天总结的内容,本文包括了搜索二叉树模拟实现(带注释)-C++,分享给大家。
真💙欢迎各位给予我更好的建议,小编创作不易,觉得有用可以鼓励哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!🙊🙊🙊