二叉查找树是一种重要的数据结构
二叉查找树常见的操作时间复杂度一般为
O(h)
,
h
<script type="math/tex" id="MathJax-Element-2">h</script>为树的深度。此处补充二叉查找树中结点的搜索、删除,以及对应前驱、后继。此外前驱后继结点中还涉及到求子树的最大\最小元素。
要找前驱或者后继,需要添加指向父结点的指针。
前驱
若结点左子树非空,则前驱为左子树最大值;
若左子树为空,前驱为其祖先结点的父结点,且该祖先结点是其父结点的右儿子
后继
若结点右子树非空,则后继为右子树最小值;
若右子树为空,后继为其祖先结点的父结点,且该祖先结点是其父结点的左儿子
删除
删除结点分三种情况
1. 结点为叶节点,没有后代——直接删除
2. 结点只有一个后代,即仅有左儿子或者右儿子——将结点的单个后代与该结点的父结点连接起来。此处要判断该结点和后代作为左儿子还是右儿子四种情况。
3. 结点有左右两个后代——该情况比较复杂。但是可以利用前驱或者后继结点。这种情况下的前驱\后继都最多只有一个后代。以前驱为例,用前驱的关键字和数据替换掉该结点,然后对前驱执行上述第2种情况,删除前驱。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef int elemtype;
struct bstreeNode
{
elemtype data;
bstreeNode * left;
bstreeNode * right;
bstreeNode * parent;
bstreeNode(int val):data(val), left(NULL),right(NULL), parent(NULL) {}
};
//insert element
void insert(bstreeNode * r, const elemtype & val)
{
bstreeNode * p = r;
bstreeNode * pp = NULL;
while(p != NULL)
{
pp = p;
if (val >= p->data)
{
p = p->right;
}
else
{
p = p->left;
}
}
if(pp != NULL)
{
bstreeNode * pi = new bstreeNode(val);
pi -> parent = pp;
if (pp -> data <= val)
{
pp -> right = pi;
}
else
{
pp -> left = pi;
}
}
}
//create bstree
bstreeNode * cretree(const vector<elemtype> & arr)
{
bstreeNode * root;
if( arr.size()>0 )
{
root = new bstreeNode(arr.at(0));
}
for(int i=1; i<arr.size(); i++)
{
insert(root, arr.at(i));
}
return root;
}
//destroy tree
void destree(bstreeNode * & r)
{
if( r != NULL)
{
destree( r -> left );
destree( r -> right );
}
delete r;
}
//find predecessor
bstreeNode * bstreePreNode(const bstreeNode * r)
{
if(r->left != NULL)
{
bstreeNode * p = r-> left;
while(p -> right != NULL)
{
p = p-> right;
}
return p;
}
else
{
bstreeNode * pp = r-> parent;
while(pp -> parent != NULL && r != pp -> right)
{
r = pp;
pp = pp-> parent;
}
return pp;
}
}
//find successor
bstreeNode * bstreeNextNode(const bstreeNode * r)
{
if(r->right != NULL)
{
bstreeNode * p = r->right;
while(p->left != NULL)
{
p = p->left;
}
return p;
}
else
{
bstreeNode * pp = r->parent;
while(pp->parent != NULL && r != pp->left)
{
r = pp;
pp = pp -> parent;
}
return pp;
}
}
//search element value
bstreeNode * searchbstree(bstreeNode * r, const elemtype & val)
{
bstreeNode * p =r;
if(p != NULL)
{
if(p->data == val)
{
return p;
}
else
{
if(p->data > val)
{
searchbstree(p->left, val);
}
else
{
searchbstree(p->right, val);
}
}
}
else
{
return NULL;
}
}
//delete element
int delbstreeNode(bstreeNode * r, elemtype val)
{
bstreeNode * dd = searchbstree(r, val);
if(dd != NULL) //case 1
{
bstreeNode * dp = dd-> parent;
if(dd->left == NULL && dd->right == NULL)
{
if(dd == dp->right)
{
dp->right = NULL;
}
else
{
dp->left = NULL;
}
delete dd;
}
if(dd-> left == NULL || dd->right == NULL) //case 2
{
if(dd == dp->right && dd -> right != NULL)
{
dp->right = dd-> right;
}
if(dd==dp->right && dd -> left != NULL)
{
dp->right = dd->left;
}
if(dd == dp->left && dd -> right != NULL)
{
dp->left = dd-> right;
}
if(dd==dp->left && dd -> left != NULL)
{
dp->left = dd->left;
}
delete dd;
}
else //case 3
{
bstreeNode * dn = bstreePreNode(dd);
dd -> data = dn -> data;
bstreeNode * dnp = dn -> parent;
if(dd == dnp)
{
dd->left = dn -> left;
}
else
{
dnp -> right = dn -> left;
}
delete dn;
}
return 1;
}
else
{
return 0;
}
}
//print tree in LDR order
//print the predecessor and successor of every element
void LDRtree(bstreeNode * root) //traversal tree
{
if(root != NULL)
{
if( root -> left != NULL)
{
LDRtree( root -> left);
}
cout<< root->data <<" pre ";
bstreeNode * pre = bstreePreNode(root);
bstreeNode * nex = bstreeNextNode(root);
cout<< pre->data <<" next "<< nex->data <<endl;
if ( root -> right != NULL)
{
LDRtree( root -> right);
}
}
}
int main()
{
elemtype arr[] = {4, 52, 26, 4, 8, 1, 15, 3, 27, 108};
vector<elemtype> vec(arr, arr+sizeof(arr)/sizeof(elemtype));
//construct a bstree
bstreeNode * root = cretree(vec);
cout<<"print the tree:\n";
LDRtree(root);
cout<<"serched data: "<<endl;
bstreeNode * da = searchbstree(root, 26);
cout<<da->data<<endl;
cout<<"deleted? "<<delbstreeNode(root, 26)<<endl;
cout<<"print the new tree:\n";
LDRtree(root);
destree(root);
return 0;
}
本处最小元素的前驱和最大元素的后继都设定为根节点