目录
#pragma once
#include <iostream>
using namespace std;
【K 模型 / key 模型】
K 模型即只有 key 作为关键码,结构中只需要存储 Key 即可,关键码即为需要搜索到的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
- 以词库中所有单词集合中的每个单词作为 key,构建一棵二叉搜索树
- 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
// 节点储存内容: 左孩子、右孩子、key
template<class K>
struct BSTreeNode
{
BSTreeNode(const K& key)
: _left(nullptr)
, _right(nullptr)
, _key(key)
{}
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
};
// K 模型主体结构
namespace key
{
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
/*BSTree()
:_root(nullptr)
{}*/
BSTree() = default; // 指定强制生成默认构造 C++11支持
BSTree(const BSTree<K>& t)
{
_root = Copy(t._root);
}
BSTree<K>& operator=(const BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
~BSTree()
{
Destroy(_root);
_root = nullptr;
}
Node* root()
{
return _root;
}
// Insert
///...
// Find
// ...
// InOrder
// ...
// Erase
// ...
protected:
Node* Copy(Node* root)
{
// 和前序建立的逻辑类似
if (root == nullptr)
return nullptr;
Node* newRoot = new Node(root->_key);
newRoot->_left = Copy(root->_left);
newRoot->_right = Copy(root->_right);
return newRoot;
}
//void Destroy(Node*& root)
void Destroy(Node* root)
{
if (root == nullptr)
return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
// root = nullptr;
}
private:
Node* _root = nullptr;
};
}
// 插入 Insert
public:
bool Insert(const K& key)
{
// 考虑到后面有三叉链,是双向链接,这里也建议统一写法,记录cur的同时保存父亲节点
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
// 链接
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
// 查找 Find
public:
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
// 中序访问 InOrder
public:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
// 递归需要写参数!!
// 为了符合使用习惯,套一层可以解决问题
// void _InOrder(Node* root = _root) // 缺省值必须是全局变量或者是常量。访问全局变量需要this指针?
protected:
void _InOrder(Node* root)
{
if (root == nullptr)
return;
// 中序打印搜索二叉树,会出现有序序列
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
// 删除 Erase🔺
// 分析:对于叶子,直接删就行(也可以归类到托孤(nullptr))
// 对于孩子是叶子节点,且只有一子,直接删,托孤
// 对于有左右孩子的节点,找:左子树的最大节点 or 右子树的最小节点
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
// 删除
// 1. 左为空
if (cur->_left == nullptr)
{
// 特殊处理删除 root(root 没有 parent),直接修改 _root 即可
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
// 2. 右为空
else if (cur->_right == nullptr)
{
// 特殊情况处理,直接修改 _root
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
// 3. 其他
else
{
// 找右树的最小节点代替(也可以找左树的最大节点)
Node* minRight = cur->_right;
Node* pminRight = cur; // 这里不能用nullptr初始化!!!有可能已经满足条件,下面的循环不进去
while (minRight->_left)
{
pminRight = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
if (pminRight->_left == minRight)
{
pminRight->_left = minRight->_right;
}
else
{
pminRight->_right = minRight->_right;
}
delete minRight;
}
return true;
}
}
return false;
}
// 递归方式实现 Find、Insert、Erase
public:
//【递归】
//【FindR】
bool FindR(const K& key)
{
return _FindR(_root, key);
}
// 【InsertR】插入的逻辑很好分析,最重要的是,如何跟父亲链接起来?
// 解决方法:引用!!!!!!!!!!!
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
//【EraseR】
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
protected:
bool _FindR(Node* root, const K& key) // 参数需要调 _root 的最好都套一层
{
if (root == nullptr)
return false;
if (root->_key == key)
return true;
if (root->_key < key)
return _FindR(root->_right, key);
else
return _FindR(root->_left, key);
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_key < key)
{
return _InsertR(root->_right, key);
}
else if (root->_key > key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _EraseR(root->_right, key);
}
if (root->_key > key)
{
return _EraseR(root->_left, key);
}
else
{
// 开始删除
Node* del = root;
// 1. 左为空
if (root->_left == nullptr)
{
root = root->_right;
}
// 2. 右为空
else if (root->_right == nullptr)
{
root = root->_left;
}
// 3. 左右都不为空:
else
{
Node* maxleft = root->_left;
while (maxleft->_right)
{
maxleft = maxleft->_right;
}
swap(root->_key, maxleft->_key);
return _EraseR(root->_left, key);
}
delete del;
return true;
}
return false;
}
【KV 模型 / Key-Value 模型】
代码逻辑基本同 K 模型,只有少许细节变化。
// 节点储存内容: 左孩子、右孩子、key、value
template<class K, class V>
struct BSTreeNode
{
BSTreeNode(const K& key, const V& value)
: _left(nullptr)
, _right(nullptr)
, _key(key)
, _value(value)
{}
BSTreeNode<K, V>* _left;
BSTreeNode<K, V>* _right;
K _key;
V _value;
};
// KV 模型主体结构
namespace keyValue
{
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
public:
~BSTree()
{
Destroy(_root);
_root = nullptr;
}
// Insert
///...
// Find
// ...
// InOrder
// ...
// Erase
// ...
protected:
void Destroy(Node* root)
{
if (root == nullptr)
return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
// root = nullptr;
}
private:
Node* _root = nullptr;
};
}
// 插入 Insert
bool Insert(const K& key, const V& value)
{
// 考虑到后面有三叉链,是双向链接,这里也建议统一写法,记录cur的同时保存父亲节点
if (_root == nullptr)
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key, value);
// 链接
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
// 查找 Find
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
// 中序访问 InOrder
public:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
// 递归需要写参数!!
// 为了符合使用习惯,套一层可以解决问题
// void _InOrder(Node* root = _root) // 缺省值必须是全局变量或者是常量。访问全局变量需要this指针?
protected:
void _InOrder(Node* root)
{
if (root == nullptr)
return;
// 中序打印搜索二叉树,会出现有序序列
_InOrder(root->_left);
cout << root->_key << ":" << root->_value << endl;
_InOrder(root->_right);
}
// 删除 Erase
// 分析:对于叶子,直接删就行(也可以归类到托孤(nullptr))
// 对于孩子是叶子节点,且只有一子,直接删,托孤
// 对于有左右孩子的节点,找:左子树的最大节点 or 右子树的最小节点
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
// 删除
// 1. 左为空
if (cur->_left == nullptr)
{
// 特殊处理删除 root(root 没有 parent),直接修改 _root 即可
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
// 2. 右为空
else if (cur->_right == nullptr)
{
// 特殊情况处理,直接修改 _root
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
// 3. 其他
else
{
// 找右树的最小节点代替(也可以找左树的最大节点)
Node* minRight = cur->_right;
Node* pminRight = cur; // 这里不能用nullptr初始化!!!有可能已经满足条件,下面的循环不进去
while (minRight->_left)
{
pminRight = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
if (pminRight->_left == minRight)
{
pminRight->_left = minRight->_right;
}
else
{
pminRight->_right = minRight->_right;
}
delete minRight;
}
return true;
}
}
return false;
}