编程练习——伸展树(SplayTree)

来源:互联网 发布:python wave 编辑:程序博客网 时间:2024/05/18 13:42
伸展树用于查询结果的概率非平均情况,即起初假设某些要查询的信息偏多,有些信息几乎无人问津。对于平均访问概率来说,使用SplayTree实现并不是一个明智的选择。
可能会用到此数据结构的程序:词典或者多维搜索树,还有连接/切除树(link/cut tree)(这个树是用于网络优化问题包括最大流和最小代价)
  1. /*
  2. * create by chico chen
  3. * date: 2008/10/02
  4. */
  5. template<class T>
  6. class SplayTree:public BinaryTree<T>
  7. {
  8. public:
  9.     explicit SplayTree(T& data):BinaryTree(data)
  10.     {
  11.     
  12.     }
  13.     explicit SplayTree(TreeNode<T>* root):BinaryTree(root)
  14.     {
  15.     }
  16.     ~SplayTree()
  17.     {
  18.         
  19.     }
  20. public:
  21.     void insertNode(T& data)
  22.     {
  23.         
  24.         if(NULL == this->head)
  25.         {
  26.             this->head = new TreeNode<T>(data);
  27.             return;
  28.         }
  29.         
  30.         splay(this->head,data);
  31.         if(this->head->data > data)
  32.         {
  33.             //     A     B                 A
  34.             //            / /     ->         / /
  35.             //         C   D             C   B
  36.             //                                /
  37.             //                                 D
  38.             TreeNode<T>* node = new TreeNode<T>(data);
  39.             node->left = this->head->left ;
  40.             node->right = this->head;
  41.             this->head->left = NULL;
  42.             this->head = node;
  43.         }
  44.         else if(this->head->data < data)
  45.         {
  46.             //     A     B                 A
  47.             //            / /     ->         / /
  48.             //         C   D             B   D
  49.             //                              /     
  50.             //                            C        
  51.             TreeNode<T>* node = new TreeNode<T>(data);
  52.             node->right = this->head->right;
  53.             node->left = this->head;
  54.             this->head->right = NULL;
  55.             this->head = node;
  56.         }
  57.         else
  58.         {
  59.             // insert the same key
  60.             // throw exception
  61.             throw "the same key";
  62.         }
  63.     }
  64.     // use the data as key to splay the tree
  65.     // then we can get the structures of the tree like the following:
  66.     //     (1)  A             (2)   A
  67.     //              /                    / /
  68.     //               B               C   B
  69.     // the difference between the two structures is whether the root has left child
  70.     // In case (1), we can simpliy make the root right child instead the root.
  71.     // In case (2), we should splay the root left subtree and then it will be 
  72.     // changed like case (1), and we make the splayed left subtree root instead  
  73.     // the root.
  74.     void deleteNode(T& data)
  75.     {
  76.         
  77.         if(NULL == this->head)
  78.         {
  79.             return;
  80.         }
  81.         splay(this->head, data);
  82.         if(this->head->data != data)
  83.         {
  84.             // not found the key to delete
  85.             return;
  86.         }
  87.         TreeNode<T>* newRoot;
  88.         if(NULL == this->head->left)
  89.         {
  90.             newRoot = this->head->right;
  91.         }
  92.         else
  93.         {
  94.             newRoot = this->head->left;
  95.             splay(newRoot,data);
  96.             newRoot->right = this->head->right;
  97.         }
  98.         delete this->head;
  99.         this->head = newRoot;
  100.     }
  101.     
  102.     TreeNode<T>* searchNode(T& data)
  103.     {
  104.         if(NULL == this->head)
  105.         {
  106.             return NULL;
  107.         }
  108.         splay(this->head, data);
  109.         if(this->head->data == data)
  110.         {
  111.             return this->head;
  112.         }
  113.         return NULL;
  114.     }
  115. private:
  116.     // use top-down splay method,
  117.   
  118.     // you should make the suitable final step 
  119.     // according to the situation, such as "insert", "delete", "search".
  120.     // And what's the top-down method?
  121.     // now we should add LeftMaxRoot as L and RightMinRoot as R
  122.     // 1. L  A  R         2. L  A  R        3. L   A   R
  123.     //         /                        /                      /
  124.     //        B                     B                     B
  125.     //                               /                          /
  126.     //                              C                          C
  127.     // 
  128.     // 1.->L  B  R      2.->L  C   R        3.L   C    R
  129.     //        /                     /                          /      /      
  130.     //     A                    B                         B    A
  131.     //                             / 
  132.     //                              A
  133.     // but in case 3. we can simplified case 3 rotate as
  134.     // 3. L   B      R
  135.     //            /      /
  136.     //            C  A
  137.     // and we must integrate the LeftMaxRoot and RightMinRoot together,
  138.     // then we have final step to do this. And L is left tree, and R is right tree.
  139.     // L     A     R               A       
  140.     //         / /         ->         /   /
  141.     //       B   C                L     R
  142.     //                                 /   /
  143.     //                                B C
  144.     void splay(TreeNode<T>* &subRoot,T& data)
  145.     {
  146.         if(NULL == subRoot)
  147.         {
  148.             return;
  149.         }
  150.         TreeNode<T>* leftRoot;
  151.         TreeNode<T>* rightRoot;
  152.         // here some code use static member, if you promise you have sync-control
  153.         // or you don't use this code in thread or process, you could choose static
  154.         // member to accelerate your program.
  155.         // It means the following code is thread-safe.
  156.         TreeNode<T> head(data); 
  157.         leftRoot = rightRoot = &head;
  158.         while(true)
  159.         {
  160.             if(data < subRoot->data)
  161.             {
  162.                 if(NULL == subRoot->left)
  163.                 {
  164.                     break;
  165.                 }
  166.                 else if(data < subRoot->left->data)
  167.                 {
  168.                     // Left rotate
  169.                     TreeNode<T>* tempLeft = subRoot->left;
  170.                     subRoot->left = tempLeft->right;
  171.                     tempLeft->right = subRoot;
  172.                     subRoot = tempLeft;
  173.                 }
  174.                 else
  175.                 {
  176.                     // do nothing
  177.                 }
  178.                 // split the tree with right root
  179.                 if(NULL == subRoot->left)
  180.                     break;
  181.                 rightRoot->left = subRoot;
  182.                 rightRoot = subRoot;
  183.                 subRoot = subRoot->left ;
  184.             }
  185.             else if(data > subRoot->data)
  186.             {
  187.                 if(NULL == subRoot->right)
  188.                 {
  189.                     // need not to rotate
  190.                     break;
  191.                 }
  192.                 else if(data > subRoot->right->data)
  193.                 {
  194.                     // right rotate
  195.                     TreeNode<T>* tempRight = subRoot->right;
  196.                     subRoot->right = tempRight->left;
  197.                     tempRight->left = subRoot;
  198.                     subRoot = tempRight;
  199.                 }
  200.                 else
  201.                 {
  202.                     // do nothing
  203.                 }
  204.                 // split the tree by left root
  205.                 if(NULL == subRoot->right)
  206.                     break;
  207.                 leftRoot->right = subRoot;
  208.                 leftRoot = subRoot;
  209.                 subRoot = subRoot->right;
  210.             }
  211.             else
  212.             {
  213.                 // the same key
  214.                 break;
  215.             }
  216.         }
  217.         // the final step 
  218.         // we have find the last node, ant then we should 
  219.         // integrate the left root, the right root and the root into One tree.
  220.         // head.right is left root
  221.         // head.left is right root
  222.         leftRoot->right = subRoot->left;
  223.         rightRoot->left = subRoot->right;
  224.         subRoot->left = head.right;
  225.         subRoot->right = head.left;
  226.     
  227.         
  228.     }
  229. };

 

发现CSDN的代码编辑器还是有些问题,空格处理不好,导致我注释中的树形错乱了...

不过没有大关系,应该抓起旁边的纸边看边画就能明白。

在网上找splayTree的源码学习,发现凭自己的实力还真的看不懂.....

幸好在家里翻到了古老的数据结构教材。这才明白。

至于不使用添加父节点或者采用递归栈等方式的原因在于:空间消耗太大。

另外递归栈也不好调试

这个top-down splay的方法消耗空间为O(1),带来的效果却和添加父节点类似,没有使用递归的方法。

至于具体的方法,在代码的注释里。

这里为了编代码方便就没有将treeNode 类中的成员变量私有化。

另外的BinaryTree的代码在以前的blog中

这个splayTree还是较为完整的,至少比Apache中的splayTree完整些。现在我依旧不明白为什么Apache中的内存管理使用的是splayTree,而且splayTree还没有delete函数。难道内存管理的东西没有必要删除吗?

思考中....

原创粉丝点击