概念及其性质
二叉搜索树,又名二叉排序树,二叉查找树
二叉搜索树有一下特点:
(1)若左子树不为空,则左子树的所有节点均小于根节点
(2)若右子树不为空,则右子树的所有节点均大于根节点
(3)左右子树也是二叉搜索树
(4)每棵树都有自己的key值,而且不能重复
如何定义二叉搜索树
//二叉搜索树的节点,Key-Value结构
template<typename K,typename V>
struct ResearchBinaryTreeNode
{
ResearchBinaryTreeNode<K, V>* _left;
ResearchBinaryTreeNode<K, V>* _right;
K _key;
V _value;
ResearchBinaryTreeNode(const K& key,const V& value);
};
//定义二叉搜索树
template<typename K,typename V>
class ResearchBinaryTree
{
typedef ResearchBinaryTreeNode<K,V> Node;
public:
ResearchBinaryTree();//构造函数
~ResearchBinaryTree();//析构函数
bool Insert(const K& key,const V& value);//插入
Node* Find(const K& key);//查找
bool Remove(const K& key);//删除
void InOrder();//中序遍历
Node* FindR(const K& key);//递归形式查找
bool InsertR(const K& key, const V& value);//递归形式插入
bool RemoveR(const K&key);//递归形式删除
protected:
Node* _root;
};
二叉搜索树的查找
二叉搜索树的查找,就是从根节点开始,进行key值的比较
若相同,则查询到;若大于查找的key值,则走左孩子;小于的话走右孩子;如果为空,则没找到
非递归实现
Node* Find(const K& key)
{
Node* cur = _root;
//根据搜索二叉树的特点来进行查找
while (cur)
{
if (key < cur->_key)
cur = cur->_left;
else if (key>cur->_key)
cur = cur->_right;
else
return cur;
}
return NULL;
}
递归实现
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
Node* _FindR(Node* root, const K& key)
{
if (root == NULL)
return NULL;
if (key < root->_key)
return _FindR(root->_left, key);
else if (key>root->_key)
return _FindR(root->_right, key);
else
return root;
}
二叉搜索树的插入
非递归实现
bool Insert(const K& key,const V& value)
{
if (_root == NULL)
{
_root = new Node(key,value);
return true;
}
Node* cur = _root;
Node* parent = cur;
//找到需要插入节点的父亲节点
while (cur)
{
parent = cur;
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key>key)
cur = cur->_left;
else
return false;
}
//parent为需要插入节点的父亲节点
if (parent->_key > key)
parent->_left = new Node(key,value);
else if (parent->_key<key)
parent->_right = new Node(key,value);
return true;
}
递归实现
bool InsertR(const K& key, const V& value)
{
return _InsertR(_root, key, value);
}
bool _InsertR(Node*& root, const K& key, const V& value)
{
//构建新节点
if (root == NULL)
{
root = new Node(key, value);
return true;
}
if (key < root->_key)
return _InsertR(root->_left, key, value);
else if (key > root->_key)
return _InsertR(root->_right, key, value);
else
return false;
}
二叉搜索树的删除
二叉搜索树稍微复杂一点的地方就是删除部分,在删除一个节点的时候,有四种情况
(1)删除节点的左子树为空 如删除节点6
(2)删除节点的右子树为空 如删除节点9
(3)删除节点的左子树和右子树都为空 如删除节点2
(4)删除节点的左子树和右子树都不为空 如删除节点7
由于当删除节点的左子树和右子树都为空时,左子树和右子树都为空,满足左子树为空(或右子树为空)的条件,因为我们可以将这种情况划分到左子树为空的情况中
因此,三种情况的处理结果如下:
(1)若左子树为空,就让父亲节点指向删除节点的右子树;比如删除6,就让7指向6的右子树
(2)若右子树为空,就让父亲节点指向删除节点的左子树;比如删除3,就让5指向3的左子树
(3)若都不为空,则用替换法进行删除;比如删除7,就找7的右子树(9)的最左节点8,将8放到7的位置,然后删除原来的8
非递归实现
bool Remove(const K& key)
{
Node* cur = _root;
Node* parent = NULL;
Node* delNode = NULL;
//找出要删除的节点以及其父亲节点
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key >cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
break;
}
}
if (cur == NULL)
return false;
//如果删除的是根节点,那么parent的值为NULL
//cur此时是要删除的节点
if (cur->_left == NULL)
{
delNode = cur;
//cur是父亲节点的左孩子的话,就把cur的右孩子赋给父亲节点的左孩子
//否则,将cur的右孩子赋给父亲节点的右孩子
if (parent == NULL)
_root = cur->_right;
else if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
else if (cur->_right == NULL)
{
delNode = cur;
//cur是父亲节点的左孩子的话,就把cur的右孩子赋给父亲节点的左孩子
//否则,将cur的右孩子赋给父亲节点的右孩子
if (parent == NULL)
_root = cur->_left;
else if(parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
else
{
//都不为空的情况,需要采用替换法来解决
Node* subLeft = NULL;//定义右子树的最左节点
//循环找到右子树的最左节点
//这里subLeft不可能为空
subLeft = cur->_right;
parent = cur;
while (subLeft->_left)
{
parent = subLeft;
subLeft = subLeft->_left;
}
cur->_key = subLeft->_key;
if (parent->_left == subLeft)
parent->_left = subLeft->_right;
else
parent->_right = subLeft->_right;
delNode = subLeft;
}
delete delNode;
delNode = NULL;
return true;
}
递归实现
bool RemoveR(const K&key)
{
return _RemoveR(_root, key);
}
bool _RemoveR(Node* root,const K& key)
{
if (root == NULL)
return false;
//递归,找到要删除的节点
if (root->_key < key)
return _RemoveR(root->_right, key);
else if (root->_key > key)
return _RemoveR(root->_left, key);
else
{
Node* delNode = root;
//删除节点的左为空
if (root->_left == NULL)
root = root->_right;
else if (root->_right == NULL)
root = root->_left;
else//左右都不为空的情况
{
Node* parent = root;
Node* subLeft = root->_right;
while (subLeft->_left)
{
parent = subLeft;
subLeft = subLeft->_left;
}
delNode = subLeft;
//若为左子树,代表走了while循环,否则没有走循环
//要删除的节点是subLeft
root->_key = subLeft->_key;
if (parent->_left == subLeft)
parent->_left = subLeft->_right;
else
parent->_right = subLeft->_right;
delete delNode;
return true;
}
}
}