SBT 简短代码 (poj3481,并附上用STL set/map做的代码)

关于Size Balanced Tree的讲解可以查看发明者陈启峰的PPT:
http://wenku.baidu.com/view/ef481548cf84b9d528ea7a56.html
或者论文:
http://wenku.baidu.com/view/364afa42a8956bec0975e3b1.html
我就不搬运了~

set和map内部是使用红黑树实现的,故其中的数据是有序的,也可以用来解此题,而且两者的时间空间使用都一模一样。
进一步了解红黑树:http://blog.csdn.net/iceteaset/article/details/48032497
我全部使用inline的红黑树可以达到250ms,比下面的SBT更快一点点。或许是实现方式的问题。不过就算SBT真的慢一点点,它的代码长度可不止短了一点点。

以下代码均可以在poj3481上测试其正确性和时间。

SBT:

#include<iostream>
//192K 282MS
struct Key  //单独设置一个struct是为了方便修改(value域不可删除)
{
    int value,num;
};
struct SBNode  //省略了parent域,不过也导致insert,delete只能使用递归
{
    Key key;
    int size;
    SBNode* c[2];
    SBNode(){}
    SBNode(const Key& k){
        key=k;
        size=1;
    }
};
class SBTree
{
private:
    SBNode* root,*nil;
    inline void rotate(SBNode*& x,bool l) //根据l的值(LEFT/RIGHT)进行左右旋
    {
        SBNode* y=x->c[!l];
        x->c[!l]=y->c[l];
        y->c[l]=x;
        y->size=x->size;
        x->size=x->c[l]->size+x->c[!l]->size+1;
        x=y;
    }
    inline bool cmp(const Key& k1,const Key& k2) //自定义比较函数
    {
        if (k1.value<k2.value) return LEFT;
        else return RIGHT;
    }
    inline void maintain(SBNode * &x , bool l) //根据l的值(LEFT/RIGHT)进行左右子树的维护
    {
        if (x->c[l]->c[l]->size>x->c[!l]->size)
            rotate(x,!l);
        else if (x->c[l]->c[!l]->size>x->c[!l]->size){
            rotate(x->c[l],l);
            rotate(x,!l);
        }else return;
        maintain(x->c[l],l);
        maintain(x->c[!l],!l);
        maintain(x,l);
        maintain(x,!l);
    }
public:
    SBTree(){nil=new SBNode;nil->size=0;nil->c[0]=nil;nil->c[1]=nil;root=nil;}
    ~SBTree(){delete nil;} 
    const static bool LEFT=false,RIGHT=true;  //增强可读性
    inline void insert(const Key& key){insert(root,key);} //重载是为了方便调用
    inline void insert(SBNode*& x,const Key& key)
    {
        if (x==nil)
        {
            x=new SBNode(key);
            x->c[0]=nil;
            x->c[1]=nil;
        }else{
            x->size++;
            bool lr=cmp(key,x->key);
            insert(x->c[lr],key); //递归进下一层
            maintain(x,lr);
        }
    }
    inline bool del(const Key& key){return del(root,key);}
    inline bool del(SBNode*& x,const Key& key)
    {
        if (x==nil)
            return false;
        if (cmp(key,x->key) && cmp(x->key,key)) //如果Key相等,即找到了
        {
            if (x->c[LEFT]!=nil && x->c[RIGHT]!=nil) //如果有两个孩子,
            {                                        
                SBNode* temp=x->c[RIGHT];
                while (temp->c[LEFT]!=nil)
                    temp=temp->c[LEFT];
                x->key=temp->key;                   //则用后继的Key代替当前的Key,
                x->size--;
                del(x->c[RIGHT],temp->key);         //然后继续递归,目标改为了后继
                return true;
            }
            bool lr=x->c[LEFT]!=nil? LEFT:RIGHT;
            SBNode* temp=x;
            x=x->c[lr];
            delete temp;
            return true;
        }else{
            bool lr= cmp(key,x->key);
            if (del(x->c[lr],key)) //递归进下一层
                x->size--;
        }
    }
    inline SBNode* findMost(bool lr) //找树中最大值/最小值
    {
        SBNode *p=root;
        if (p==nil) return NULL;
        else{
            while (p->c[lr] != nil) p = p->c[lr];
            return p;       
        }
    }
};
int main()
{
    SBTree* tree=new SBTree;
    int no,k,p;
    while (scanf("%d",&no),no)
    {
        SBNode* nod;
        Key key;
        switch (no)
        {
        case 1:
            scanf("%d%d",&k,&p);
            key.value=p;
            key.num=k;
            tree->insert(key);
            break;
        case 2:
            nod=tree->findMost(SBTree::RIGHT);
            printf("%d\n",nod==NULL?0:nod->key.num);
            if (nod!=NULL) tree->del(nod->key);
            break;
        case 3:
            nod=tree->findMost(SBTree::LEFT);
            printf("%d\n",nod==NULL?0:nod->key.num);
            if (nod!=NULL) tree->del(nod->key);
            break;
        }
    }
    return 0;
}

set:

#include<iostream>
#include<set>
//196K 282MS
using namespace std;
struct Key
{
    int value,num;
};
class Cmp{
public:
    inline bool operator()(const Key& a,const Key& b)
    {
        return a.value>b.value;
    }
};

int main()
{
    set<Key,Cmp> s;
    int no,k,p;
    Key key;
    set<Key,Cmp>::iterator i;
    while (scanf("%d",&no),no)
    {
        switch (no)
        {
        case 1:
            scanf("%d%d",&k,&p);
            key.value=p;
            key.num=k;
            s.insert(key);
            break;
        case 2:
            if (s.empty())
                printf("%d\n",0);
            else 
            {
                i=s.begin();
                printf("%d\n",(*i).num);
                s.erase(i);
            }
            break;
        case 3:
            if (s.empty())
                printf("%d\n",0);
            else 
            {
                i=s.end();
                i--;
                printf("%d\n",(*i).num);
                s.erase(i);
            }
            break;
        }
    }
    return 0;
}

map:

#include<iostream>
#include<map>
//196K 282MS
using namespace std;

int main()
{
    int no,k,p;
    map<int,int> m;
    map<int,int>::iterator i;
    while (scanf("%d",&no),no)
    {
        switch (no)
        {
        case 1:
            scanf("%d%d",&k,&p);
            m[p]=k;
            break;
        case 2:
            if (m.empty())
                printf("%d\n",0);
            else 
            {
                i=m.end();
                i--;
                printf("%d\n",(*i).second);
                m.erase(i);
            }
            break;
        case 3:
            if (m.empty())
                printf("%d\n",0);
            else 
            {
                i=m.begin();
                printf("%d\n",(*i).second);
                m.erase(i);
            }
            break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值