伸展树用于查询结果的概率非平均情况,即起初假设某些要查询的信息偏多,有些信息几乎无人问津。对于平均访问概率来说,使用SplayTree实现并不是一个明智的选择。
可能会用到此数据结构的程序:词典或者多维搜索树,还有连接/切除树(link/cut tree)(这个树是用于网络优化问题包括最大流和最小代价)
- /*
- *createbychicochen
- *date:2008/10/02
- */
- template<classT>
- classSplayTree:publicBinaryTree<T>
- {
- public:
- explicitSplayTree(T&data):BinaryTree(data)
- {
- }
- explicitSplayTree(TreeNode<T>*root):BinaryTree(root)
- {
- }
- ~SplayTree()
- {
- }
- public:
- voidinsertNode(T&data)
- {
- if(NULL==this->head)
- {
- this->head=newTreeNode<T>(data);
- return;
- }
- splay(this->head,data);
- if(this->head->data>data)
- {
- //ABA
- // /\-> /\
- //CDCB
- //\
- //D
- TreeNode<T>*node=newTreeNode<T>(data);
- node->left=this->head->left;
- node->right=this->head;
- this->head->left=NULL;
- this->head=node;
- }
- elseif(this->head->data<data)
- {
- //ABA
- // /\-> /\
- //CDBD
- // /
- // C
- TreeNode<T>*node=newTreeNode<T>(data);
- node->right=this->head->right;
- node->left=this->head;
- this->head->right=NULL;
- this->head=node;
- }
- else
- {
- //insertthesamekey
- //throwexception
- throw"thesamekey";
- }
- }
- //usethedataaskeytosplaythetree
- //thenwecangetthestructuresofthetreelikethefollowing:
- //(1)A(2)A
- // \ /\
- // BCB
- //thedifferencebetweenthetwostructuresiswhethertheroothasleftchild
- //Incase(1),wecansimpliymaketherootrightchildinsteadtheroot.
- //Incase(2),weshouldsplaytherootleftsubtreeandthenitwillbe
- //changedlikecase(1),andwemakethesplayedleftsubtreerootinstead
- //theroot.
- voiddeleteNode(T&data)
- {
- if(NULL==this->head)
- {
- return;
- }
- splay(this->head,data);
- if(this->head->data!=data)
- {
- //notfoundthekeytodelete
- return;
- }
- TreeNode<T>*newRoot;
- if(NULL==this->head->left)
- {
- newRoot=this->head->right;
- }
- else
- {
- newRoot=this->head->left;
- splay(newRoot,data);
- newRoot->right=this->head->right;
- }
- deletethis->head;
- this->head=newRoot;
- }
- TreeNode<T>*searchNode(T&data)
- {
- if(NULL==this->head)
- {
- returnNULL;
- }
- splay(this->head,data);
- if(this->head->data==data)
- {
- returnthis->head;
- }
- returnNULL;
- }
- private:
- //usetop-downsplaymethod,
- //youshouldmakethesuitablefinalstep
- //accordingtothesituation,suchas"insert","delete","search".
- //Andwhat'sthetop-downmethod?
- //nowweshouldaddLeftMaxRootasLandRightMinRootasR
- //1.LAR2.LAR3.LAR
- // // /
- // BB B
- // /\
- //CC
- //
- //1.->LBR2.->LCR3.LCR
- //// \/
- //A B BA
- //\
- // A
- //butincase3.wecansimplifiedcase3rotateas
- //3.LBR
- // \ /
- // CA
- //andwemustintegratetheLeftMaxRootandRightMinRoottogether,
- //thenwehavefinalsteptodothis.AndLislefttree,andRisrighttree.
- //LARA
- ///\-> /\
- //BCLR
- // \/
- // BC
- voidsplay(TreeNode<T>*&subRoot,T&data)
- {
- if(NULL==subRoot)
- {
- return;
- }
- TreeNode<T>*leftRoot;
- TreeNode<T>*rightRoot;
- //heresomecodeusestaticmember,ifyoupromiseyouhavesync-control
- //oryoudon'tusethiscodeinthreadorprocess,youcouldchoosestatic
- //membertoaccelerateyourprogram.
- //Itmeansthefollowingcodeisthread-safe.
- TreeNode<T>head(data);
- leftRoot=rightRoot=&head;
- while(true)
- {
- if(data<subRoot->data)
- {
- if(NULL==subRoot->left)
- {
- break;
- }
- elseif(data<subRoot->left->data)
- {
- //Leftrotate
- TreeNode<T>*tempLeft=subRoot->left;
- subRoot->left=tempLeft->right;
- tempLeft->right=subRoot;
- subRoot=tempLeft;
- }
- else
- {
- //donothing
- }
- //splitthetreewithrightroot
- if(NULL==subRoot->left)
- break;
- rightRoot->left=subRoot;
- rightRoot=subRoot;
- subRoot=subRoot->left;
- }
- elseif(data>subRoot->data)
- {
- if(NULL==subRoot->right)
- {
- //neednottorotate
- break;
- }
- elseif(data>subRoot->right->data)
- {
- //rightrotate
- TreeNode<T>*tempRight=subRoot->right;
- subRoot->right=tempRight->left;
- tempRight->left=subRoot;
- subRoot=tempRight;
- }
- else
- {
- //donothing
- }
- //splitthetreebyleftroot
- if(NULL==subRoot->right)
- break;
- leftRoot->right=subRoot;
- leftRoot=subRoot;
- subRoot=subRoot->right;
- }
- else
- {
- //thesamekey
- break;
- }
- }
- //thefinalstep
- //wehavefindthelastnode,antthenweshould
- //integratetheleftroot,therightrootandtherootintoOnetree.
- //head.rightisleftroot
- //head.leftisrightroot
- leftRoot->right=subRoot->left;
- rightRoot->left=subRoot->right;
- subRoot->left=head.right;
- subRoot->right=head.left;
- }
- };
发现优快云的代码编辑器还是有些问题,空格处理不好,导致我注释中的树形错乱了...
不过没有大关系,应该抓起旁边的纸边看边画就能明白。
在网上找splayTree的源码学习,发现凭自己的实力还真的看不懂.....
幸好在家里翻到了古老的数据结构教材。这才明白。
至于不使用添加父节点或者采用递归栈等方式的原因在于:空间消耗太大。
另外递归栈也不好调试
这个top-down splay的方法消耗空间为O(1),带来的效果却和添加父节点类似,没有使用递归的方法。
至于具体的方法,在代码的注释里。
这里为了编代码方便就没有将treeNode 类中的成员变量私有化。
另外的BinaryTree的代码在以前的blog中。
这个splayTree还是较为完整的,至少比Apache中的splayTree完整些。现在我依旧不明白为什么Apache中的内存管理使用的是splayTree,而且splayTree还没有delete函数。难道内存管理的东西没有必要删除吗?
思考中....