二叉树搜索树
二叉搜索树,同时也称为二叉排序树。它可以为一个空树,或者满足二叉搜索树的性质
- 如果左子树不为空时,左子树的值小于双亲结点
- 如果右子树不为空时,右子树的值大于双亲结点
- 同时,它的左右子树也满足二叉搜索树的性质
当对二叉搜索树进行中序遍历时,会得到有序序列,所以又被称为二叉排序树
例如对上图的树进行中序遍历时会产生:【0 1 2 3 4 5 6 7 8 9】
二叉搜索树的操作
- 树的结构
按照模板将树的结构给出
template<class T>
struct BSNode
{
BSNode(const T&_data = T()) //构造函数,如果用户没有给参数,则调用默认参数
:left(nullptr)
,right(nullptr)
,data(_data)
{
}
BSNode<T>* left;
BSNode<T>* right;
T data;
};
- 查找
根据二叉搜索树的性质,左子树的值比根结点的值小,右子树的值比根结点的值大,进行查找。
Node* Find(const T& _data)
{
Node* cur = root;
while (cur)
{
if (cur->data < _data)
cur = cur->right;
else if (cur->data > _data)
cur = cur->left;
else if (cur->data == _data)
return cur;
}
return nullptr;
}
- 插入 bool Insert(const T&_data)
i.先判断二叉搜索树是不是空树,如果是空树直接插入
if(root == nullptr)
{
root = BSNode(_data);
return true;
}
ii.如果树不为空,则判断要把数值插入的位置
Node *cur = root; //从根结点开始找要插入的位置
Node *parent = nullptr; // 用来保存要插入位置的双亲结点
while(cur)
{
parent = cur; //将双亲结点指向cur
if (cur->data < _data) // 用cur 开始往下查找
cur = cur->right;
else if (cur->data > _data)
cur = cur->left;
else
return false;
}
iii.找到结点,插入操作
cur = new Node(_data);
if (_data < parent->data) // 用双亲结点来判断,要插入的结点,应给插入到双亲的哪边
parent->left = cur;
else
parent->right = cur;
return true;
代码:
bool Insert(const T&_data) //将一个元素插入
{
if (root == nullptr)
{
root = new Node(_data);
return true;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (cur->data < _data)
cur = cur->right;
else if (cur->data > _data)
cur = cur->left;
else
return false;
}
cur = new Node(_data);
if (_data < parent->data)
parent->left = cur;
else
parent->right = cur;
return true;
}
- 删除 bool Delete(const T& _data)
i.先判断删除的数值在二叉树中,如果不存在,则返回, 否则要删除的结点可能分下面三种情况
a. 待删除结点只有左孩子
b.待删除结点只有右孩子
c.待删除结点左右孩子都存在
在a类情况和b类情况中需要加一个特判(待删除结点为根结点)
bool Delete(const T& _data)
{
if (root == nullptr) //结点为空
{
return false;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
if (_data == cur->data)
break;
else if (cur->data < _data)
{
parent = cur;
cur = cur->right;
}
else
{
parent = cur;
cur = cur->left;
}
}
if (cur == nullptr) //未找到
return false;
//1、只有左孩子
if (cur->right == nullptr)
{
if (cur == root)
root = cur->left;
else
{
if (cur == parent->left)
{
parent->left = cur->left;
}
else
{
parent->right = 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;
}
}
}
//左右子树都存在
/*找一个替换的结点:在左子树找最大值,或者在右子树中找最大值,进行替换
*/
else
{
if (cur->left != nullptr || cur->right != nullptr)
{
//在右子树中找最小值进行替换
Node *replace = cur->right;
parent = cur;
while (replace->left)//在右子树中最左边的结点值最小
{
parent = replace;
replace = replace->left;
}
cur->data = replace->data; //将要删除的结点与右子树中最小结点的值进行替换
if (replace == parent->left)
{
parent->left = replace->right;
}
else
{
parent->right = replace->right;
}
delete replace;
replace = nullptr;
}
return true;
}
return false;
}
完整代码
template<class T>
struct BSNode
{
BSNode(const T&_data = T())
:left(nullptr)
,right(nullptr)
,data(_data)
{
}
BSNode<T>* left;
BSNode<T>* right;
T data;
};
template<class T>
class BSTree
{
typedef BSNode<T> Node;
public:
BSTree()
:root(nullptr)
{
}
~BSTree()
{
Destory(root);
}
BSTree(const BSTree<T>& t)
{
root = copy(t);
}
Node *copy(BSTree* t)
{
if (t.root == nullptr)
return nullptr;
Node *temp = new Node;
temp->data = t->root;
temp->left = copy(t->left);
temp->right = copy(t->right);
return temp;
}
bool Insert(const T&_data) //将一个元素插入
{
if (root == nullptr)
{
root = new Node(_data);
return true;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (cur->data < _data)
cur = cur->right;
else if (cur->data > _data)
cur = cur->left;
else
return false;
}
cur = new Node(_data);
if (_data < parent->data)
parent->left = cur;
else
parent->right = cur;
return true;
}
Node* Find(const T& _data)
{
Node* cur = root;
while (cur)
{
if (cur->data < _data)
cur = cur->right;
else if (cur->data > _data)
cur = cur->left;
else if (cur->data == _data)
return cur;
}
return nullptr;
}
bool Delete(const T& _data)
{
if (root == nullptr) //结点为空
{
return false;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
if (_data == cur->data)
break;
else if (cur->data < _data)
{
parent = cur;
cur = cur->right;
}
else
{
parent = cur;
cur = cur->left;
}
}
if (cur == nullptr) //未找到
return false;
//1、只有左孩子
if (cur->right == nullptr)
{
if (cur == root)
root = cur->left;
else
{
if (cur == parent->left)
{
parent->left = cur->left;
}
else
{
parent->right = 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;
}
}
}
//左右子树都存在
/*找一个替换的结点:在左子树找最大值,或者在右子树中找最小值,进行替换
*/
else
{
if (cur->left != nullptr || cur->right != nullptr)
{
//在右子树中找最小值进行替换
Node *replace = cur->right;
parent = cur;
while (replace->left)//在右子树中最左边的结点值最小
{
parent = replace;
replace = replace->left;
}
cur->data = replace->data; //将要删除的结点与右子树中最小结点的值进行替换
if (replace == parent->left)
{
parent->left = replace->right;
}
else
{
parent->right = replace->right;
}
delete replace;
replace = nullptr;
}
return true;
}
return false;
}
private:
void Destory(Node*& root)
{
if (root)
{
Destory(root->left);
Destory(root->right);
root = nullptr;
}
}
Node *root;
};
性能分析:
每次插入或删除结点时都必须进行查找,所以查找的效率决定删除或者插入的效率,最坏情况下,当二叉搜索树为一个单支,其搜索的时间复杂度为O(n)