要模拟实现搜索二叉树,必须了解他的性质:
搜索二叉树的性质:
1,每个节点都有一个用于搜索的关键码,每个节点的关键码都不一样;
2,一个节点的左子树上所有的关键码总是小于它,而右子树的关键总是大于它;
3,每一个子树都是一个搜索二叉树;
这里简单来模拟实现一下搜索二叉树(递归和非递归):
插入:
当插入一个节点时,你会发现新插入节点不会影响原先树的结构,所以不用调整,这是简单之处。
bool _Insert(const K& x)
{
if (_root == NULL)
{
_root = new Node(x);
}
else
{
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (cur->_key > x)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
if (parent->_key > x)
{
parent->_left = new Node(x);
}
else
{
parent->_right = new Node(x);
}
}
return true;
}
删除:
先遍历搜索树找到删除节点,下面主要分三种情况:
1,删除节点无左子树;
2,删除节点无右子树;
3,左右子树都有。
对于1,2两种情况,如果该节点是根节点时,只需将他仅有的那个孩子的根节点设为新的根节点即可,如果不是根节点,删除这个节点,还需将父节点与他的子树连接在一起,这种情况下,你就得判断自己是父节点的左孩子还是右孩子。而对于3这种情况,你需找一个新的节点来替代它,这里删这个节点不是真的删他自己,而是删了一个替代节点,替代节点有两个选择:左子树的最右节点(左子树最大值),右子树的最左节点(右子树最小值),找到替代节点,将他的关键码赋给待删除节点,然后删除它即可,但这里还有一个关键得注意(这里替代节点取右子树最左节点为例),这个最左节点的父节点可能是根节点,也可能不是,这里影响后面的连接。
bool _Remove(const K& x)
{
if (_root == NULL)
return false;
Node* del = _root;
Node* parent = del;
while (del)
{
if (del->_key == x) //被删除的节点找到(左为空,右为空,左右均不为空)
{
Node* cur = del;
if (cur->_left == NULL) //删除节点无左子树
{
if (cur == _root)
_root = _root->_right;
else
{
if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
}
else if (cur->_right == NULL) //删除节点无右子树
{
if (cur == _root)
_root = _root->_left;
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
}
else //左右子树都有
{
cur = cur->_right;
while (cur->_left)
{
parent = cur;
cur = cur->_left;
}
del->_key = cur->_key;
del = cur;
if (cur == parent->_left) //注意,此时的cur是最左节点
parent->_left = cur->_right;
else //此时的cur为根节点的右子树的根节点,parent为根节点
parent->_right = cur->_right;
}
delete del;
del = NULL;
return true;
}
else if (del->_key > x)
{
parent = del;
del = del->_left;
}
else
{
parent = del;
del = del->_right;
}
}
return false;
}
bool _RemoveR(const K& x, Node* & root)
{
if (root == NULL)
return false;
if (root->_key > x)
_RemoveR(x, root->_left);
else if (root->_key < x)
_RemoveR(x, root->_right);
else //找到删除的位置
{
Node* del = root;
if (root->_left == NULL)
{
root = root->_right;
}
else if (root->_right == NULL)
{
root = root->_left;
}
else
{
Node* parent = root->_right;
Node* rootL = root->_right;
while (rootL->_left)
{
parent = rootL;
rootL = rootL->_left;
}
root->_key = rootL->_key;
del = rootL;
if (parent->_left == rootL)
parent->_left = rootL->_right;
else
parent->_right = rootL->_right;
}
delete del;
del = NULL;
return true;
}
}
查找:
Node* _Find(Node* root, const K& x)
{
while (root)
{
if (x > root->_key)
root = root->_right;
else if (x < root->_key)
root = root->_left;
else
return root;
}
return NULL;
}
Node* _FindR(Node* root, const K& x)
{
if (x > root->_key)
return _FindR(root->_right, x);
else if (x < root->_key)
return _FindR(root->_left, x);
else
{
return root;
}
return NULL;
}
下面是完整代码:
#include<iostream>
using namespace std;
template<class K>
struct SearchBinaryTreeNode
{
SearchBinaryTreeNode<K>* _left;
SearchBinaryTreeNode<K>* _right;
K _key;
SearchBinaryTreeNode(const K& x)
:_left(NULL),_right(NULL),_key(x)
{}
};
template<class K>
class SearchBinaryTree
{
typedef SearchBinaryTreeNode<K> Node;
public:
SearchBinaryTree()
:_root(NULL)
{}
~SearchBinaryTree()
{
_Delete(_root);
}
void Insert(const K& x)
{
_Insert(x);
}
bool Remove(const K& x)
{
return _Remove(x);
}
void RemoveR(const K& x)
{
_RemoveR(x, _root);
}
Node* FindR(const K& x)
{
return _FindR(_root,x);
}
Node* Find(const K& x)
{
return _Find(_root,x);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
private:
void _Delete(Node*& root)
{
if (root == NULL)
return;
_Delete(root->_left);
_Delete(root->_right);
delete root;
root = NULL;
}
Node* _Find(Node* root, const K& x)
{
while (root)
{
if (x > root->_key)
root = root->_right;
else if (x < root->_key)
root = root->_left;
else
return root;
}
return NULL;
}
Node* _FindR(Node* root, const K& x)
{
if (x > root->_key)
return _FindR(root->_right, x);
else if (x < root->_key)
return _FindR(root->_left, x);
else
{
return root;
}
return NULL;
}
void _InOrder(Node* root)
{
if (root)
{
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
}
bool _Insert(const K& x)
{
if (_root == NULL)
{
_root = new Node(x);
}
else
{
Node* cur = _root;
//Node* newNode = new Node(x);
Node* parent = cur;
while (cur)
{
if (cur->_key > x)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < x)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
if (parent->_key > x)
{
parent->_left = new Node(x);
}
else
{
parent->_right = new Node(x);
}
}
return true;
}
//删除一个数
//1,叶子节点/左子树为空或右子树为空
//2,左右子树均不为空
bool _Remove(const K& x)
{
if (_root == NULL)
return false;
Node* del = _root;
Node* parent = del;
while (del)
{
if (del->_key == x) //被删除的节点找到(左为空,右为空,左右均不为空)
{
Node* cur = del;
if (cur->_left == NULL) //删除节点无左子树
{
if (cur == _root)
_root = _root->_right;
else
{
if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
}
else if (cur->_right == NULL) //删除节点无右子树
{
if (cur == _root)
_root = _root->_left;
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
}
else //左右子树都有
{
cur = cur->_right;
while (cur->_left)
{
parent = cur;
cur = cur->_left;
}
del->_key = cur->_key;
del = cur;
if (cur == parent->_left) //注意,此时的cur是最左节点
parent->_left = cur->_right;
else //此时的cur为根节点的右子树的根节点,parent为根节点
parent->_right = cur->_right;
}
delete del;
del = NULL;
return true;
}
else if (del->_key > x)
{
parent = del;
del = del->_left;
}
else
{
parent = del;
del = del->_right;
}
}
return false;
}
bool _RemoveR(const K& x, Node* & root)
{
if (root == NULL)
return false;
if (root->_key > x)
_RemoveR(x, root->_left);
else if (root->_key < x)
_RemoveR(x, root->_right);
else //找到删除的位置
{
Node* del = root;
if (root->_left == NULL)
{
root = root->_right;
}
else if (root->_right == NULL)
{
root = root->_left;
}
else
{
Node* parent = root->_right;
Node* rootL = root->_right;
while (rootL->_left)
{
parent = rootL;
rootL = rootL->_left;
}
root->_key = rootL->_key;
del = rootL;
if (parent->_left == rootL)
parent->_left = rootL->_right;
else
parent->_right = rootL->_right;
}
delete del;
del = NULL;
return true;
}
}
Node* _root;
};
下面是测试代码:
void Test()
{
SearchBinaryTree<int> tree;
tree.Insert(5);
tree.Insert(1);
tree.Insert(2);
tree.Insert(3);
tree.Insert(4);
tree.Insert(9);
tree.Insert(8);
tree.Insert(6);
tree.Insert(7);
tree.RemoveR(5);
tree.RemoveR(4);
tree.RemoveR(1);
tree.RemoveR(9);
tree.RemoveR(2);
tree.RemoveR(3);
tree.RemoveR(6);
tree.RemoveR(7);
tree.RemoveR(8);
//cout << tree.FindR(5) << endl;
//cout << tree.Find(5) << endl;
//cout << tree.Find(9) << endl;
//cout << tree.Find(9) << endl;
tree.~SearchBinaryTree();
tree.InOrder();
}
int main()
{
Test();
system("pause");
return 0;
}
分析
搜索二叉树的退化和缺陷:
搜索二叉树找一个数的运行效率取决于它的形状(N个节点),最好的情况是满二叉树,这时总共lgN层,时间复杂度是lgN,最差的情况是上图所示,总共N层。这时它的时间复杂度是N,这是因为这棵树已经不平衡了,对于最好的情况(满二叉树),可以参考二分查找。
对于上述问题,下篇文章会介绍到高度平衡的二叉搜索树,即 AVL树。