本文主要讲一下二叉搜索树的相关操作——插入、删除和查找。
概念:二叉搜索树又称二叉排序树,它或者是一颗空树,或者是一颗具有以下性质的树。
性质:①若它的左子树不为空,则左子树上所有节点的值都小于根节点的值;
②若它的右子树不为空,则右子树上所有节点的值都大于根节点的值;
③它的左右子树也分别为二叉搜索树;
由于二叉搜索树的插入和查找操作相较于删除简单一些,因此,这里不具体进行阐述,主要针对删除进行一些具体阐述。
二叉搜索树的删除操作主要分为一下几种情况:
情况一:要删除节点为叶子节点即当前节点没有左右子节点;
解决方法:直接删除该节点。
情况二:要删除的节点只有左孩子,没有右孩子;
解决方法:将左孩子连接到双亲节点上,如图:
情况三:要删除的节点只有右孩子,没有左孩子;
解决方法:将右孩子连接到双亲节点上,如图:
情况四:要删除的节点左右孩子都存在;
解决方法:找到要删除节点的右子树中按中序遍历的第一个节点,将其与删除节点交换,再删除该节点(也就是用中序遍历找到的第一个节点代替删除节点)。如图:
插入、删除和查找的代码有两种实现方式:递归和非递归。
我主要说一下在写 非递归版本删除操作的思路和一些注意事项:
思路:
第一步:先找到要删除的节点的位置;
第二步:再判断要删除的节点情况属于上面所列出的情况中的哪一种(情况一可以划分到情况二三中);
注意:如果删除情况属于二三,还需要判断要删除的节点是否为根节点;若不是根节点还要判断删除节点是双亲节点的左孩子还是右孩子;
注意:如果属于情况三,需要注意的是,删除节点右子树经过中序遍历的第一个节点不一定是其双亲节点的左节点,这点尤为重要,画个图解释一下:
再说一下二叉搜索树性能分析:
当二叉搜索树为完全二叉树结构时,其时间复杂度为O(lg N);
当二叉搜索树是一支单支退化二叉搜索树时,其时间复杂度为O(N);
如图:它就像一支单链表
因此,因此最坏情况下,二叉排序树的平均查找长度为O(n),一般情况下平均查找长度为O(lgN)。
源代码:(含递归和非递归版本)
#include<iostream>
#include<queue>
#include<utility>
using namespace std;
template<class T>
struct SearchBinaryTreeNode
{
T _data;
SearchBinaryTreeNode<T> *_left;
SearchBinaryTreeNode<T> *_right;
SearchBinaryTreeNode(const T& data)
:_data(data)
, _left(NULL)
, _right(NULL)
{}
};
template<class T>
class SearchBinaryTree
{
typedef SearchBinaryTreeNode<T> Node;
public:
SearchBinaryTree()
:_root(NULL)
{}
SearchBinaryTree(const T* arr,size_t size,const T& invalid)
{
size_t index = 0;
_root=CreateTree(arr,size,invalid,index);
}
//前序创建
Node* CreateTree(const T* arr, size_t size, const T& invalid, size_t& index)
{
Node* root = NULL;
if (index < size)
{
if (arr[index] != invalid)
{
root = new Node(arr[index]);
root->_left = CreateTree(arr,size,invalid,++index);
root->_right = CreateTree(arr,size,invalid,++index);
}
}
return root;
}
SearchBinaryTree(const SearchBinaryTree<T>& tree)
{
return _CopyTree(tree._root);
}
Node* _CopyTree(Node* root)
{
if (NULL == root)
return NULL;
Node* NewNode = root;
root->_left = _CopyTree(root->_left);
root->_right = _CopyTree(root->_right);
return NewNode;
}
~SearchBinaryTree()
{
Destory(_root);
_root = NULL;
}
void Destory(Node* root)
{
if (NULL == root)
return;
Destory(root->_left);
Destory(root->_right);
delete root;
}
SearchBinaryTree& operator=(SearchBinaryTree<T> tree)
{
swap(_root,tree._root);
return *this;
}
//遍历
void PrevOrder()
{
_PrevOrder(_root);
cout << endl;
}
void _PrevOrder(Node* root)
{
if (root == NULL)
return;
cout << root->_data << " ";
_PrevOrder(root->_left);
_PrevOrder(root->_right);
}
public:
bool Insert(const T& data)
{
if (_root == NULL)
_root = new Node(data);
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//找到插入位置
if (data < parent->_data)
parent->_left = new Node(data);
else
parent->_right = new Node(data);
return true;
}
bool Delete(const T& data)
{
if (NULL == _root)
return false;
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
//左为空或左右都为空
if (cur->_left == NULL)
{
if (parent == NULL)//是否为根节点
{
_root = _root->_right;
}
else//不是根节点
{
//判断节点在父节点的左/右
if (cur == parent->_left)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
delete cur;
}
//右为空或左右都为空
else if (cur->_right == NULL)
{
if (parent == NULL)//判断是否为根节点
{
_root = _root->_left;
}
else
{
//判断删除节点是父节点的左/右
if (cur == parent->_left)
parent->_left = cur->_left;
else
parent->_right = cur->_right;
}
delete cur;
}
else//删除节点的左右节点不为空
{
Node* tmp = cur->_right;
parent = cur;
while (tmp->_left)//找到右子树的最左节点
{
parent = tmp;
tmp = tmp->_left;
}
if (tmp == parent->_left)
{
swap(cur->_data, tmp->_data);
parent->_left = tmp->_right;
}
else
{
swap(cur->_data,tmp->_data);
parent->_right = tmp->_right;
}
delete tmp;
}
return true;
}
}
return false;
}
Node* Find(const T& data)
{
if (NULL == _root)
return NULL;
while (_root)
{
if (data < _root->_data)
_root = _root->_left;
else if (data > _root->_data)
_root = _root->_right;
else
return _root;
}
return NULL;
}
递归版本
public:
void _Insert_R(const T& data)
{
Insert_R(_root,data);
}
void _Remove_R(const T& data)
{
Remove_R(_root,data);
}
void _Find_R(const T& data)
{
Find_R(_root, data);
}
protected:
bool Insert_R(Node*& root, const T& data)
{
if (NULL == root)
{
root = new Node(data);
return true;
}
if (data < root->_data)
{
return Insert_R(root->_left, data);
}
else if (data > root->_data)
{
return Insert_R(root->_right, data);
}
else
{
return false;
}
}
bool Remove_R(Node*& root, const T& data)
{
if (root == NULL)
return false;
if (data < root->_data)
return Remove_R(root->_left, data);
else if (data > root->_data)
return Remove_R(root->_right, data);
else
{
if (root->_left == NULL)
root = root->_right;
else if (root->_right == NULL)
root = root->_left;
else
{
Node* tmp = root->_right;
Node* parent = root;
while (tmp->_left)
{
parent = tmp;
tmp = tmp->_left;
}
if (tmp == parent->_left)
{
swap(tmp->_data, root->_data);
parent->_left = tmp->_right;
}
else
{
swap(tmp->_data, root->_data);
parent->_right = tmp->_right;
}
delete tmp;
return true;
}
}
}
Node* Find_R(Node* root, const T& data)
{
if (NULL == root)
return NULL;
if (data < root->_data)
return Find_R(root->_left, data);
else if (data > root->_data)
return Find_R(root->_right,data);
else
{
return root;
}
}
protected:
Node* _root;
};
文中若有不当之处,请大家随时指正,感谢。