浅谈 Splay
一、旋转(Zig-Zag)
1. 右旋(Right Rotation)
观察每个节点的变化,其中每个节点都有指向其父节点的指针没有画出。
①②③处节点连接有变化。
(1)Q 的左子树修改为 P 的右子树的内容
即
q->left = p->right;
p->right->father = q;
注意 P->right 节点)。
修改如下:
q->left = p->right;
if(p->right != NULL) p->right->father = q;
(2)P 的右子树修改为 Q ,且同时 Q 的父节点修改为 P 。
p->right = q;
q->father = p;
注意:
update(q); update(p); //先Q后P
(3)R 的子树应该修改为 P
需要判断
全局变量
特判
if(r == NULL) {
p->father = NULL; root = p; return;
}
if(q == r->left) {
r->left = p; p->father = r;
} else {
r->right = p; p->father = r;
}
整理一下,不管
p->father = r;
//记录树根
if(r == NULL) { root = p; return; }
//判断P连到R的那颗子树
if(q == r->left) r->left = p;
else r->right = p;
Code :
void right_rotate(node *p) {
node *q = p->father; //记录p的父节点
node *r = q->father; //记录p的父节点的父节点
//操作1
q->left = p->right;
if(p->right != NULL) p->right->father = q;
//操作2
p->right = q; q->father = p;
//维护节点信息(注意此处可暂不维护P)
update(q); //update(p);
//操作3
p->father = r;
if(r == NULL) { root = p; return; }
if(q == r->left) r->left = p;
else r->right = p;
}
2、左旋(Left Rotation)
同理右旋,只是①②不同。
Code :
void left_rotate(node *p) {
node *q = p->father; //记录p的父节点
node *r = q->father; //记录p的父节点的父节点
//操作1
q->right = p->left;
if(p->left != NULL) p->left->father = q;
//操作2
p->left = q; q->father = p;
//维护节点信息
update(q); //update(p);
//操作3
p->father = r;
if(r == NULL){ root = p; return; }
if(q == r->left) r->left = p;
else r->right = p;
}
3、双旋
不断旋转
定义:
(1)X 和 Y 同时是其父节点的左子树或者同时是各自父节点的右子树(即同侧)。
这时我们要进行两次旋转,先旋转
同左旋转演示图如下:
同右旋转演示图如下:
(2)X 和 Y 是其父节点的左、右子树,不同侧(即一左一右或一右一左)。
这时我们只要旋转两次