二叉查找树常用操作(接上篇)

二叉查找树是一种重要的数据结构

二叉查找树常见的操作时间复杂度一般为 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;
}

本处最小元素的前驱和最大元素的后继都设定为根节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值