目录
1、二叉搜索树
二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树,其中每个节点的值大于其左子树中所有节点的值,小于其右子树中所有节点的值。这种特性使得二叉搜索树具有快速的查找、插入和删除操作。
二叉搜索树的性质包括:
- 左子树中所有节点的值小于根节点的值;
- 右子树中所有节点的值大于根节点的值;
- 左右子树也分别为二叉搜索树。
如下图所示:
2、二叉搜索树的相关操作。
1、查找
a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
b、最多查找高度次,走到到空,还没找到,这个值不存在。
2、插入
a. 树为空,则直接新增节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
3、删除
删除操作也是最值得思考的操作,因为有四种情况
a. 要删除的结点无孩子结点
这是最简单的情况,直接删除节点就好,并且将该节点的父节点对应的指针置为nullptr
b. 要删除的结点只有左孩子结点
如果为根节点,那么直接让该节点的左孩子变为根节点即可。
如果不为根节点,那么需要判断该节点是prev(该节点的父节点)的左孩子还是右孩子,让对应的指针指向该节点的左孩子即可。
c.
要删除的结点只有右孩子结点
如果为根节点,同上操作,只是变为对该节点右孩子的操作不为根节点,判断该节点是prev(该节点的父节点)的左孩子还是右孩子,让对应的指针指向该节点的右孩子即可。
d.
要删除的结点有左、右孩子结点
如果该节点有左孩子和右孩子,那么如何操作才能在不破坏二叉搜索树结构的情况下完成删除呢?我们需要找到该节点的 最小右孩子来替换该节点,这样就可以解决问题。最小右孩子:最小右孩子分为两种情况:1.当前节点的右孩子节点的最小左孩子。2.若是当前节点的右孩子节点没有最小左孩子,那么当前节点的右孩子节点就是最小右孩子。下面是一段代码 实现,cur就是 当前要删除的节点,我们将它设为初始的最小右孩子的父节点,然后while循环查找最小左孩子,最后判断最小右孩子是该父节点的左右指针,将对应指针指向RightMin->_right;
Node* RightMinParent = cur;
Node* RightMin = cur->_right;
while (RightMin->_left)
{
RightMinParent = RightMin;
RightMin = RightMin->_left;
}
cur->_key = RightMin->_key;
if (RightMin == RightMinParent->_left)
{
RightMinParent->_left = RightMin->_right;
}
else
{
RightMinParent->_right = RightMin->_right;
}
delete RightMin;
return true;
3、代码实现(非递归)
二叉搜索树的实现:
1.
K
模型:
K
模型即只有
key
作为关键码,结构中只需要存储
Key
即可,关键码即为需要搜索到
的值
。
比如:
给一个单词
word
,判断该单词是否拼写正确
,具体方式如下:
以词库中所有单词集合中的每个单词作为
key
,构建一棵二叉搜索树
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
2.
KV
模型:每一个关键码
key
,都有与之对应的值
Value
,即
<Key, Value>
的键值对
。该种方
式在现实生活中非常常见:
比如
英汉词典就是英文与中文的对应关系
,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>
就构成一种键值对;
再比如
统计单词次数
,统计成功后,给定单词就可快速找到其出现的次数,
单词与其出
现次数就是
<word, count>
就构成一种键值对
#pragma once
namespace key_value
{
template<class K, class V>
struct BSTreeNode
{
typedef BSTreeNode<K, V> Node;
Node* _left;
Node* _right;
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:
bool Insert(const K& key, const V& value)
{
if (_root == nullptr)
{
_root = new Node(key, value);
return true;
}
Node* prev = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
prev = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
prev = cur;
cur = cur->_right;
}
else
{
return false;
}
}
Node* newnode = new Node(key,value);
if (prev->_key > key)
{
prev->_left = newnode;
}
else if (prev->_key < key)
{
prev->_right = newnode;
}
return true;
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
cur = cur->_left;
}
else if (cur->_key < key)
{
cur = cur->_right;
}
else
{
return cur;
}
}
}
bool Erase(const K& key)
{
Node* prev = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
prev = cur;
cur = cur->_left;
}
else if(cur->_key<key)
{
prev = cur;
cur = cur->_right;
}
else
{
if (cur->_left == nullptr)
{
if (cur == _root)
{
cur = cur->_right;
}
else
{
if (cur == prev->_left)
{
prev->_left = cur->_right;
}
else
{
prev->_right = cur->_right;
}
}
delete cur;
return true;
}
else if (cur->_right == nullptr)
{
if (cur == _root)
{
cur = cur->_left;
}
else
{
if (cur == prev->_left)
{
prev->_left = cur->_left;
}
else
{
prev->_right = cur->_left;
}
}
delete cur;
return true;
}
else
{
Node* RightMinParent = cur;
Node* RightMin = cur->_right;
while (RightMin->_left)
{
RightMinParent = RightMin;
RightMin = RightMin->_left;
}
cur->_key = RightMin->_key;
if (RightMin == RightMinParent->_left)
{
RightMinParent->_left = RightMin->_right;
}
else
{
RightMinParent->_right = RightMin->_right;
}
delete RightMin;
return true;
}
}
}
return false;
}
void Inoder()
{
inoderprint(_root);
cout << endl;
}
void inoderprint( Node* root)
{
if (root == nullptr)
{
return;
}
inoderprint(root->_left);
cout << root->_key << " " << root->_value << endl;
inoderprint(root->_right);
}
private:
Node* _root = nullptr;
};
}
以上实现是 KV模型:
可以使用以下代码测试功能:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include"BSTree.h"
int main()
{
key_value::BSTree<string, int> BST;
BST.Insert("苹果",12);
BST.Insert("梨",10);
BST.Insert("草莓",9);
BST.Insert("橘子",11);
BST.Inoder();
BST.Erase("梨");
BST.Inoder();
key_value::BSTreeNode<string,int> *node=BST.Find("苹果");
cout << node->_key << " " << node->_value << endl;
return 0;
}