首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Splay tree 的兑现

2012-11-06 
Splay tree 的实现Splay tree 伸展树1.基本思想:把本次访问的结点通过一系列的旋转操作,变换为根结点,同时

Splay tree 的实现
Splay tree 伸展树

1.基本思想:把本次访问的结点通过一系列的旋转操作,变换为根结点,同时要保持树为二叉查找树(BST)。

2.旋转操作:Zig,Zag.(代码注释中有说明)

3.核心操作:Splay(伸展).

4.5个基本操作:

Find(x,&Spt); //查找操作,在Spt中查找值为x的元素,然后把x所在的结点变为Splay tree的根结点

Insert(x,&Spt);//在spt中插入值为x的结点,并把x所在的结点变为Splay tree的根结点

Delete(x,&Spt);//在spt中删除值为x的结点

Join(&s1,&s2);//合并s1,s2两棵Splay tree

Split(x,&s,&s1,&s2);//把值为 x的 结点左右子树分离成2个Splay tree(s1,s2)

5.实现:(参考LRJ的书)

5(1).需要用到的数据结构:

int right[].left[],next[],father[];

DataType data[];

5(2).说明:

right[p],left[p]记录的是结点p的右儿子和左儿子.

father[p]是p 的父亲结点.

next[] 是存放结点的表,手动实现内存分配.

data[p]对应p结点存放的数据.

5(3).实现代码:

#include<iostream>#include<queue>using namespace std;/**** author: yfr** date: 2012-1-10** project: splay tree** reference: LRJ's Book**/#define SIZE 100int Left[SIZE],Right[SIZE],father[SIZE],next[SIZE],data[SIZE];/**基本函数声明 **/void Init();int newnode(int d);void delnode(int p);//********************************void Zig(int &);void Zag(int &);void Splay(int &x,int &s);int BST_find(int x,int p);int SPT_find(int x,int &p);int BST_insert(int x,int &p);void SPT_insert(int x,int &p);void remove(int x,int &p);//********************************int findmax(int &s);int findmin(int &s);int join(int &s1,int &s2);void split(int x,int &s,int &s1,int &s2);//********************************/**       /                             \      p                              x     / \         Zig(x)             / \    x  <>   ----------------->     <>  p   / \                                / \  <> <>                              <> <>**///zig zag 函数 注意指针修改时要成对去修改 void Zig(int &x){     int p = father[x];     Left[p] = Right[x];     if(Right[x])//如果右子树存在      father[Right[x]] = p;      Right[x] = p;     father[x] = father[p];     father[p] = x;     //这步很关键!!      if(data[father[x]]>data[x])     Left[father[x]] = x;     else     Right[father[x]] = x;}/**       /                             \      x                              p     / \         Zag(x)             / \    p  <>   <-----------------     <>  x   / \                                / \  <> <>                              <> <>**/void Zag(int &x){     int p = father[x];     Right[p] = Left[x];     if(Left[x])//如果左子树存在      father[Left[x]] = p;     Left[x] = p;     father[x] = father[p];     father[p] = x;     //这步很关键!!      if(data[father[x]]>data[x])     Left[father[x]] = x;     else     Right[father[x]] = x;}//s是树根,x是待伸长的结点 void Splay(int &x,int &s){    int p;    while(father[x])    {       p = father[x];       if(!father[p])//如果p是根       {           if( x == Left[p])           Zig(x);           else if( x == Right[p])           Zag(x);       }        else//如果不是树根        {           int g = father[p];//祖先结点            if(Left[g]==p && Left[p]==x) //LL的情况           {               Zig(p);               Zig(x);           }           else if(Left[g]==p&&Right[p]==x) //LR的情况           {               Zag(x);               Zig(x);           }           else if(Right[g]==p&&Left[p]==x) //RL的情况           {               Zig(x);               Zag(x);           }           else if(Right[g]==p&&Right[p]==x) //RR的情况           {               Zag(p);               Zag(x);           }       }    }     s = x;//变为树根 }//初始化各容器 void Init(){     memset(Left,0,sizeof(Left));     memset(Right,0,sizeof(Right));     memset(father,0,sizeof(father));     for(int i=0;i<SIZE;i++)     next[i] = i+1;}//模拟内存分配函数 int newnode(int d){    int p = next[0];    next[0] = next[p];    data[p] = d;    return p;}void delnode(int p){     Left[p] = Right[p] = father[p] = 0;     next[p] = next[0];     next[0] = p;}//*********返回插入结点的编号,以便用来Splay**************//int BST_insert(int x,int &p){    if(!p){ p = newnode(x); return p;}    else if(x < data[p])    {         int q = BST_insert(x,Left[p]);         father[Left[p]] = p;//修改父亲指针          return q;    }    else if(x >= data[p])    {         int q = BST_insert(x,Right[p]);         father[Right[p]] = p;//修改父亲指针          return q;    }}//SPT的insert操作 void SPT_insert(int x,int &p){    int q = BST_insert(x,p);    Splay(q,p);//伸展 }int BST_find(int x,int p){    if(!p)return 0;//空树    if(x == data[p]) return p;    else if(x < data[p]) return BST_find(x,Left[p]);    else return BST_find(x,Right[p]); }int SPT_find(int x,int &s){    int q = BST_find(x,s);    if(q)//如果查找成功     Splay(q,s);    return q;}int findmax(int &s){      int p = s;      while(Right[p]) p = Right[p];      Splay(p,s);      return p;}int findmin(int &s){      int p = s;      while(Left[p]) p = Left[p];      Splay(p,s);      return p;}/*******************************************************/int join(int &s1,int &s2){    father[s1] = father[s2] = 0;//断开与公共先祖结点的连接 ,此步很关键     if(!s1) return s2;    if(!s2) return s1;    int q = findmax(s1);    Right[s1] = s2;    father[s2] = s1;    return s1;}void split(int x,int &s,int &s1,int &s2){     int p = SPT_find(x,s);     s1 = Left[p];     s2 = Right[p];}void remove(int x,int &p){     int q = SPT_find(x,p);     if(q){//如果找到了x      int temp = p;     p = join(Left[p],Right[p]);     delnode(temp);     }}/****************************************************************///辅助函数 void order(int p){   if(!p)return;   order(Left[p]);   cout<<data[p]<<endl;   order(Right[p]);}void bfs(int p){   if(!p)return;   queue<int> q;   q.push(p);   while(!q.empty())   {      int v = q.front();      q.pop();      if(Left[v]) q.push(Left[v]);      if(Right[v]) q.push(Right[v]);      cout<<data[v]<<endl;   }}int main(){    freopen("dataout.txt","w",stdout);    Init();    int ROOT = 0;    SPT_insert(12,ROOT);//build SPT    SPT_insert(8,ROOT);    SPT_insert(2,ROOT);    SPT_insert(7,ROOT);    SPT_insert(13,ROOT);    remove(13,ROOT);    order(ROOT);    cout<<"--------------"<<endl;    bfs(ROOT);    cout<<"-----------"<<endl;    cout<<father[ROOT]<<endl;    cout<<"------------"<<endl;    int s1,s2;    split(7,ROOT,s1,s2);    bfs(s1);    cout<<"---------"<<endl;    bfs(s2);    return 0;}

热点排行