定义
概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
int a [] = {5,3,4,1,7,8,2,6,0,9};的二叉搜索树
常见操作
查找
- 如果key比他的父节点比他小,他的左子树指向parent,key比他的父节点比他大,他的左子树指向parent,
2,其他情况返回null
删除
删除要包括以下情况:
- 如果根节点为空直接返回false
- 先找到与要删除值相等的节点,然后分成以下情况:
(1)、删除的节点左为空,但是右边不为空
(2)、删除的节点右子树为空,但是左子树边不为空
(3)、删除的节点右子树,左子树都不为空
这里我们用替代法删除
(2)
(3)
插入
插入过程如下:
- 如果根节点为空直接插入的根节点
- 如果有重复的直接返回
- 如果以上情况不符合就找到节点为空的情况并保留他的父节点,比父节点大就插入到右边,比父节点小就插入到左边
遍历
- 依次遍历左子树,右子树,直到为空就返回。
实现
k版本
代码如下:
template<class k>
struct tree {
k _key;
struct tree<k>* _left;
struct tree<k>* _right;
tree(const k&k):_key(k)
,_left(nullptr),
_right(nullptr) {
}
};//二叉数结构体
template<class k>
class SStree {
typedef struct tree<k> Node;//二叉树节点
public:
bool Insert(const k& k) {
if (root == nullptr) {
root = new Node(k);
return true;
}
Node* parent = nullptr;
Node* cur = root;
while (cur) {
if (cur->_key > k) {
parent = cur;
cur = cur->_left;
}
else if (cur->_key < k) {
parent = cur;
cur = cur->_right;
}
else if (cur->_key == k) {
return false;
}
}
Node* node = new Node(k);
if (k > parent->_key) {
parent->_right = node;
}
else {
parent->_left = node;
}
return true;
}
Node* find(const k& k)const {
Node* _root = root;
while (_root) {
if (_root->_key > k) {
_root = _root->_left;
}
else if (_root->_key < k) {
_root = _root->_right;
}
else {
return _root;
}
}
return nullptr;
}
void indof(Node* _root) {
if (_root == nullptr) {
return;
}
indof(_root->_left);
cout << _root->_key;
indof(_root->_right);
}
void Indof() {
indof(root);
cout << endl;
}
bool erase(const k& k) {
if (root == nullptr) {
return false;
}
Node* cur = root;
Node* parent = nullptr;
while (cur) {
if (cur->_key > k) {
parent = cur->_left;
cur = cur->_left;
}
else if (cur->_key < k) {
parent = cur;
cur = cur->_right;
}
else {
//准备删除
//佐为空
//右为空
//左右都为空
if (cur->_left == nullptr) {
//根节点的左为空
if (root == cur) {
root = cur->_right;
}
else {
if (cur == parent->_left) {
parent->_left = cur->_right;
}
else if (cur == parent->_right) {
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr) {
if (root == cur) {
root = cur->_left;
}
else {
if (cur == parent->_left) {
parent->_left = cur->_left;
}
else if (cur == parent->_right) {
parent->_right = cur->_left;
}
}
delete cur;
}
else {
//替代法删除
//找右数的最左节点
//找左数的最右节点
//要注意右子树的根可能就是最小节点
Node* submin = cur->_right;
Node* parentmin = cur;
while (submin) {
parentmin = submin;
submin->_left;
}
if (parentmin->_left == submin) {
parentmin->_left = submin->_right;
}
else {
parentmin->_right = submin->_right;
}
delete submin;
}
}
return false;
}
}
private:
Node* root = nullptr;
};
应用
- K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:以单词集合中的每个单词作为key,构建一棵二叉搜索树在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
- KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word,
chinese>就构成一种键值对;再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word,
count>就构成一种键值对。比如:实现一个简单的英汉词典dict,可以通过英文找到与其对应的中文,具体实现方式如下:<单词,中文含义>为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较Key查询英文单词时,只需给出英文单词,就可快速找到与其对应的key
性能分析
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。 对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的 深度的函数,即结点越深,则比较次数越多。 但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树: