自调整树
首先我们要明确的是二叉搜索树的作用是什么?
二叉搜索树,平衡树都是为了快速的查找,插入与删除,在这期间我们都可能要进行树的重新构建,这中极其的消耗空间与时间,或许我们还有其它的办法,是的,我们可以根据访问的概率来进行自调整树算法。
在自调整树中,有两种情况。
1)单一旋转,当访问孩子节点的时候,进行与父节点的旋转
2)重复进行孩子-父亲旋转,一直到被访问的元素位于根部。
现在针对移动到根部,进行修改的版本为“倾斜策略”,在之前的版本中是直接的从孩子节点向父节点进行不断的旋转,那么在新策略下面,我们同样的分3种情况来
我们用Q代表当前节点,P代表父亲节点,G代表祖父节点
1)若节点的父亲是根节点,那么直接的进行旋转OK
2)若是同构的情况:(1)Q为P的左子树,P为G的左子树
(2)或者另一种情况:Q为P的右子树,P为G的右子树
那么这种情形下,假如(1),则先对P围绕着G进行右旋转,再对Q围绕P进行右旋转。(2)的情况正好相反
3)若是异构:Q为P的左子树,P为G的右子树。那么先对Q围绕P进行右旋转,此时P为Q的孩子节点。再对G进行一次左旋。另一种情况:Q为P的右子树,P为G的左子树则正好相反。
倾斜策略是一种集中关注与元素而不是树的形状,但是如果靠近跟的元素访问的次数比较多,那么我们考虑的不是访问的概率,而是平衡。于是急需对平衡策略进行修改。
产生了半倾斜策略:
它对于同构倾斜只需要进行一次旋转,并将继续对被访问节点的父亲节点进行倾斜,而不是对节点自身进行倾斜。那么最后元素不一定位于根节点。
template<class T>//半倾斜策略,5种情形
void SplayTree::semisplay(SplayingNode<T>*p)
{
while(p!=root)
{
if (p->parent->parent==0)//若找寻的节点的父节点为根节点
{
if (p->parent->left=p)//为左子树
{
rotateR(p);//右旋转
}
else
rotateL(p);//左旋转
}
else if (p->parent->left==p)//若父节点不是根节点,且为父节点的左节点
{
if (p->parent->parent->left==p->parent)//若父节点是祖父节点的左子树
{
rotateR(p->parent);//右旋转父节点,同构的情况
p=p->parent;
}
else
{
rotateR(p);//当父节点为祖父节点的有节点时,即异构
rotateL(p);//左旋
}
}
else
{
if (p->parent->parent->right==p->parent)
{
rotateL(p->parent);//左旋父节点,只对父节点进行倾斜
p=p->parent;
}
else
{
rotateL(p);//若父节点不为根节点,且为父节点的右子树,且父节点为祖父节点的左子树
rotateR(p);//左旋再右旋
}
if (root==0)
{
root=p;
}
}
}
}