AVL树的原理及实现

8 篇文章 0 订阅

近日觉得没事干,就随便拿来本数据结构,从中发现AVL树十分有趣,便决定把它实现了。

       下面是原理:

AVL树又叫高度平衡树,它满足两个条件:

1|h(Tl)-h(Tr)|<=1,其中h(T)表示树T的高度;

2TlTr都是高度平衡树

因为高度平衡树的特性,所以它能够保证查找的最坏复杂度Olog2n.

查找的实现十分简单如下:

template<class D,class K>

BOOL mAVLTree<D,K>::search(const K &k, D &d) const

{

  mAVLTreeNode<D,K> * current=m_pAVLTree.m_pHeadAVLTree;

  while(current)

       {

            if(k<current->pKey)

                {

                     current=current->pLlink;

                }

            else if(k>current->pKey)

                {

                     current=current->pRlink;

                }

            else

                {

                     return TRUE;

                }

       }

  return FALSE;

}

插入和删除的实现较为复杂。而这两个操作中最复杂的就是删除。那么,先谈谈如何插入。其时间复杂度为Olog2n).当你对AVL树插入一个结点时,如果是一棵空树,那么就直接插入根结点。如果插入的是非空树,那么只有4中情况需要进行位置调整。

第一种是RR型如下图显示:

图上A是表示最后一个产生变化的结点(即还没有插入结点时为+1并且在插入操作中的搜索路径上的结点)或者A就是根结点(从根结点开始的经过的路径上都是完全平衡balance=0的结点(不包括根结点))。B表示在A之后的搜索路径上,在插入前的完全平衡balance=0的结点。c表示插入结点的位置。该图的符号表示插入结点后所产生的变化。就因为产生了这样的变化所以就需要调整位置,调整位置的方法如下图所示:

图中*号表示平衡系数为0balance=0)。

另外第二种LL型跟以上的RR型类似。

那么下面介绍第三种类型RL型。情况如下图所示:

A,B与之前的表示一样,XB一样。对于这种型态,根据插入结点是X的左还是右,会得到不同的变化之后的balance值。上图插入的是X的右子树.

这种情况的位置调整如下图所示:

同样的,第四种情况LR型与上面的RL型似。

具体的实现代码如下:

//插入AVL

template<class D,class K>

HeadNode<D,K> & mAVLTree<D,K>::Insert(const K &k, const D &d)

{

     mAVLTreeNode<D,K> *t,*s,*p,*father;//ts的父亲,s是最后一个不平衡结点或者是树的HEAD结点,p是插入结点的位置,fatherp的父亲

     HeadNode<D,K> * head;

     if(!m_pAVLTree.m_pHeadAVLTree)

         {

              p=new mAVLTreeNode<D,K>();

              p->pData=d;

              p->pKey=k;

              m_pAVLTree.m_pHeadAVLTree=p;

              return m_pAVLTree;

         }

     head=&m_pAVLTree;

     t=m_pAVLTree.m_pHeadAVLTree;

     s=m_pAVLTree.m_pHeadAVLTree;

     p=m_pAVLTree.m_pHeadAVLTree;

     father=p;

     //查询插入位置

     while(p)

         {

              if(k<p->pKey)

                   {

                       p=father->pLlink;

                       if(p==NULL)

                            {

                                 p=new mAVLTreeNode<D,K>();

                                 father->pLlink=p;

                                 break;

                            }

                       else

                            {

                                 if(p->pBalance!=0)

                                     {

                                          t=father;s=p;

                                     }

                                 father=p;

                            }

                   }

              else if(k>p->pKey)

                   {

                       p=father->pRlink;

                       if(p==NULL)

                            {

                                 p=new mAVLTreeNode<D,K>();

                                 father->pRlink=p;

                                 break;

                            }

                       else

                            {

                                 if(p->pBalance!=0)

                                     {

                                          t=father;s=p;

                                     }

                                 father=p;

                            }

                   }

              else

                   {

                       printf("find the same key word!!!");

                       return m_pAVLTree;

                   }

         }

     //插入

     p->pKey=k;

     p->pData=d;

     p->pBalance=0;

     p->pLlink=NULL;

     p->pRlink=NULL;

 

     //调整结点

     mAVLTreeNode<D,K> * q,* r;

     int a=0;

     if(k<s->pKey)

         {

              r=s->pLlink;

              q=r;

         }

     else

         {

              r=s->pRlink;

              q=r;

         }

     while(q!=p)

         {

              if(k<q->pKey)

                   {

                       q->pBalance=-1;

                       q=q->pLlink;

                   }

              if(k>q->pKey)

                   {

                       q->pBalance=1;

                       q=q->pRlink;

                   }

         }

     if(k<s->pKey)

         a=-1;

     else

         a=1;

     if(s->pBalance==0)

         {

              s->pBalance=a;

              head->m_pTreeHeight+=1;

              return m_pAVLTree;

         }

     if(s->pBalance==-a)

         {

              s->pBalance=0;

              return m_pAVLTree;

         }

     //单向转动

     if(r->pBalance==a)

         {

              q=r;

              if(a==-1) //LL

                   {

                       s->pLlink=r->pRlink;

                       r->pRlink=s;

                       s->pBalance=0;

                       r->pBalance=0;

                   }

              else if(a==1)//RR

                   {

                       s->pRlink=r->pLlink;

                       r->pLlink=s;

                       s->pBalance=0;

                       r->pBalance=0;

                   }

         }

     else //双重转动

         {

              if(a==-1)// LR

                   {

                       q=r->pRlink;

                       r->pRlink=q->pLlink;

                       q->pLlink=r;

                       s->pLlink=q->pRlink;

                       q->pRlink=s;

                       if(q->pBalance==a)

                       {

                            s->pBalance=-a;

                            r->pBalance=0;

                       }

                       else if(q->pBalance==0) //当是新插入的结点时

                       {

                            s->pBalance=0;

                            r->pBalance=0;

                       }

                       else if(q->pBalance==-a)

                       {

                            s->pBalance=0;

                            r->pBalance=a;

                       }

                   }

              else if(a==1) //RL

                   {

                       q=r->pLlink;

                       r->pLlink=q->pRlink;

                       q->pRlink=r;

                       s->pRlink=q->pLlink;

                       q->pLlink=s;

                       if(q->pBalance==a)

                       {

                            s->pBalance=-a;

                            r->pBalance=0;

                       }

                       else if(q->pBalance==0) //当是新插入的结点时

                       {

                            s->pBalance=0;

                            r->pBalance=0;

                       }

                       else if(q->pBalance==-a)

                       {

                            s->pBalance=0;

                            r->pBalance=a;

                       }

                   }

              q->pBalance=0;

         }

     if(head->m_pHeadAVLTree==s)

         {

              head->m_pHeadAVLTree=q;

         }

     else

         {

              if(s==t->pRlink)

                   t->pRlink=q;

              else

                   t->pLlink=q;

         }

     return m_pAVLTree;

}

最后,我们来解决最复杂的删除结点操作。删除的时间复杂度与树的高度有关为O(h).删除可以分为两种情况:1、是删除叶结点。在这种情况下,前提条件需要建立一个堆栈S,用来保存current经过的结点。current总是son的父亲结点,B()=balance。有4条规则:

1)如果Bcurrent=0,则因子树高度的降低不影响以current为根子树型的高度,故如果son=LLINKcurrent,Bcurrent<- +1,否则Bcurrent<- -1,并终止整个过程。

2)如果Bcurrent= +1son=RLINKcurrent,或者Bcurrent=-1son=LLINK(current),Bcurrent=0,current的高度减1。此时令son<-current,current<=S,然后继续。

(3)如果Bcurrent= +1 son=LLINK(current),则此时current的平衡系数等于+2,根据下图的情况进行相应的变换。

第一种情况删除左边,+右平衡型

做单一转动后结果如下图:

由于树型高度不变,从而删除算法到此结束.

第二种情况删除左边,++型如下图所示:

单一转动变换后如下图所示:

如果不是根,又因为变换导致高度减少1所以平衡过程还要继续。

第三种情况 删除左边 + - *型,如下图所示:

双向旋转变换后如下图所示:

变换之后,如果Current不是根结点,则平衡过程还要继续,因为变换之后子书的高度减1。其实,这里根据B的情况的不同应该分成3种情况,上图只介绍了其中一种情况。其他情况只要根据BB)的值去改变其他的B()值就可以了。如果BB=0,则变换后BB=0BA=BC=0;如果BB=+1,则变换后的BB=0BA=-1BC=0;如果BB=-1,则变换后的BB=0BA=0BC=+1

4)如果Bcurrent=-1son=RLINK(current),则此时所发生的情况与(3)的正好相反,操作也类似。

2.删除的第二种情况是删除非叶结点。在这种情况下,如果有右子树那么只需要找该结点的后续结点。没右子树只有左子树时,只需和左子结点交换位置就可以了,因为平衡树的关系,左子树只有一个结点。在交换位置的同时,将该结点放入堆栈Sson指向该结点的左子树,current指向该结点。然后就跟着再进行删除叶结点的操作。

具体代码如下:

//删除叶结点的操作

template<class D,class K>

void mAVLTree<D,K>::UpdateTreeStructure(mAVLTreeNode<D,K> *current, mAVLTreeNode<D,K> *son,

                                               mAVLTreeNode<D,K> *pTDelP,mAVLTreeNode<D,K> * parent,

                                               mStack<mAVLTreeNode<D,K> > &pStack)

{

     current=pStack.Pop();

     //以下是删除叶结点并进行相应既平衡变换

     while(current)

     {

         if(current->pBalance==0)

              {

                   if(son==current->pLlink)

                       {

                            current->pBalance=1;

                       }

                   else

                       {

                            current->pBalance=-1;

                       }

                   if(parent->pLlink==pTDelP)

                       {

                            parent->pLlink=NULL;

                       }

                   else

                       {

                            parent->pRlink=NULL;

                       }

                   delete pTDelP;

                   return;

              }

         if((current->pBalance==1 && son==current->pRlink) || (current->pBalance==-1&& son==current->pLlink))

              {

                   current->pBalance=0;

                   son=current;

                   current=pStack.Pop();

              }

         else if(current->pBalance==1 && son==current->pLlink)

              {

                   if(current->pRlink->pBalance==0)// + 右平衡型

                       {

                            mAVLTreeNode<D,K> * r=current->pRlink,*pp=NULL;

                            current->pRlink=r->pLlink;

                            r->pLlink=current;

                            r->pBalance=-1;

                            pp=pStack.Pop();

                            if(pp!=NULL)  //不是根结点

                                 {

                                     if(current==pp->pLlink)

                                          {

                                               pp->pLlink=r;

                                          }

                                     else

                                          {

                                               pp->pRlink=r;

                                          }

                                 }

                            else

                                 {

                                     m_pAVLTree.m_pHeadAVLTree=r;

                                 }

                            if(parent->pLlink==pTDelP)

                                 {

                                     parent->pLlink=NULL;

                                 }

                            else

                                 {

                                     parent->pRlink=NULL;

                                 }

                            delete pTDelP;

                            return;

                       }

                   else if(current->pRlink->pBalance==1)// + +

                       {

                            mAVLTreeNode<D,K> * r=current->pRlink,*pp=NULL;

                            current->pRlink=r->pLlink;

                            r->pLlink=current;

                            r->pBalance=0;

                            current->pBalance=0;

                            pp=pStack.Pop();

                            if(pp!=NULL)  //不是根结点

                                 {

                                     if(current==pp->pLlink)

                                          {

                                               pp->pLlink=r;

                                          }

                                     else

                                          {

                                               pp->pRlink=r;

                                          }

                                 }

                            else

                                 {

                                     m_pAVLTree.m_pHeadAVLTree=r;

                                 }

                            son=r;

                            current=pp;

                        }

                   else if(current->pRlink->pBalance==-1) // + - *

                       {

                            if(current->pRlink->pLlink->pBalance==0)

                                 {

                                     mAVLTreeNode<D,K> * rl=current->pRlink->pLlink;

                                     mAVLTreeNode<D,K> * r=current->pRlink,*pp=NULL;

                                     r->pLlink=rl->pRlink;

                                     rl->pRlink=r;

                                     current->pRlink=rl->pLlink;

                                     rl->pLlink=current;

                                     r->pBalance=0;

                                     rl->pBalance=0;

                                     current->pBalance=0;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=rl;

                                                   }

                                               else

                                                   {

                                                        pp->pRlink=rl;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=rl;

                                          }

                                     son=rl;

                                     current=pp;

                                 }

                            else if(current->pRlink->pLlink->pBalance==1)

                                 {

                                     mAVLTreeNode<D,K> * rl=current->pRlink->pLlink;

                                     mAVLTreeNode<D,K> * r=current->pRlink,*pp=NULL;

                                     r->pLlink=rl->pRlink;

                                     rl->pRlink=r;

                                     current->pRlink=rl->pLlink;

                                     rl->pLlink=current;

                                     r->pBalance=0;

                                     rl->pBalance=0;

                                     current->pBalance=-1;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=rl;

                                                   }

                                               else

                                                   {

                                                        pp->pRlink=rl;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=rl;

                                          }

                                     son=rl;

                                     current=pp;

                                 }

                            else if(current->pRlink->pLlink->pBalance==-1)

                                 {

                                     mAVLTreeNode<D,K> * rl=current->pRlink->pLlink;

                                     mAVLTreeNode<D,K> * r=current->pRlink,*pp=NULL;

                                     r->pLlink=rl->pRlink;

                                     rl->pRlink=r;

                                     current->pRlink=rl->pLlink;

                                     rl->pLlink=current;

                                     r->pBalance=1;

                                     rl->pBalance=0;

                                     current->pBalance=0;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=rl;

                                                   }

                                               else

                                                    {

                                                        pp->pRlink=rl;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=rl;

                                          }

                                     son=rl;

                                     current=pp;

                                 }

                       }

              }

              else if(current->pBalance==-1 && son==current->pRlink)

              {

                   if(current->pLlink->pBalance==0)// - 左平衡型

                       {

                            mAVLTreeNode<D,K> * l=current->pLlink,*pp=NULL;

                            current->pLlink=l->pRlink;

                            l->pRlink=current;

                            l->pBalance=1;

                            pp=pStack.Pop();

                            if(pp!=NULL)  //不是根结点

                                 {

                                     if(current==pp->pLlink)

                                          {

                                               pp->pLlink=l;

                                          }

                                     else

                                          {

                                               pp->pRlink=l;

                                          }

                                 }

                            else

                                 {

                                     m_pAVLTree.m_pHeadAVLTree=l;

                                 }

                            if(parent->pLlink==pTDelP)

                                 {

                                     parent->pLlink=NULL;

                                 }

                            else

                                 {

                                     parent->pRlink=NULL;

                                 }

                            delete pTDelP;

                            return;

                       }

                   else if(current->pLlink->pBalance==1)// - -

                       {

                            mAVLTreeNode<D,K> * l=current->pLlink,*pp=NULL;

                            current->pLlink=l->pRlink;

                            l->pRlink=current;

                            l->pBalance=0;

                            current->pBalance=0;

                            pp=pStack.Pop();

                            if(pp!=NULL)  //不是根结点

                                 {

                                     if(current==pp->pLlink)

                                          {

                                               pp->pLlink=l;

                                          }

                                     else

                                          {

                                               pp->pRlink=l;

                                          }

                                 }

                            else

                                 {

                                     m_pAVLTree.m_pHeadAVLTree=l;

                                 }

                            son=l;

                            current=pp;

                       }

                   else if(current->pLlink->pBalance==-1) // - + *

                       {

                            if(current->pLlink->pRlink->pBalance==0)

                                 {

                                     mAVLTreeNode<D,K> * lr=current->pLlink->pRlink;

                                     mAVLTreeNode<D,K> * l=current->pLlink,*pp=NULL;

                                     l->pRlink=lr->pLlink;

                                     lr->pLlink=l;

                                     current->pLlink=lr->pRlink;

                                     lr->pRlink=current;

                                     l->pBalance=0;

                                     lr->pBalance=0;

                                     current->pBalance=0;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=lr;

                                                   }

                                               else

                                                   {

                                                        pp->pRlink=lr;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=lr;

                                          }

                                     son=lr;

                                     current=pp;

                                 }

                            else if(current->pLlink->pRlink->pBalance==1)

                                 {

                                     mAVLTreeNode<D,K> * lr=current->pLlink->pRlink;

                                     mAVLTreeNode<D,K> * l=current->pLlink,*pp=NULL;

                                     l->pRlink=lr->pLlink;

                                     lr->pLlink=l;

                                     current->pLlink=lr->pRlink;

                                     lr->pRlink=current;

                                     l->pBalance=-1;

                                     lr->pBalance=0;

                                     current->pBalance=0;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=lr;

                                                   }

                                               else

                                                   {

                                                        pp->pRlink=lr;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=lr;

                                          }

                                     son=lr;

                                     current=pp;

                                 }

                            else if(current->pLlink->pRlink->pBalance==-1)

                                 {

                                     mAVLTreeNode<D,K> * lr=current->pLlink->pRlink;

                                     mAVLTreeNode<D,K> * l=current->pLlink,*pp=NULL;

                                     l->pRlink=lr->pLlink;

                                     lr->pLlink=l;

                                     current->pLlink=lr->pRlink;

                                     lr->pRlink=current;

                                     l->pBalance=0;

                                     lr->pBalance=0;

                                     current->pBalance=1;

                                     pp=pStack.Pop();

                                     if(pp!=NULL)  //不是根结点

                                          {

                                               if(current==pp->pLlink)

                                                   {

                                                        pp->pLlink=lr;

                                                   }

                                               else

                                                   {

                                                        pp->pRlink=lr;

                                                   }

                                          }

                                     else

                                          {

                                               m_pAVLTree.m_pHeadAVLTree=lr;

                                          }

                                     son=lr;

                                     current=pp;

                                 }

                       }

              }

     }

     if(parent->pLlink==pTDelP)

         {

              parent->pLlink=NULL;

         }

     else

         {

              parent->pRlink=NULL;

         }

     delete pTDelP;

}

//删除结点的操作方法

template<class D,class K>

BOOL mAVLTree<D,K>::DeleteNode(const K &k)

{

     mAVLTreeNode<D,K> * current=NULL;

     mAVLTreeNode<D,K> * son=m_pAVLTree.m_pHeadAVLTree;

     mAVLTreeNode<D,K> * pTDelP=NULL; //真实删除点的位置

     mAVLTreeNode<D,K> * parent=NULL; //真实删除点的位置的父亲结点

     mStack<mAVLTreeNode<D,K>> pStack;

     if(son==NULL)

         {

              return FALSE;

         }

     while(son)

         {

              if(k<son->pKey)

                   {

                       mStackNode<mAVLTreeNode<D,K>> * pStackNode=new mStackNode<mAVLTreeNode<D,K>>();

                       pStackNode->pNode=son;

                       pStack.Push(pStackNode);

                       current=son;

                       son=son->pLlink;

                   }

              else if(k>son->pKey)

                   {

                       mStackNode<mAVLTreeNode<D,K>> * pStackNode=new mStackNode<mAVLTreeNode<D,K>>();

                       pStackNode->pNode=son;

                       pStack.Push(pStackNode);

                       current=son;

                       son=son->pRlink;

                   }

              else

                   {

                       break;

                   }

         }

     if(son==NULL)

         return FALSE;

     parent=current;

     pTDelP=son;

     if(son->pRlink)        //如果删除的结点有右子树

         {

              while(son->pRlink)

              {

                   mAVLTreeNode<D,K> * p=son->pRlink;

                   while(p->pLlink)

                       {

                            p=p->pLlink;

                       }

                   while(son)//下移删除结点

                       {

                            if(p->pKey<son->pKey)

                            {

                                 mStackNode<mAVLTreeNode<D,K>> * pStackNode=new mStackNode<mAVLTreeNode<D,K>>();

                                 pStackNode->pNode=son;

                                 pStack.Push(pStackNode);

                                 current=son;

                                 son=son->pLlink;

                            }

                       else if(p->pKey>son->pKey)

                            {

                                 mStackNode<mAVLTreeNode<D,K>> * pStackNode=new mStackNode<mAVLTreeNode<D,K>>();

                                 pStackNode->pNode=son;

                                 pStack.Push(pStackNode);

                                 current=son;

                                son=son->pRlink;

                            }

                       else

                            {

                                 break;

                            }

                       }

                   //交换删除结点的值

                   D dd;

                   K kk;

                   dd=son->pData;

                   kk=son->pKey;

                   son->pData=pTDelP->pData;

                   son->pKey=pTDelP->pKey;

                   pTDelP->pData=dd;

                   pTDelP->pKey=kk;

                   pTDelP=son;

                   parent=current;

              }

              UpdateTreeStructure(current,son,pTDelP,parent,pStack);

         }

     else if(son->pLlink)   //只有一个左结点的情况

     {

         mStackNode<mAVLTreeNode<D,K>> * pStackNode=new mStackNode<mAVLTreeNode<D,K>>();

         pStackNode->pNode=son;

         pStack.Push(pStackNode);

         current=son;

         son=son->pLlink;

 

         D dd;

         K kk;

         dd=son->pData;

         kk=son->pKey;

         son->pData=pTDelP->pData;

         son->pKey=pTDelP->pKey;

         pTDelP->pData=dd;

         pTDelP->pKey=kk;

         pTDelP=son;

         parent=current;

 

         UpdateTreeStructure(current,son,pTDelP,parent,pStack);

     }

     else     //删除叶结点

     {

         UpdateTreeStructure(current,son,pTDelP,parent,pStack);

     }

     return TRUE;

}

最后给出主要AVL树类:

//AVL

template<class D,class K>

class mAVLTree

{

     protected:

         HeadNode<D,K>  m_pAVLTree;

     public:

         mAVLTree()

         {

              m_pAVLTree.m_pTreeHeight=0;

              m_pAVLTree.m_pHeadAVLTree=NULL;

         }

         mAVLTree(HeadNode<D,K> &pAVLTree)

         {

              m_pAVLTree.m_pTreeHeight=pAVLTree.m_pTreeHeight;

              m_pAVLTree.m_pHeadAVLTree=pAVLTree.m_pHeadAVLTree;

         }

         ~mAVLTree(){}

         BOOL search(const K & k,D & d)const;

         HeadNode<D,K> & Insert(const K & k,const D & d);

         int Depth(mAVLTreeNode<D,K> * pTree);

         void print(mAVLTreeNode<D,K> * pTree);

         //删除结点,平衡树的变换过程

         void UpdateTreeStructure(mAVLTreeNode<D,K> * current,mAVLTreeNode<D,K> * son,

              mAVLTreeNode<D,K> * pTDelP,mAVLTreeNode<D,K> *parent,mStack<mAVLTreeNode<D,K>> &pStack);

         BOOL DeleteNode(const K & k);

         //检测平衡树

         BOOL IsBalanceTree(mAVLTreeNode<D,K> * pTree);

         //获取树

         mAVLTreeNode<D,K>* GetTree(){return m_pAVLTree.m_pHeadAVLTree;}

};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值