二叉搜索树又称二叉排序树(Binary Search Tree),简称BST。主要用于查找搜索。
如果理解起来有些抽象,可以尝试这个网站,可视化演示操作过程:visualgo
定义
二叉搜索树或者为空树或者满足如下条件:
- 若左子树非空,左子树全部节点小于根节点
- 若右子树非空,右子树全部节点大于根节点
- 左右子树均满足以上两点(递归定义的)
二叉搜索树是没有重复元素的。
优势在于查找和插入,时间复杂度可以达到O(logn)。
如上图即为一颗BST树。
查找
如图为查找50的过程
从根节点开始,若节点为NULL,否则比较根节点与搜索值的大小关系,如果相等则查找成功,如果小于根节点值则转到左子树上继续查找,同理若大于节点值则转到右节点上继续查找。
BSTNode *BSTNode::findNode(int val)
{
if (val == value)
return this;
else if (val < value)
{
if (left == NULL)
return NULL;
return left->findNode(val);
}
else if (val > value)
{
if (right == NULL)
return NULL;
return right->findNode(val);
}
return NULL;
}
插入
如图为插入8的过程:
插入的关键是找到插入的位置, 可以在查找的基础上改装成插入,即若查找成功代表插入值已存在于BST中无需再次插入,查找失败(找到了NULL),则该位置即为需要插入的位置。
void BSTNode::insertNode(int val)
{
if (val < value)
{
if (left == NULL)
{
left = new BSTNode(val);
left->parent = this;
}
else
left->insertNode(val);
}
else if (val > value)
{
if (right == NULL)
{
right = new BSTNode(val);
right->parent = this;
}
else
right->insertNode(val);
}
}
删除
首先定义两个概念:
前驱结点:节点val值小于该节点val值并且值最大的节点
后继节点:节点val值大于该节点val值并且值最小的节点
相比较而言删除操作较为复杂,需要考虑多种情况:
假设待删除节点为d
- 若d为叶节点,则直接删除即可。
- 若节点只有左子树,则将左子树改为d父节点的子树。(右节点同理)
- 若d有两棵子树,则让d的后继(或者前驱)节点x取代d的位置,并将原位置的x删除掉(此时会转换成1或2的情况)
由于前两者情况较为简单,这里演示第三种情况:
删除如图BST中值为7的节点:
首先查找到6:
然后发现6的左右子树均非空,这里选择右子树,查找到后继节点8
用8替代7的位置
由于8节点为叶节点,因此直接删除。
void BSTNode::delNode()
{
if (left != NULL && right != NULL)
{
BSTNode *temp = left->findMax();
value = temp->value;
temp->delNode();
}
else
{
if (left == NULL)
{
if (this == parent->left)
{
parent->left = right;
}
else
{
parent->right = right;
}
if (right != NULL)
{
right->parent = parent;
}
}
else
{
if (this == parent->left)
{
parent->left = left;
}
else
{
parent->right = left;
}
left->parent = parent;
}
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
class BSTNode
{
public:
int value;
BSTNode *left;
BSTNode *right;
BSTNode *parent;
public:
BSTNode(int val);
BSTNode *findNode(int val);
void insertNode(int val);
void delNode();
BSTNode *findMin();
BSTNode *findMax();
};
BSTNode *BSTNode::findMin()
{
BSTNode *tmp = this;
while (tmp->left != NULL)
tmp = tmp->left;
return tmp;
}
BSTNode *BSTNode::findMax()
{
BSTNode *tmp = this;
while (tmp->right != NULL)
tmp = tmp->right;
return tmp;
}
void BSTNode::delNode()
{
if (left != NULL && right != NULL)
{
BSTNode *temp = left->findMax();
value = temp->value;
temp->delNode();
}
else
{
if (left == NULL)
{
if (this == parent->left)
{
parent->left = right;
}
else
{
parent->right = right;
}
if (right != NULL)
{
right->parent = parent;
}
}
else
{
if (this == parent->left)
{
parent->left = left;
}
else
{
parent->right = left;
}
left->parent = parent;
}
}
}
BSTNode::BSTNode(int val)
{
value = val;
left = right = parent = NULL;
}
BSTNode *BSTNode::findNode(int val)
{
if (val == value)
return this;
else if (val < value)
{
if (left == NULL)
return NULL;
return left->findNode(val);
}
else if (val > value)
{
if (right == NULL)
return NULL;
return right->findNode(val);
}
return NULL;
}
void BSTNode::insertNode(int val)
{
if (val < value)
{
if (left == NULL)
{
left = new BSTNode(val);
left->parent = this;
}
else
left->insertNode(val);
}
else if (val > value)
{
if (right == NULL)
{
right = new BSTNode(val);
right->parent = this;
}
else
right->insertNode(val);
}
}
/**
* @brief
*
*/
class BST
{
public:
BST();
BST(vector<int> v);
BSTNode *find(int val);
BSTNode *root;
bool del(int val);
void insert(int val);
};
BST::BST()
{
root = NULL;
}
BST::BST(vector<int> v)
{
root = NULL;
for (int i = 0; i < v.size(); i++)
{
root->insertNode(v[i]);
}
}
BSTNode *BST::find(int val)
{
if (root == NULL)
return NULL;
else
return root->findNode(val);
}
void BST::insert(int val)
{
if (root == NULL)
root = new BSTNode(val);
else
{
root->insertNode(val);
}
}
bool BST::del(int val)
{
BSTNode *findNode = find(val);
if (findNode == NULL)
return false;
if (findNode == root)
{
if (root->left == NULL && root->right == NULL)
{
root = NULL;
delete findNode;
}
else if (root->left == NULL)
{
root = root->right;
root->parent = NULL;
delete findNode;
}
else if (root->right == NULL)
{
root = root->left;
root->parent = NULL;
delete findNode;
}
else
{
root->delNode();
}
}
else
{
root->delNode();
}
return true;
}
创建
创建就是按顺序的插入过程