SBTree树实现

SBTree树实现

SBTree与AVL树具有相同的概念,也具有相同的操作,类似自平衡,旋转操作和旋转触发。SBTree严格遵守下列公式,如有违反,则需要通过相应的转置操作来达到平衡.

SIZE[right[t]] >= max(SIZE[left[left[t]]],SIZE[right[left[t]]]);

SIZE[left[t]] >= max(SIZE[left[right[t]]],SIZE[right[right[t]]]);

其中SIZE[t]表示t结点所在的子树个数,且两个公式必须同时满足

SIZE[left[left[t]]]可以表示成t->left->left,SIZE[right[left[t]]]可表示成t->left->right

每个结点所在子树的结点个数不小于其兄弟的两个孩子所在子树的结点个数。

还有SBTree只有在插入时才可能触发调整.

下面看其实现:

 #include <iostream>
 using namespace std;

//树节点类
 class SBTNode{
     //size:子树大小,就是以当前节点为根构成的树有多少节点
     //data:权值,就是树上的节点存储的值
     //value:临时存储权值的
     int data,size,value;
     SBTNode *lchild,*rchild,*father;
     //构造函数,参数分别为权值,以当前节点为根的树的大小,父亲节点
     SBTNode(int init_data,int init_size = 0,SBTNode *init_father = NULL);
     ~~SBTNode();
     //二叉排序树的插入
     void insert(SBTNode *node,int value);
     //搜索
     SBTNode *search(int value);
     //找前驱
     SBTNode *predecessor();
     //找后继
     SBTNode *successor();
     //移除某个度为0或1的节点
     void remove_node(SBTNode *delete_node);
     //移除某个权值的点
     bool remove(int value);
     //找出第k大的元素
     int select(int k);
 };

class BinaryTree{
private:
    SBTNode *root;
public:
    BinaryTree();
    ~BinaryTree();
    //下面依次是二叉树的插入、查找、删除节点、找出第k大的树,都是以上面
    //的节点类的函数为基础的
    void insert(int value);
    bool find(int value);
    bool remove(int value);
    int select(int k);
};
//这里搞了个权值为0的节点,就相当于我们的NULL
//不过我们这里代替NULL指针的是ZERO(权值为0的节点)的地址,我们看到下面SBTNode的构造函数初始化的时候用的也是ZPTR指针.

SBTNode ZERO(0);
SBTNode* ZPTR = &ZERO;

SBTNode::SBTNode(int init_data,int init_size,SBTNode *init_father){
    data = init_data;
    size = init_size;
    lchild = ZPTR;
    rchild = ZPTR;
    father = init_father;
}

SBTNode::~SBTNode(){
    if(lchild != ZPTR){
        delete lchild;
    }
    if(rchild != ZPTR){
        delete rchild;
    }
}

//左旋:将右孩子变为“根节点”(当前子树的根节点),右孩子的左孩子变为原来根节点的右孩子
//下面注释中:node(原来的根节点)的右孩子用“根节点”来说
SBTNode *left_rotate(SBTNode *node){
    //用temp保存“根节点”
    SBTNode *temp = node->rchild;
    //"根节点"的左孩子 变为node(原来的根节点)的右孩子
    node->rchild = temp->lchild;
    //更新"根节点"原来的左孩子的父亲为node(原来的根节点)
    temp->lchild->father = node;
    //node(原来的根节点)就变为"根节点"的左孩子
    temp->lchild = node;
    //"根节点"的父亲更新为node(原来的根节点)的父亲
    temp->father = node->father;
    //node(原来的根节点)的父亲更新为"根节点"
    node->father = temp;
    //"根节点"的大小更新为node(原来的根节点)的大小
    temp->size = node->size;
    //node(原来的根节点)的大小更新为它左孩子和右孩子的大小再加上本身1
    node->size = node->lchild->size + node->rchild->size + 1;
    //返回左旋后的根节点
    return temp;
}

//右旋:将左孩子变为"根节点"(当前子树的根节点),左孩子的右孩子就变为原来的根节点的左孩子
//下面注释中:node(原来的根节点)的左孩子用"根节点"来说
SBTNode *right_rotate(SBTNode *node){
    //用temp保存"根节点"
    SBTNode *temp = node->lchild;
    node->lchild = temp->rchild;
    temp->rchild->father = node;

    temp->rchild = node;
    temp->father = node->father;
    node->father = temp;

    temp->size = node->size;
    node->size = node->lchild->size + node->rchild->size + 1;
    return temp;
}

//利用上面的左右旋进行调整的函数
//flag为false:处理左子树更高得情况,否则处理右子树更高得情况
//node:要调整的子树的根节点
SBTNode *maintain(SBTNode *node,bool flag){
    //左子树比右子树高
    if(flag == false){
        //LL型:左子树的左子树的元素个数大于右子树的元素个数,应进行右旋
        if(node->lchild->lchild->size > node->rchild->size){
            //右旋并更新子树的根节点
            node = right_rotate(node);
        }
        //LR型:左子树的右子树的元素个数大于右子树的元素个数
        //那么先对左子树进行左旋,就变成了LL型,再右旋即可
        else if(node->lchild->rchild->size > node->rchild->size){
            //左旋并更新左子树的根节点
            node->lchild = left_rotate(node->lchild);
            //右旋并更新根节点
            node = right_rotate(node);
        }else{
            //说明平衡了,返回根节点
            return node;
        }
    }
    //右子树比左子树高
    else{
        //RR型:右子树的右子树的元素大于左子树的元素个数,应进行左旋
        if(node->rchild->rchild->size > node->lchild->size){
            //左旋并更新根节点
            node = left_rotate(node);
        }
        //RL型:右子树的左子树的元素个数大于左子树的元素个数
        //那么先对右子树进行右旋,变成RR型,再左旋即可.
        else if(node->rchild->lchild->size > node->lchild->size){
            //右旋并更新左子树的根节点
            node->rchild = right_rotate(node->rchild);
            //左旋并更新根节点
            node = left_rotate(node);
        }else{
            //说明平衡了,返回根节点
            return node;
        }
    }

    //下面为递归调用,因为有时上面的调整过后,左子树和右子树的某个节点还是不平衡
    //递归调用,处理可能左子树的左子树更高的情况
    //false表示左子树较高
    node->lchild = maintain(node->lchild,false);
    //其右子树的右子树高度更高的情况
    node->rchild = maintain(node->rchild,true);
    //最后再对子树根节点的左右子树递归进行调整
    node = maintain(node,false);
    node = maintain(node,true);
    //返回调整后的子树的根节点
    return node;
}

SBTNode *insert(SBTNode *node,int value){
    if(value == node->data){
        return node;
    }else{
        node->size++;
        if(value > node->data){
            if(node->rchild == ZPTR){
                node->rchild = new SBTNode(value,1,node);
            }else{
                node->rchild = insert(node->rchild,value);
            }
        }else{
            if(node->lchild == ZPTR){
                node->lchild = new SBTNode(value,1,node);
            }else{
                node->lchild = insert(node->lchild,value);
            }
        }
    }

    return maintain(node,value > node->data);
}

SBTNode *SBTNode::search(int value){
    if(data == value){
        return this;
    }else if(value > data){
        if(rchild == ZPTR){
            return ZPTR;
        }else{
            return rchild->search(value);
        }
    }else{
        if(lchild == ZPTR){
            return ZPTR;
        }else{
            return lchild->search(value);
        }
    }
}

SBTNode *SBTNode::predecessor(){
    SBTNode *temp = lchild;
    while(temp != ZPTR && temp->rchild != ZPTR){
        temp = temp->rchild;
    }
    return temp;
}

SBTNode *SBTNode::successor(){
    SBTNode *temp = rchild;
    while(temp != ZPTR && temp->lchild != ZPTR){
        temp = temp->lchild;
    }
    return temp;
}

void SBTNode::remove_node(SBTNode *delete_node){
    SBTNode *temp = ZPTR;
    if(delete_node->lchild != ZPTR){
        temp = delete_node->lchild;
        temp->father = delete_node->father;
        delete_node->lchild = ZPTR;
    }

    if(delete_node->rchild != ZPTR){
        temp = delete_node->rchild;
        temp->father = delete_node->father;
        delete_node->rchild = ZPTR;
    }

    if(delete_node->father->lchild == delete_node){
        delete_node->father->lchild = temp;
    }else{
        delete_node->father->rchild = temp;
    }

    temp = delete_node;
    while(temp != NULL){
        temp->size--;
        temp = temp->father;
    }

    delete delete_node;
}

bool SBTNode::remove(int value){
    SBTNode *delete_node, *current_node;
    current_node = search(value);
    if(current_node == ZPTR){
        return false;
    }
    size--;
    if(current_node->lchild != ZPTR){
        delete_node = current_node->predecessor();
    }else if(current_node->rchild != ZPTR){
        delete_node = current_node->successor();
    }else{
        delete_node = current_node;
    }

    current_node->data = delete_node->data;
    remove_node(delete_node);
    return true;
}

int SBTNode::select(int k){
    //rank当前节点在子树的排位
    int rank = lchild->size + 1;
    //若rank等于第k大,说明就是要找的值,直接返回权值
    if(rank == k){
        return data;
    }else if(k < rank>){
        //小于rank,就表明要找比当前节点更小的值,就在左边查找
        return lchild->select(k);
    }else{
        //大于就在右边
        //这里只所以看k-rank,因为我们已经把前rank排除了,
        //相当于我们要在右子树(把他当做一棵新的树去查找),所以排位当然要减去rank.
        return rchild->select(k - rank);
    }
}

BinaryTree::BinaryTree(){
    root = NULL;
}

BinaryTree::~BinaryTree(){
    if(root != NULL){
        delete root;
    }
}


void BinaryTree::insert(int value){
    if(root == NULL){
        //初始化时只有根节点,所以子树大小为1
        root = new SBTNode(value,1);
    }else{
        root = ::insert(root,value);
    }
}

bool BinaryTree::find(int value){
    if(root->search() == NULL){
        return false;
    }else{  
        return true;
    }
}

bool BinaryTree::remove(int value){
    return root->remove(value);
}

int BinaryTree::select(int k){
    return root->select(k);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云镛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值