数据结构与算法11: 伸展树(SplayTree)

写在前面
前面介绍的DSW在全局构建平衡二叉树,AVL在局部构建平衡二叉树,这些工作是否总是必要? 二叉搜索树执行快速的插入、搜索以及删除元素才是关键,而不是树的形状。因此,伸展树它按照访问的情况来调整树,通常它不是平衡的二叉搜索树。Splay Tree由贝尔实验室的Daniel Dominic Sleator 和Robert Endre Tarjan 于1985发明. 伸展树所有操作平均时间复杂度为O(log n),最坏情况下均摊时间复杂度为O(log n)。本节总结和实现伸展树的基本操作。

1.基本的splaying操作

在普通二叉搜索树的操作基础上,Splay Tree加上了 一个Splaying操作。对一个节点进行Splaying操作,总是将其调整到根部,这一动作是伸展树中的基本操作。将一个节点x调整至根部分为三种情况,分别总结如下。

case 1 : x没有祖父节点(zig操作)

实现为:

void SplayTree::zig(BSTNode * x) {
    BSTNode * p = x->parent;
    if(x == p->left)     {  // 右旋转
        std::cout << "right rotate: "<<p->key<<std::endl;
        BST::rightRotate(p);
    }
    else {  // 左旋转
        std::cout << "left rotate: "<<p->key<<std::endl;
        BST::leftRotate(p);
    }
}

case 2: x的父节点和祖父节点异构(zig-zag操作)

实现为:

void SplayTree::zigZag(BSTNode * x) {
    BSTNode*  p = x->parent, *g = x->parent->parent;
    BSTNode* gg = g->parent;
    if(x == p->right) {     // LR
std::cout << "left-then-right rotate: "<<g->key<<std::endl;
        BST::leftRotate(p);
        BST::rightRotate(g);
    }else {     // RL
std::cout << "right-then-left rotate: "<<g->key<<std::endl;
        BST::rightRotate(p);
        BST::leftRotate(g);
    }
    if(gg == 0)
        root->height = calcHeight(root);
    else
        gg->height = calcHeight(gg);
}

case 3: x的父节点和祖父节点同构(zig-zig操作)


实现为:

void SplayTree::zigZig(BSTNode * x) {
        BSTNode *p = x->parent, *g = x->parent->parent;
        BSTNode *gg = g->parent;
        if(x == p->left && p == g->left) {      // LL
            std::cout << "right-then-right rotate: "<<g->key<<std::endl;
            BST::rightRotate(g);
            BST::rightRotate(p);
        }else {             // RR
            std::cout << "left-then-left rotate: "<<g->key<<std::endl;
            BST::leftRotate(g);
            BST::leftRotate(p);
        }
        if(gg == 0)
            root->height = calcHeight(root);
        else
            gg->height = calcHeight(gg);
}

splay操作就是将一个节点调整为根节点的过程,实现为:

/** * 对结点x进行伸展操作 也就是将x调整至根部作为新的根节点 */
void SplayTree::splay(BSTNode* x) {
    if(x == 0) return;
    while(x->parent != 0) {
        if(x->parent == root)   // x没有祖父节点
            zig(x);
        else if( (x == x->parent->left && x->parent == x->parent->parent->left )
                || (x == x->parent->right && x->parent == x->parent->parent->right) )   // 同构配置
            zigZig(x);
        else        // 异构配置
            zigZag(x);
    }
}

2.搜索、插入以及删除时的调整动作

对于SplayTree在搜索、插入以及删除时一般都执行调整动作,具体为:
(1)查找键k ,如果键k存在则splay(k)
(2)插入键k, 则splay(k)
(3)删除键k,如果键k存在,使用复制删除,然后调整实际删除节点的父节点为新的根

在哪个元素上执行调整动作还可以有更细致的定义,具体可以参见: Splay trees)

查找操作实现为:

/** * 查找元素e * 存在包含e的结点 则返回包含e的节点指针,并且将e调为新的根 * 否则返回0 */
BSTNode* SplayTree::search(const int& e)  {
    BSTNode *prev = 0;
    BSTNode *current = BST::iterativeSearch(e,prev);
    if(current != 0) {
        splay(current);  // 调整查找到的节点
    }
    return current;
}

插入操作实现:
在BST的插入的基础上进行调整,假设插入位置的父节点为prev,则插入后调整实现为:

/** * 插入节点后调整动作 * prev指向插入位置的父节点 * 如果插入节点不是根节点,则调整至根节点 */
void SplayTree::insertAdjust(BSTNode* prev,const int&e) {
    if(prev == 0)
        return;
    else if(e < prev->key)
        splay(prev->left);
    else
        splay(prev->right);
}

删除操作实现:
在BST删除操作的基础上进行调整,假设实际删除节点的父节点为prev,则调整动作为:

/** * 删除结点后调整动作 * prev指向实际删除节点的父节点 * 将prev节点调整至根节点 */
void SplayTree::removeAdjust(BSTNode* prev,const int&e) {
    if(prev != 0)
        splay(prev);
}

下面给出一个实际例子。给定
插入数据为: int insertEle[] = {44,55,66,77,88,99};
查找数据为: int searchEle[] = {44,66,88};
删除数据为: int removeEle[] = {55,88};
按照插入、查找和删除的顺序执行,则整个过程如下图所示(由于完成所有操作共33步,因此下图中有省略):

这里写图片描述
数据结构与算法11: 伸展树(SplayTree)_第1张图片
数据结构与算法11: 伸展树(SplayTree)_第2张图片
数据结构与算法11: 伸展树(SplayTree)_第3张图片

省略中间的插入过程,插入99时旋转88,则最后得到的插入完的伸展树为:
数据结构与算法11: 伸展树(SplayTree)_第4张图片
数据结构与算法11: 伸展树(SplayTree)_第5张图片

查找44的过程中,将44调至根部的过程如下所示:
数据结构与算法11: 伸展树(SplayTree)_第6张图片
数据结构与算法11: 伸展树(SplayTree)_第7张图片
数据结构与算法11: 伸展树(SplayTree)_第8张图片
数据结构与算法11: 伸展树(SplayTree)_第9张图片
数据结构与算法11: 伸展树(SplayTree)_第10张图片
数据结构与算法11: 伸展树(SplayTree)_第11张图片

至此,节点44被调整至根部。

删除节点的情况,例如删除55和88的过程如下图所示:
数据结构与算法11: 伸展树(SplayTree)_第12张图片
数据结构与算法11: 伸展树(SplayTree)_第13张图片
数据结构与算法11: 伸展树(SplayTree)_第14张图片
数据结构与算法11: 伸展树(SplayTree)_第15张图片
数据结构与算法11: 伸展树(SplayTree)_第16张图片
数据结构与算法11: 伸展树(SplayTree)_第17张图片
数据结构与算法11: 伸展树(SplayTree)_第18张图片

你可能感兴趣的:(数据结构)