目录
1.二叉搜索树概念
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
例如:

2.二叉树插入的实现
如何插入?
如果树为空,直接插入。
如果树不为空,则将要插入的值与二叉树中各结点的值比较,最后再插入
例如:
代码实现:
先创建一个结构体存储每个结点的信息:
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
非递归版本:
Insert(const T& key)
{
if (_root == nullptr)
{
_root = new Node(key);
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(key);
if (key > parent->_key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
}
递归版本:
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
bool _InsertR(const K& key)
{
return _InsertR(_root, key);
}
private:
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (key > root->_key)
{
return _InsertR(root->_right, key);
}
else if (key < root->_key)
{
return _InsertR(root->_left, key);
}
else//不允许存在相同的值
return false;
}
}
root是父亲结点的左右指针的引用,修改root也就是修改父亲结点的左右指针,
3. 二叉搜索树的查找
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _FindR(root->_right, key);
}
else if (root->_key > key)
{
return _FindR(root->_left, key);
}
else
{
return true;
}
}
4.二叉树的删除
二叉树的删除可分为两种情况。
1.要删除的结点只有一个孩子或无孩子。
2.要删除的结点有两个孩子。
例如:
第一种情况:
1.删除4;
2.删除10;
第二种情况:
1.删除3;在它的右子树中寻找中序下的第一个结点(关键码最小,也就是最左结点),用它的值填补到被删除
节点中,再来处理该结点的删除问题--替换法删除
非递归版本
bool Erase(const T& 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
{}
先找到要被删除的结点。先处理第一情况,
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
当被删除的结点有两个孩子时:
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left)
{
minParent = minRight;
minRight = minRight->_left;
}
swap(minRight->_key, cur->_key);
if (minParent->_left == minRight)
{
minParent->_left = minRight->_right;
}
else
{
minParent->_right = minRight->_right;
}
delete minRight;
递归版本:
public:
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
private:
bool _EraseR(Node*& root, const K& key)//root是父亲结点左右指针的引用
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _EraseR(root->_right, key);
}
else if (root->_key > key)
{
return _EraseR(root->_left, key);
}
else//先找到要删除的结点
{
Node* del = root;
if (root->_left == nullptr)
{
root = root->_right;
}
else if (root->_right == nullptr)
{
root = root->_left;
}
else
{
Node* minRight = root->_right;//找到被删删除结点的右孩子,minRight
while (minRight->_left)//以minRight为根,找到最左的孩子。
{
minRight = minRight->_left;
}
swap(root->_key, minRight->_key);//将被删出的结点与最左孩子值替换。
return _EraseR(root->_right, key);//此时被删除的结点在之前最左孩子的位置,它
无左孩子,转换成了第一种情况对其删除。
}
delete del;
return true;
}
}
画图分析:
完整代码:
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
private:
void DestoryTree(Node* root)
{
if (root == nullptr)
return;
DestoryTree(root->_left);
DestoryTree(root->_right);
delete root;
}
Node* CopyTree(Node* root)
{
if (root == nullptr)
return nullptr;
Node* copyNode = new Node(root->_key);
copyNode->_left = CopyTree(root->_left);
copyNode->_right = CopyTree(root->_right);
return copyNode;
}
public:
// 强制编译器自己生成构造,C++11支持
BSTree() = default;
BSTree(const BSTree<K>& t)//写了拷贝构造,不会默认生成构造函数
{
_root = CopyTree(t._root);
}
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
~BSTree()
{
DestoryTree(_root);
_root = nullptr;
}
bool _FindR(const K& key)
{
return _FindR(_root, key);
}
bool _InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool _EraseR(const K& key)
{
return _EraseR(_root, key);
}
void InOrder()
{
_InOrder(_root);
}
private:
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _EraseR(root->_right, key);
}
else if (root->_key > key)
{
return _EraseR(root->_left, key);
}
else
{
Node* del = root;
if (root->_left == nullptr)
{
root = root->_right;
}
else if (root->_right == nullptr)
{
root = root->_left;
}
else
{
Node* minRight = root->_right;
while (minRight->_left)
{
minRight = minRight->_left;
}
swap(root->_key, minRight->_key);
return _EraseR(root->_right, key);
}
delete del;
return true;
}
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (key > root->_key)
{
return _InsertR(root->_right, key);
}
else if (key < root->_key)
{
return _InsertR(root->_left, key);
}
else
return false;
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _FindR(root->_right, key);
}
else if (root->_key > key)
{
return _FindR(root->_left, key);
}
else
{
return true;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};
5.二叉搜索树的应用
5.1 K模型
K
模型即只有
key
作为关键码,结构中只需要存储
Key
即可,关键码即为需要搜索到
值
。
比如:
给一个单词
word
,判断该单词是否拼写正确
,具体方式如下:
以词库中所有单词集合中的每个单词作为
key
,构建一棵二叉搜索树
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误
5.2 KV模型
每一个关键码
key
,都有与之对应的值
Value
,即
<Key, Value>
的键值对
。
比如:
英汉词典就是英文与中文的对应关系
,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文
<word, chinese>
就构成一种键值对;
或者统计单词等的次数,若存在,则把value的值+1;
对上面代码进行改进,来运用KV模型。
下面展示需要更改的部分
template<class K, class V>
struct BSTreeNode
{
BSTreeNode<K, V>* _left;
BSTreeNode<K, V>* _right;
const K _key;
V _value;
BSTreeNode(const K& key, const V& value)
:_left(nullptr)
, _right(nullptr)
, _key(key)
, _value(value)
{}
};
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
public:
void InOrder()
{
_InOrder(_root);
cout << endl;
}
Node* FindR(const K& key)//返回结点的指针,可对结点内容进行修改
{
return _FindR(_root, key);
}
bool InsertR(const K& key, const V& value)
{
return _InsertR(_root, key, value);
}
private:
bool _InsertR(Node*& root, const K& key, const V& value)
{
if (root == nullptr)
{
root = new Node(key, value);
return true;
}
if (root->_key < key)
return _InsertR(root->_right, key, value);
else if (root->_key > key)
return _InsertR(root->_left, key, value);
else
return false;
}
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr)
return nullptr;
if (root->_key < key)
{
return _FindR(root->_right, key);
}
else if (root->_key > key)
{
return _FindR(root->_left, key);
}
else
{
return root;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_key << ":" << root->_value << endl;
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};
例如:
void test2()
{
string arr[] = { "香蕉","苹果","梨","桃子","梨","香蕉","黄瓜" };
BSTree<string, int> p;
for (auto ch : arr)
{
auto ret = p.FindR(ch);
if (ret==nullptr)
{
p.InsertR(ch, 1);
}
else
{
ret->_value++;
}
}
p.InOrder();
}
int main()
{
test2();
return 0;
}
结果:
黄瓜:1
梨:2
苹果:1
桃子:1
香蕉:2