二叉搜索树

本文详细介绍了二叉搜索树(BST)的实现方法,包括模板类定义、节点操作、查找、插入、删除等功能。通过递归和迭代方式实现查找算法,并提供插入和删除节点的具体步骤。
#include "BinTree.hpp"
//二叉搜索树
//任何一个二叉树是二叉搜索树,当且仅当其中序遍历序列单调非降

//词条模版类
template <typename K,typename V> struct Entry {
    K key;
    V value;
    
    Entry(K k = K(), V v = V()) : key(k), value(v) {}
    
    Entry(Entry<K,V> const& e) : key(e.key), value(e.value) {}
    
    bool operator<(Entry<K,V> const& e) {
        return key < e.key;
    }
    
    bool operator>(Entry<K,V> const& e) {
        return key > e.key;
    }
    
    bool operator==(Entry<K,V> const& e) {
        return key == e.key;
    }
    
    bool operator!=(Entry<K,V> const& e) {
        return key != e.key;
    }
    
};


template <typename T> class BST : public BinTree<T> {
protected:
    BinNodePosi(T) _hot; //"命中"节点的父亲
    BinNodePosi(T) connect34(  //按照"3+4"的结构,连接3个节点及3颗子树
                             BinNodePosi(T),BinNodePosi(T),BinNodePosi(T),
                             BinNodePosi(T),BinNodePosi(T),BinNodePosi(T),BinNodePosi(T));
    BinNodePosi(T) rotateAt(BinNodePosi(T) x); //对x及其父亲、祖父做统一旋转调整
    
public:
    virtual BinNodePosi(T)& search(const T& e); //查找
    virtual BinNodePosi(T) insert(const T& e); //插入
    virtual bool remove(const T& e); //删除
};


#pragma mark - 查找
//在以v为根的(AVL、SPLAY、rbTree等)BST子树中查找关键码e
template <typename T>
static BinNodePosi(T)& searchIn(BinNodePosi(T) & v, const T& e,BinNodePosi(T) & hot) {
    if (!v || (e == v->data)) {
        return v;
    }
    //一般情况:先记下当前节点,然后再深入一层,递归查找
    hot = v;
    
    return searchIn((e < v->data)? v->lc:v->rc, e, hot);
}

//迭代版
#define EQUAL(e, v) (!(v) || (e) == (v)->data) //节点v(或假想的通配哨兵)的关键码等于e

template <typename T>
static BinNodePosi(T)& searchIn_I2(BinNodePosi(T) & v, const T& e,BinNodePosi(T) & hot) {
    if (EQUAL(e, v)) {
        return v;    //退化情况:在子树根节点v处命中
    }
    
    hot = v;
    
    while (1) {
        //确定深入方向
        BinNodePosi(T) & c = ( e < hot->data) ? hot->lc : hot->rc;
        
        if (EQUAL(e, c)) {
            return c;
        }
        
        hot = c;
    }//hot始终指向最后一个失败节点
    
}//返回时,返回值指向命中节点(或假想的通配哨兵),hot指向其父亲(退化时为初始值NULL)


template <typename T> BinNodePosi(T) & BST<T>::search(const T &e) {
    return searchIn(this->_root, e, _hot = NULL);
}

#pragma mark - 插入
//将关键码e插入BST树中
template <typename T> BinNodePosi(T) BST<T>::insert(const T &e) {
    BinNodePosi(T) &x = search(e);
    if (x) {
        return x; //确认目标不存在(留意对_hot的设置)
    }
    
    x = new BinNode<T> (e, _hot);  //创建新节点x:以e为关键码,以_hot为父
    this -> _size++;  //更新全树规模
    this -> updateHeightAbove(x);  //更新x及其历代祖先的高度
    return x;   //新插入的节点,必为叶子
}//无论e是否存在于原树中,返回时总有x->data == e

#pragma mark - 删除
template <typename T>
static BinNodePosi(T) removeAt(BinNodePosi(T) &x,BinNodePosi(T) &hot) {
    BinNodePosi(T) w = x;        //实际被摘除的节点,初值同x
    BinNodePosi(T) succ = NULL;  //实际被删除节点的接替者
    
    if ( ! HasLChild(*x) ){
        //若*x的左子树为空,则可直接将*x替换为其右子树
        succ = x = x -> rc;
    }else if ( !HasRChild(*x) ) {
        //若右子树为空,则可对称的处理---注意,此时succ != NULL
        succ = x = x -> lc;
    }else{
        //若左右子树均存在,则选择x的直接后继作为实际被摘除节点,为此需要(在右子树中)找到*x的直接后继*w
        //交换*x和*w的数据元素
        w = w -> succ();
        std::swap(x->data, w->data);
        BinNodePosi(T) u = w -> parent;
        ( (u == x) ? u->rc : u->lc ) = succ = w -> rc;  //隔离节点*w
    }
    
    
    hot = w -> parent; //记录实际被删除节点的父亲
    if (succ) {
        succ -> parent = hot;   //并将被删除节点的接替者与hot相连
    }
    
    delete w -> data;
    delete w;
    
    return succ;//释放被摘除节点,返回接替者
}

//从BST树中删除关键码e
template <typename T> bool BST<T>::remove(const T &e) {
    BinNodePosi(T) &x = search(e);
    if (!x) {   //确认目标存在(留意_hot的设置)
        return false;
    }
    
    removeAt(x, _hot);   //实施删除
    this -> _size--;
    this -> updateHeightAbove(_hot); //更新_hot及其历代祖先的高度
    return true;
}//删除成功与否,由返回值指示


template <typename T> BinNodePosi(T) BST<T>::connect34(BinNodePosi(T) a, BinNodePosi(T) b, BinNodePosi(T)c, BinNodePosi(T) T0, BinNodePosi(T) T1, BinNodePosi(T) T2, BinNodePosi(T) T3) {
    a -> lc = T0;
    if (T0) {
        T0 -> parent = a;
    }
    
    a -> rc = T1;
    if (T1) {
        T1 -> parent = a;
    }
    this -> updateHeight(a);
    
    
    c -> lc = T2;
    if (T2) {
        T2 -> parent = c;
    }
    
    c -> rc = T3;
    if (T3) {
        T3 -> parent = c;
    }
    this -> updateHeight(c);
    
    b -> lc = a;
    a -> parent = b;
    b -> rc = c;
    c -> parent = b;
    this -> updateHeight(b);
    return b;  //该子树新的根节点
}

//v为非空孙辈节点
template <typename T> BinNodePosi(T) BST<T>::rotateAt(BinNodePosi(T) v){
    
    BinNodePosi(T) p = v -> parent;
    BinNodePosi(T) g = p -> parent;
    
    if (IsLChild(*p)) { //zig
        
        if (IsLChild(*v)) { //zig--zig
            p -> parent = g -> parent;//向上联接
            return connect34(v, p, g, v->lc, v->rc, p->rc, g->rc);
        }else{  //zig--zag
            v -> parent = g -> parent;  //向上联接
            return connect34(p, v, g, p->lc, v->lc, v->rc, g->rc);
        }
        
    }else{ //zag
        
        if (IsRChild(*v)) { //zag--zag
            p -> parent = g -> parent;//向上联接
            return connect34(g, p, v, g->lc, p->lc, v->lc, v->rc);
        }else{ //zag---zig
            v -> parent = g -> parent; //向上联接
            return connect34(g, v, p, g->lc, v->lc, v->rc, p->rc);
        }
        
        
    }
    
}

 

转载于:https://www.cnblogs.com/gkp307/p/9943767.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值