SplayTree伸展树的非递归实现(自底向上)

Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得Splay Tree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的期望的时间复杂度还是O(nlogn)的。

下图是对伸展树查询节点1和删除节点6的结果,利用我的伸展树来实现

 

  1 头文件————————————————————————————
  2 #ifndef _SPLAY_TREE_H_
  3 #define _SPLAY_TREE_H_
  4 
  5 #include <iostream>
  6 #include <iomanip>
  7 #include <cassert>
  8 #include <stack>
  9 
 10 typedef struct splay_tree_node_t
 11 {
 12      int data;
 13      struct splay_tree_node_t *left;
 14      struct splay_tree_node_t *right;
 15 } splay_tree_node, *position, *splay_tree;
 16 
 17 void print_splay_tree(splay_tree st, int depth, int ctrl);//ctrl:0=root 1=left 2=right
 18 position find_max(splay_tree st);
 19 void insert_splay_tree(splay_tree *pst, int x);
 20 void delete_splay_tree(splay_tree *pst, int x);
 21 int find_splay_tree(splay_tree *pst, int x);
 22 
 23 splay_tree rotate3(position child, position parent, position grand_parent, int *type);
 24 splay_tree rotate2(position child, position parent);
 25 
 26 inline void fcn(int type, position cur, position parent, position grand_parent);
 27 #endif
 28 
 29 源文件——————————————————————————————
 30 #include "./SplayTree.h"
 31 
 32 splay_tree rotate3(position child, position parent, position grand_parent, int *type)
 33 {
 34      assert(child != NULL && parent != NULL && grand_parent != NULL);
 35 
 36      if(parent->left == child && grand_parent->left == parent)//child, parent, grand_parent一字形东北方向 0
 37      {
 38           *type = 0;
 39           grand_parent->left = parent->right;
 40           parent->right = grand_parent;
 41 
 42           parent->left = child->right;
 43           child->right = parent;
 44      }
 45      else if(parent->right == child && grand_parent->right == parent)//child, parent, grand_parent一字形西北方向 1
 46      {
 47           *type = 1;
 48           grand_parent->right = parent->left;
 49           parent->left = grand_parent;
 50 
 51           parent->right = child->left;
 52           child->left = parent;
 53      }
 54      else if(parent->right == child && grand_parent->left == parent)//child, parent, grand_parent之字形<
 55      {
 56           *type = 2;
 57           grand_parent->left = child->right;
 58           parent->right = child->left;
 59           child->left = parent;
 60           child->right = grand_parent;
 61      }
 62      else if(parent->left == child && grand_parent->right == parent)//child, parent, grand_parent之字形>
 63      {
 64           *type = 3;
 65           grand_parent->right = child->left;
 66           parent->left = child->right;
 67           child->right = parent;
 68           child->left - grand_parent;
 69      }
 70 
 71      return child;
 72 }
 73 splay_tree rotate2(position child, position parent)
 74 {
 75      assert(child != NULL && parent != NULL);
 76      if(parent->left == child)
 77      {
 78           parent->left = child->right;
 79           child->right = parent;
 80      }
 81      else//parent->right == child
 82      {
 83           parent->right = child->left;
 84           child->left = parent;
 85      }
 86      return child;
 87 }
 88 
 89 position find_max(splay_tree st)
 90 {
 91      while(NULL != st && NULL != st->right)
 92           st = st->right;
 93      return st;
 94 }
 95 
 96 void print_splay_tree(splay_tree st, int depth, int ctrl)
 97 {
 98      if(NULL != st)
 99      {
100           std::cout<<std::setw(depth);
101           if(0 == ctrl)
102                std::cout<<"root:";
103           else if(1 == ctrl)
104                std::cout<<"left";
105           else if(2 == ctrl)
106                std::cout<<"right";
107           std::cout<<st->data<<std::endl;
108           print_splay_tree(st->left, depth+6, 1);
109           print_splay_tree(st->right, depth+6, 2);
110      }
111 }
112 void insert_splay_tree(splay_tree *pst, int x)
113 {
114      if(NULL == *pst)
115      {
116           position tmp = new splay_tree_node;
117           if(NULL == tmp)
118                return ;
119           tmp->data = x;
120           tmp->left = tmp->right = NULL;
121           *pst = tmp;
122      }
123      else if(x < (*pst)->data)
124           insert_splay_tree(&((*pst)->left), x);
125      else if(x > (*pst)->data)
126           insert_splay_tree(&((*pst)->right), x);
127      else
128           return ;
129 }
130 void delete_splay_tree(splay_tree *pst, int x)
131 {
132      assert(NULL != pst);
133      int res = find_splay_tree(pst, x);
134      if(res == 0)//not found
135           return ;
136      //此时root指向的就是要删除的节点,因为find_splay_tree操作将节点推至向根
137      position root = *pst;
138      splay_tree splay_left = root->left;
139      splay_tree splay_right = root->right;
140      position tmp = find_max(splay_left);
141      if(NULL == tmp)//无左子树
142           *pst = splay_right;//将右子树为新树
143      else
144      {
145           find_splay_tree(&splay_left, tmp->data);
146           splay_left->right = splay_right;//将右子树为左子树的新右子树
147           *pst = splay_left;//将左子树为新树
148      }
149 }
150 int find_splay_tree(splay_tree *pst, int x)
151 {
152      assert(NULL != pst);
153      position cur = *pst;
154      std::stack<position> s;
155 
156      while(cur != NULL && cur->data != x)//沿着查找路径将树节点以此压入栈中
157      {
158           if(x < cur->data)
159           {
160                s.push(cur);
161                cur = cur->left;
162           }
163           else
164           {
165                s.push(cur);
166                cur = cur->right;
167           }
168      }
169 
170      if(NULL == cur)//not found
171           return false;
172 
173      position parent, grand_parent;
174      int type = -1;//0一字形东北方向; 1一字形西北方向; 2之字形<; 3之字形<
175      //每次取父节点和祖父节点和当前节点进行伸展调节
176      while(s.size() >= 2)
177      {
178           parent = s.top();
179           s.pop();
180           //fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展
181           fcn(type, cur, parent, grand_parent);
182           grand_parent = s.top();
183           s.pop();
184           cur = rotate3(cur, parent, grand_parent, &type);//after rotate, cur is the new "root"
185      }
186      if(s.empty())
187           *pst = cur;
188      else //rotate cur and the old root
189      {
190           parent = s.top();
191           s.pop();
192           fcn(type, cur, parent, grand_parent);
193           //此时只对cur和根节点进行伸展,完成后find_splay_tree函数结束
194           *pst = rotate2(cur, parent);
195      }
196 
197      return true;
198 }
199 
200 //fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展
201 inline void fcn(int type, position cur, position parent, position grand_parent)
202 {
203      if(type == 0)
204           {
205                if(grand_parent == parent->left)
206                     parent->left = cur;
207                else if(grand_parent == parent->right)
208                     parent->right = cur;
209           }
210           else if(type == 1)
211           {
212                if(grand_parent == parent->left)
213                     parent->left = cur;
214                else if(grand_parent == parent->right)
215                     parent->right = cur;
216           }
217           else if(type == 2)
218           {
219                if(grand_parent == parent->left)
220                     parent->left = cur;
221                else if(grand_parent == parent->right)
222                     parent->right = cur;
223           }
224           else if(type == 3)
225           {
226                if(grand_parent == parent->left)
227                     parent->left = cur;
228                else if(grand_parent == parent->right)
229                     parent->right = cur;
230           }
231 }

 

posted @ 2013-08-12 13:33  老司机  阅读(711)  评论(0编辑  收藏  举报