中根遍历二叉查找树所得序列一定是有序序列_树表查找:二叉排序树、DSW算法、平衡二叉树、自适应树

902ba0ac2a369fac83e2c33012e3f425.png

前言

以树为查找表,则称树表(Tree Table)。 本文中的描述与代码实现,默认为升序查找或遍历。

二叉排序树

二叉排序树(Binary Search Tree),也称二叉搜索树。 二叉排序树有三项规则: 1. 一个结点的关键字,大于左子树上所有结点的关键字。 2. 一个结点的关键字,小于右子树上所有结点的关键字。 3. 左子树和右子树也是二叉排序树。

这样一来,二叉排序树中结点的位置就有了一定的顺序,便于查找。

二叉排序树不是给个Sort方法,然后用户调用它就能把这个二叉树有序化。 而当增加元素的时候,就需要将新建结点在合适的位置插入, 这也是为什么Binary Search Tree在这里译为二叉排序树而不是二叉搜索树。

PS:根据三项规则,不难得知,将二叉排序树中序遍历,可得到一个升序有序序列。

删除操作

增加和查找没什么好说的,递归就是了,看看代码也能懂。

删除操作值得说一下, 首先查找到关键字相符合的结点,将它记为t。

  • 若t是叶子结点,则直接删除。
  • 若t有左子树无右子树,则以左子结点代替t与t的父结点相连,然后删去t。
  • 若t有右子树无左子树,则以右子结点代替t与t的父结点相连,然后删去t。
  • 若t既有左子树又有右子树呢? 你可以把两个子树的结点的关键字都记录下来, 之后删除t, 然后再将刚才记录下来的关键字一个个重新添加进去。 不过这样很麻烦,我并不推荐。

假如有这样一个二叉排序树。

6572d5d52b8a242368f1038de01dc982.png

现在我要删除4,4既有左子树又有右子树。 将其中序遍历,得到的序列为1234567.。 如果4消失的话,新序列就是123567

如果靠删除4,重新添加其他元素得到新序列, 那还不如重新造一个二叉排序树好了。

不如将4结点的关键字改为原序列前一个的3,然后把3结点删了。 这样中序遍历出的新序列,仍然是123567。 或者将4结点的关键字改为原序列后一个的5,然后把5结点删了,新序列也一样。 这两种方法效率更高,而且不会改变原二叉排序树的顺序。

8b1123d3912b60c0547c0691aa26c601.png

而4结点序列前的3,是左子树中的最大值结点, 序列后的5,是右子树中的最小值结点。

总而言之,直接删除本结点, 不如使本结点的值改为左子树中的最大值,而后删除左子树中的最大值结点, 或者使本结点的值改为右子树中的最小值,而后删除右子树中的最小值结点, 其原理为中序前驱替代被删结点而被删, 或中序后继替代被删结点而被删。

删除操作的改进

刚才我们得出结论, 在t既有左子树又有右子树的情况删除t, 可以去删除左子树中的最大值结点或者右子树中的最小值结点。

但是这样就会出现问题。 假如我们选择去删除左子树中的最大值结点, 那么在多次删除操作之后,右子树就会相对于左子树越来越大。 这样就会越来越不平衡。 一个二叉排序树经过多次增加和删除之后, 由于它的结构不平衡,它的查找效率将大大降低。 (为什么结构不平衡就会降低查找效率?实现代码之后有讲。)

那么我们就需要改进删除操作。 我们不是去删除左子树中的最大值结点或者右子树中的最小值结点, 而是既可能去删除左子树中的最大值结点,又可能去删除右子树中的最小值结点。 只要左子树高度更高,就去删除左子树中的最大值结点, 反之,则去删除右子树中的最小值结点。

效率

二叉排序树的效率不是固定的。 假设一个二叉排序树包含七个元素:1234567 那么它的最好情况就是左右排布的最均衡的情况。

6572d5d52b8a242368f1038de01dc982.png

这时找一个元素不会超过3次比对,这种情况时间复杂度为

最坏的情况就是单支树。

d13adf7410d4888896f6843837668af8.png
右单只树

时间复杂度为

用它那跟顺序查找没区别。

那么可不可以将它调整为最均衡的情况呢?

DSW算法

Colin Day曾经提出了一个简洁的算法,用于将二叉排序树调整至最均衡的情况。 后来Quentin F.Stout与Bette L.Warren对此算法进行了改进。 所以这个算法称为DSW算法。

在了解DSW算法之前,需要知道左旋操作与右旋操作。

右旋操作

3c2b0f636b28339d0a9be193b3acdb27.png

例图中,A结点与B结点垂直直线连接, 它表示B结点是A结点的子结点,至于是左子结点还是右子结点,无所谓,都可以。

我们要做的,就是将B与C两个结点右旋,也称作将C围绕着B右旋。 步骤如下: 1. B结点接管C结点的右子结点α作为左子结点 2. B结点成为C结点的右子结点 3. C结点与B结点的父结点A确认父子关系。

这样一来,C结点不是B结点的左子结点,而是替代了B结点的位置, 而B结点则成了C结点的右子结点, 看起来就是将它们右旋,也就是顺时针旋转了。

我们可以将右旋前后两个子树都进行中序遍历, 可以发现得到的序列都一样。 无论是左旋还是右旋,目的都是将二叉排序树的结构调整至更合理的状态。 所以它们绝不会改变中序遍历的先后顺序, 否则将会得到一个与原二叉树不同的新二叉树,这样就没有意义了。

我们在忘记左旋右旋怎么旋的时候,不妨先自己推导一下子树的中序遍历序列, 由此推出操作的步骤。

左旋操作

cfdc59ee03bb4e32c26250b5a9d8f776.png

左旋操作与右旋操作对称,故不再赘述。

算法步骤

首先,无论这个二叉排序树是什么结构, 给每个带有左子结点的结点进行右旋,使之成为右单支树。

这里我将右旋操作的函数设置成了递归函数, 这样就可以从Root开始, 将每个带有左子结点的结点进行右旋。

template<typename ElementType>
void BinarySearchTree<ElementType>::ClockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    //Recursion
    if (!nodeB)
        return;
    else if (nodeB->LChild)
    {
        BinarySearchNode<ElementType>* leftChildOfNodeB = nodeB->LChild;
        BinarySearchNode<ElementType>* rightChildOfLeftChildOfNodeB = leftChildOfNodeB->RChild;
        nodeB->LChild = rightChildOfLeftChildOfNodeB;
        if (rightChildOfLeftChildOfNodeB)
            rightChildOfLeftChildOfNodeB->Parent = nodeB;
        leftChildOfNodeB->RChild = nodeB;
        leftChildOfNodeB->Parent = nodeB->Parent;
        nodeB->Parent = leftChildOfNodeB;
        nodeB = leftChildOfNodeB;
    }
    if (nodeB->LChild)
        ClockwiseRotate(nodeB);
    else
        ClockwiseRotate(nodeB->RChild);
}

当转化成为右单支树之后, 再将这个最不平衡的右单支树调整至最均衡的情况。

我们记录当前结点数,记为n。 因为是右单支树,所以层数/高度也是n。 当调整至最均衡的情况时, 它的层数应该是

那么,这些多出来的层需要单独左旋处理。

最后,将剩下的

层进行左旋处理。

具体见类实现代码。 顺便说一句,在DSW算法中,左旋与右旋的次数为

,所以DSW所需要的时间是很理想的。

实现代码

BinarySearchNode.hpp:

#pragma once
template<typename ElementType>
class BinarySearchNode
{
public:
    ElementType Data;
    BinarySearchNode* Parent = nullptr;
    BinarySearchNode* LChild = nullptr;
    BinarySearchNode* RChild = nullptr;
    BinarySearchNode(ElementType data)
    {
        Data = data;
    }
};

BinarySearchTree.hpp:

#pragma once
#include <vector>
#include <initializer_list>
#include "BinarySearchNode.hpp"
template<typename ElementType>
class BinarySearchTree
{
private:
    BinarySearchNode<ElementType>* Root = nullptr;
public:
    BinarySearchTree() {}
    BinarySearchTree(const std::initializer_list<ElementType>& elements);
    BinarySearchTree(const BinarySearchTree& otherBST);
    ~BinarySearchTree();
    //If success, it will return true.
    bool Insert(ElementType value);
    bool IsIn(ElementType value);
    void Delete(ElementType value);
    std::vector<ElementType*> MiddleTraversal();
    size_t GetHeight();
    void DSW();
private:
    void Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode);
    void Purge(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>* DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value);
    BinarySearchNode<ElementType>* DoFind(BinarySearchNode<ElementType>* node, ElementType value);
    size_t GetHeight(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>*& GetLCMax(BinarySearchNode<ElementType>*& node);
    BinarySearchNode<ElementType>*& GetRCMin(BinarySearchNode<ElementType>*& node);
    void DoDelete(BinarySearchNode<ElementType>*& node);
    void DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence);
    void ClockwiseRotate(BinarySearchNode<ElementType>*& nodeB);
    void CounterclockwiseRotate(BinarySearchNode<ElementType>* nodeB);
    void TransformSingleBranchToBalancedTree();
};

template<typename ElementType>
BinarySearchTree<ElementType>::BinarySearchTree(const std::initializer_list<ElementType>& elements)
{
    for (ElementType i : elements)
        DoInsert(Root, i);
}
template<typename ElementType>
BinarySearchTree<ElementType>::BinarySearchTree(const BinarySearchTree& otherBST)
{
    Copy(Root, otherBST.Root);
}
template<typename ElementType>
BinarySearchTree<ElementType>::~BinarySearchTree()
{
    Purge(Root);
}
template<typename ElementType>
bool BinarySearchTree<ElementType>::Insert(ElementType value)
{
    BinarySearchNode<ElementType>* node = DoInsert(Root, value);
    return (!node) ? false : true;
}
template<typename ElementType>
bool BinarySearchTree<ElementType>::IsIn(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    return (!temp) ? false : true;
}
template<typename ElementType>
void BinarySearchTree<ElementType>::Delete(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    if (!temp)
        return;
    if (temp == Root)
        DoDelete(Root);
    else if (temp->Parent->LChild == temp)
        DoDelete(temp->Parent->LChild);
    else
        DoDelete(temp->Parent->RChild);
}
template<typename ElementType>
std::vector<ElementType*> BinarySearchTree<ElementType>::MiddleTraversal()
{
    std::vector<ElementType*> temp;
    DoMiddleTraversal(Root, temp);
    return temp;
}
template<typename ElementType>
size_t BinarySearchTree<ElementType>::GetHeight()
{
    return GetHeight(Root);
}
template<typename ElementType>
void BinarySearchTree<ElementType>::DSW()
{
    ClockwiseRotate(Root);
    TransformSingleBranchToBalancedTree();
}
template<typename ElementType>
void BinarySearchTree<ElementType>::Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode)
{
    if (!otherNode)
        return;

    oneNode = new BinarySearchNode<ElementType>(otherNode->Data);
    Copy(oneNode->LChild, otherNode->LChild);
    Copy(oneNode->RChild, otherNode->RChild);
    if (!oneNode->LChild)
        oneNode->LChild->Parent = oneNode;
    if (!oneNode->RChild)
        oneNode->RChild->Parent = oneNode;
}
template<typename ElementType>
void BinarySearchTree<ElementType>::Purge(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return;
    Purge(node->LChild);
    Purge(node->RChild);
    delete node;
}
template<typename ElementType>
BinarySearchNode<ElementType>* BinarySearchTree<ElementType>::DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value)
{
    if (!node)
    {
        node = new BinarySearchNode<ElementType>(value);
        return node;
    }
    if (value == node->Data)
        return nullptr;
    else if (value < node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->LChild, value);
        //Set parent for new node if it is the left child of "node".
        if (temp && node->LChild == temp)
            temp->Parent = node;
        return temp;
    }
    else if (value > node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->RChild, value);
        //Set parent for new node if it is the right child of "node".
        if (temp && node->RChild == temp)
            temp->Parent = node;
        return temp;
    }
}
template<typename ElementType>
BinarySearchNode<ElementType>* BinarySearchTree<ElementType>::DoFind(BinarySearchNode<ElementType>* node, ElementType value)
{
    if (!node)
        return nullptr;
    if (value == node->Data)
        return node;
    else if (value < node->Data)
        return DoFind(node->LChild, value);
    else if (value > node->Data)
        return DoFind(node->RChild, value);
}
template<typename ElementType>
size_t BinarySearchTree<ElementType>::GetHeight(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return 0;
    size_t l = GetHeight(node->LChild), r = GetHeight(node->RChild);
    return (l > r) ? l + 1 : r + 1;
}
template<typename ElementType>
BinarySearchNode<ElementType>*& BinarySearchTree<ElementType>::GetLCMax(BinarySearchNode<ElementType>*& node)
{
    if (!node->RChild)
        return node;
    return GetLCMax(node->RChild);
}
template<typename ElementType>
BinarySearchNode<ElementType>*& BinarySearchTree<ElementType>::GetRCMin(BinarySearchNode<ElementType>*& node)
{
    if (!node->LChild)
        return node;
    return GetRCMin(node->LChild);
}
template<typename ElementType>
void BinarySearchTree<ElementType>::DoDelete(BinarySearchNode<ElementType>*& node)
{
    if (node->LChild == nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = nullptr;
        delete temp;
    }
    else if (node->LChild != nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->LChild;
        node->Parent = temp->Parent;
        delete temp;
    }
    else if (node->LChild == nullptr && node->RChild != nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->RChild;
        node->Parent = temp->Parent;
        delete temp;
    }
    else
    {
        //Left child tree, right child tree, cut which is higher for balance.
        BinarySearchNode<ElementType>*& temp = (GetHeight(node->LChild) > GetHeight(node->RChild)) ? GetLCMax(node->LChild) : GetRCMin(node->RChild);
        node->Data = temp->Data;
        DoDelete(temp);
    }
}
template<typename ElementType>
void BinarySearchTree<ElementType>::DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence)
{
    if (!node)
        return;
    DoMiddleTraversal(node->LChild, sequence);
    sequence.push_back(&node->Data);
    DoMiddleTraversal(node->RChild, sequence);
}
template<typename ElementType>
void BinarySearchTree<ElementType>::ClockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    //Recursion
    if (!nodeB)
        return;
    else if (nodeB->LChild)
    {
        BinarySearchNode<ElementType>* leftChildOfNodeB = nodeB->LChild;
        BinarySearchNode<ElementType>* rightChildOfLeftChildOfNodeB = leftChildOfNodeB->RChild;
        nodeB->LChild = rightChildOfLeftChildOfNodeB;
        if (rightChildOfLeftChildOfNodeB)
            rightChildOfLeftChildOfNodeB->Parent = nodeB;
        leftChildOfNodeB->RChild = nodeB;
        leftChildOfNodeB->Parent = nodeB->Parent;
        nodeB->Parent = leftChildOfNodeB;
        nodeB = leftChildOfNodeB;
    }
    if (nodeB->LChild)
        ClockwiseRotate(nodeB);
    else
        ClockwiseRotate(nodeB->RChild);
}
template<typename ElementType>
void BinarySearchTree<ElementType>::CounterclockwiseRotate(BinarySearchNode<ElementType>* nodeB)
{
    //Once
    if (!nodeB)
        return;
    BinarySearchNode<ElementType>* ParentOfNodeB = nodeB->Parent;
    BinarySearchNode<ElementType>* rightChildOfNodeB = nodeB->RChild;
    BinarySearchNode<ElementType>* leftChildOfRightChildOfNodeB = rightChildOfNodeB->LChild;
    nodeB->RChild = leftChildOfRightChildOfNodeB;
    if (leftChildOfRightChildOfNodeB)
        leftChildOfRightChildOfNodeB->Parent = nodeB;
    rightChildOfNodeB->LChild = nodeB;
    nodeB->Parent = rightChildOfNodeB;
    rightChildOfNodeB->Parent = ParentOfNodeB;
    if (ParentOfNodeB)
        ParentOfNodeB->RChild = rightChildOfNodeB;
    else
        Root = rightChildOfNodeB;
}
template<typename ElementType>
void BinarySearchTree<ElementType>::TransformSingleBranchToBalancedTree()
{
    size_t length = 0;
    BinarySearchNode<ElementType>* temp = Root;
    while (temp)
    {
        length++;
        temp = temp->RChild;
    }

    if (length <= 2)
        return;

    int m = (1 << ((int)(log10(length + 1) / log10(2)))) - 1;

    temp = Root;
    for (int i = 0; i < length - m; i++) {
        CounterclockwiseRotate(temp);
        temp = temp->Parent->RChild;
        if (!temp)
            break;
    }

    while (m > 1) {
        m /= 2;
        temp = Root;
        for (int i = 0; i < m; i++) {
            CounterclockwiseRotate(temp);
            temp = temp->Parent->RChild;
            if (!temp)
                break;
        }
    }
}

平衡二叉树

平衡二叉树(Balanced Binary Tree),其种类有很多种,较为著名的是AVL树。 这个名字来源于它的发明者——两位苏联数学家Adel' son-Vel'sii和Landis。 之后我们所说的平衡二叉树都是指AVL树。

二叉排序树可以由DSW算法平衡化。 而平衡二叉树由二叉排序树改进而来。 区别在于修改插入与删除的操作, 每次插入元素之后或者删除元素之后, 平衡二叉树都会触发判定, 如果出现不平衡的情况,就会自动平衡自身。

d13adf7410d4888896f6843837668af8.png

比如这个单支树, 是按1234567的顺序插入元素建立的二叉排序树。 而按同样的序列建立平衡二叉树, 它将会自动平衡成这样。

6572d5d52b8a242368f1038de01dc982.png

首先,我们需要知道什么是平衡因子(Balance Factor,BF)。 一个结点,其左子树的高度减去其右子树的高度,就是它的平衡因子。 一个平衡二叉树,所有结点的平衡因子的绝对值都小于等于1, 也就是所有节点都是平衡的。 平衡二叉树一定是完全二叉树。

与DSW算法不同,AVL树不保证是完全平衡的。

调整思路

当添加或删除一个结点时,原来的树很可能会失衡(出现某个结点的平衡因子的绝对值大于1的情况)。

2e95173fc1a9d077c95262deaf5495ca.png

22bf8b28f7cc821399ee11f566d2ec79.png

那么,只要某个结点的平衡因子绝对值达到2时,我们就及时平衡它即可。 某个结点的平衡因子绝对值达到2时,将分为四种情况。

我们将平衡因子绝对值达到2的结点记为B, B的父结点记为A,A为空说明B是根结点, B的一个平衡因子绝对值达到1的子结点记为C, 新插入结点记为D。 其余非关键子树则以方块表示。

LL型

0bf5189dd2fef33272edaf53c6f5a763.png

B结点的子结点为C,C结点的子结点为新插入结点D,故称为LL型。 D插入后,B子树中序遍历序列为DCαBβ,B平衡因子为2,C平衡因子为1

对于这种情况,则将B、C右旋即可。 如此,中序遍历序列不变,且没有平衡因子绝对值达到2的结点了。

RR型

1a9cb34f064178325bd69683d3ccbd40.png

B结点的子结点为C,C结点的子结点为新插入结点D,故称为LL型。 显然这是和LL型对称的,将B、C左旋即可。

LR型

fcc5cd85b7df53d396820ade4f18e154.png

这是在B结点的子结点C的子树上插入结点D,故称为LR型。 D是带着两个儿子来的,看来事情并不简单。 D插入后,B子树中序遍历序列为αCδDγBβ,B平衡因子为2,C平衡因子为-1

对于LR型,它既不是左旋,又不是右旋,应该作如下调整: 1. C结点接管D结点左子树δ作为右子树 2. B结点接管D结点右子树γ作为左子树 3. D结点代替B结点位置,与A结点确立父子关系,并以C、D为左右子树

总之,就是中序遍历序列不变,新插入节点D成为B子树新的根结点。

RL型

6d57cbbfd15b3adbc83d756755defae6.png

RL型与LR型对称,故不再赘述。

需要注意的地方

有时会出现插入一个元素而导致某个元素平衡因子绝对值为3的情况, 这时四个情况都对不上,因为它们都只考虑新插入节点的父结点与爷爷节点。 比如以下情况:

caa65c6be4a0cf8d0b2a7d6070e2e149.png

6加入时,4、5平衡因子不足以触发调整,而这时又查不到2。 7加入后,5、6、7构成RR型,调整后如下。

4e65e2d987ea76c0183e01905e413b45.png

调整后,6为子树的根结点。 而BCD(5、6、7)的平衡因子都为0。 所以,需要在调整之后要加上递归向前判断的操作, 此时须从以A结点作为新的C结点判断开始。

实现代码

AVLTree.hpp:

#pragma once
#include <vector>
#include <initializer_list>
#include "BinarySearchNode.hpp"
template<typename ElementType>
class AVLTree
{
private:
    BinarySearchNode<ElementType>* Root = nullptr;
public:
    AVLTree(){}
    AVLTree(const std::initializer_list<ElementType>& elements);
    AVLTree(const AVLTree& otherTree);
    ~AVLTree();
    bool Insert(ElementType value);
    bool IsIn(ElementType value);
    void Delete(ElementType value);
    std::vector<ElementType*> MiddleTraversal();
    size_t GetHeight();
private:
    void Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode);
    void Purge(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>* DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value);
    BinarySearchNode<ElementType>* DoFind(BinarySearchNode<ElementType>* node, ElementType value);
    size_t GetHeight(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>*& GetLCMax(BinarySearchNode<ElementType>*& node);
    BinarySearchNode<ElementType>*& GetRCMin(BinarySearchNode<ElementType>*& node);
    //Delete the aim node and return its parent node.
    BinarySearchNode<ElementType>* DoDelete(BinarySearchNode<ElementType>*& node);
    void DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence);
    int GetBalanceFactor(BinarySearchNode<ElementType>* node);
    void DoAdjustment(BinarySearchNode<ElementType>* nodeB);
    void LLClockwiseRotate(BinarySearchNode<ElementType>*& nodeB);
    void RRCounterClockwiseRotate(BinarySearchNode<ElementType>*& nodeB);
    void LRAdjust(BinarySearchNode<ElementType>*& nodeB);
    void RLAdjust(BinarySearchNode<ElementType>*& nodeB);
};

template<typename ElementType>
AVLTree<ElementType>::AVLTree(const std::initializer_list<ElementType>& elements)
{
    for (ElementType i : elements)
        DoInsert(Root, i);
}
template<typename ElementType>
AVLTree<ElementType>::AVLTree(const AVLTree& otherTree)
{
    Copy(Root, otherTree.Root);
}
template<typename ElementType>
AVLTree<ElementType>::~AVLTree()
{
    Purge(Root);
}
template<typename ElementType>
bool AVLTree<ElementType>::Insert(ElementType value)
{
    BinarySearchNode<ElementType>* node = DoInsert(Root, value);
    if (node)
    {
        if (node->Parent && node->Parent)
            DoAdjustment(node->Parent);
        return true;
    }
    return false;
}
template<typename ElementType>
bool AVLTree<ElementType>::IsIn(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    return (!temp) ? false : true;
}
template<typename ElementType>
void AVLTree<ElementType>::Delete(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    BinarySearchNode<ElementType>* deletedNodeParent;
    if (!temp)
        return;
    if (temp == Root)
        deletedNodeParent = DoDelete(Root);
    else if (temp->Parent->LChild == temp)
        deletedNodeParent = DoDelete(temp->Parent->LChild);
    else
        deletedNodeParent = DoDelete(temp->Parent->RChild);
    DoAdjustment(deletedNodeParent);
}
template<typename ElementType>
std::vector<ElementType*> AVLTree<ElementType>::MiddleTraversal()
{
    std::vector<ElementType*> temp;
    DoMiddleTraversal(Root, temp);
    return temp;
}
template<typename ElementType>
size_t AVLTree<ElementType>::GetHeight()
{
    return GetHeight(Root);
}
template<typename ElementType>
void AVLTree<ElementType>::Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode)
{
    if (!otherNode)
        return;

    oneNode = new BinarySearchNode<ElementType>(otherNode->Data);
    Copy(oneNode->LChild, otherNode->LChild);
    Copy(oneNode->RChild, otherNode->RChild);
    if (!oneNode->LChild)
        oneNode->LChild->Parent = oneNode;
    if (!oneNode->RChild)
        oneNode->RChild->Parent = oneNode;
}
template<typename ElementType>
void AVLTree<ElementType>::Purge(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return;
    Purge(node->LChild);
    Purge(node->RChild);
    delete node;
}
template<typename ElementType>
BinarySearchNode<ElementType>* AVLTree<ElementType>::DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value)
{
    if (!node)
    {
        node = new BinarySearchNode<ElementType>(value);
        return node;
    }
    if (value == node->Data)
        return nullptr;
    else if (value < node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->LChild, value);
        //Set parent for new node if it is the left child of "node".
        if (temp && node->LChild == temp)
            temp->Parent = node;
        return temp;
    }
    else if (value > node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->RChild, value);
        //Set parent for new node if it is the right child of "node".
        if (temp && node->RChild == temp)
            temp->Parent = node;
        return temp;
    }
}
template<typename ElementType>
BinarySearchNode<ElementType>* AVLTree<ElementType>::DoFind(BinarySearchNode<ElementType>* node, ElementType value)
{
    if (!node)
        return nullptr;
    if (value == node->Data)
        return node;
    else if (value < node->Data)
        return DoFind(node->LChild, value);
    else if (value > node->Data)
        return DoFind(node->RChild, value);
}
template<typename ElementType>
size_t AVLTree<ElementType>::GetHeight(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return 0;
    size_t l = GetHeight(node->LChild), r = GetHeight(node->RChild);
    return (l > r) ? l + 1 : r + 1;
}
template<typename ElementType>
BinarySearchNode<ElementType>*& AVLTree<ElementType>::GetLCMax(BinarySearchNode<ElementType>*& node)
{
    if (!node->RChild)
        return node;
    return GetLCMax(node->RChild);
}
template<typename ElementType>
BinarySearchNode<ElementType>*& AVLTree<ElementType>::GetRCMin(BinarySearchNode<ElementType>*& node)
{
    if (!node->LChild)
        return node;
    return GetRCMin(node->LChild);
}
template<typename ElementType>
BinarySearchNode<ElementType>* AVLTree<ElementType>::DoDelete(BinarySearchNode<ElementType>*& node)
{
    if (node->LChild == nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = nullptr;
        BinarySearchNode<ElementType>* tempParent = temp->Parent;
        delete temp;
        return tempParent;
    }
    else if (node->LChild != nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->LChild;
        node->Parent = temp->Parent;
        BinarySearchNode<ElementType>* tempParent = temp->Parent;
        delete temp;
        return tempParent;
    }
    else if (node->LChild == nullptr && node->RChild != nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->RChild;
        node->Parent = temp->Parent;
        BinarySearchNode<ElementType>* tempParent = temp->Parent;
        delete temp;
        return tempParent;
    }
    else
    {
        //Left child tree, right child tree, cut which is higher for balance.
        BinarySearchNode<ElementType>*& temp = (GetHeight(node->LChild) > GetHeight(node->RChild)) ? GetLCMax(node->LChild) : GetRCMin(node->RChild);
        node->Data = temp->Data;
        return DoDelete(temp);
    }
}
template<typename ElementType>
void AVLTree<ElementType>::DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence)
{
    if (!node)
        return;
    DoMiddleTraversal(node->LChild, sequence);
    sequence.push_back(&node->Data);
    DoMiddleTraversal(node->RChild, sequence);
}
template<typename ElementType>
int AVLTree<ElementType>::GetBalanceFactor(BinarySearchNode<ElementType>* node)
{
    return GetHeight(node->LChild) - GetHeight(node->RChild);
}
template<typename ElementType>
void AVLTree<ElementType>::DoAdjustment(BinarySearchNode<ElementType>* nodeC)
{
    if (nodeC && nodeC->Parent)
        if (GetBalanceFactor(nodeC->Parent) == 2 && GetBalanceFactor(nodeC) == 1)
        {
            if (nodeC->Parent == Root)
                LLClockwiseRotate(Root);
            else if (nodeC->Parent == nodeC->Parent->Parent->LChild)
                LLClockwiseRotate(nodeC->Parent->Parent->LChild);
            else if (nodeC->Parent == nodeC->Parent->Parent->RChild)
                LLClockwiseRotate(nodeC->Parent->Parent->RChild);
        }
        else if (GetBalanceFactor(nodeC->Parent) == -2 && GetBalanceFactor(nodeC) == -1)
        {
            if (nodeC->Parent == Root)
                RRCounterClockwiseRotate(Root);
            else if (nodeC->Parent == nodeC->Parent->Parent->LChild)
                RRCounterClockwiseRotate(nodeC->Parent->Parent->LChild);
            else if (nodeC->Parent == nodeC->Parent->Parent->RChild)
                RRCounterClockwiseRotate(nodeC->Parent->Parent->RChild);
        }
        else if (GetBalanceFactor(nodeC->Parent) == 2 && GetBalanceFactor(nodeC) == -1)
        {
            if (nodeC->Parent == Root)
                LRAdjust(Root);
            else if (nodeC->Parent == nodeC->Parent->Parent->LChild)
                LRAdjust(nodeC->Parent->Parent->LChild);
            else if (nodeC->Parent == nodeC->Parent->Parent->RChild)
                LRAdjust(nodeC->Parent->Parent->RChild);
        }
        else if (GetBalanceFactor(nodeC->Parent) == -2 && GetBalanceFactor(nodeC) == 1)
        {
            if (nodeC->Parent == Root)
                RLAdjust(Root);
            else if (nodeC->Parent == nodeC->Parent->Parent->LChild)
                RLAdjust(nodeC->Parent->Parent->LChild);
            else if (nodeC->Parent == nodeC->Parent->Parent->RChild)
                RLAdjust(nodeC->Parent->Parent->RChild);
        }
}
template<typename ElementType>
void AVLTree<ElementType>::LLClockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->LChild;
    if (!nodeC)
        return;
    nodeB->LChild = nodeC->RChild;
    if (nodeC->RChild)
        nodeC->RChild->Parent = nodeB;
    nodeC->RChild = nodeB;
    nodeB->Parent = nodeC;
    if (nodeA)
        nodeC->Parent = nodeA;
    nodeB = nodeC;
    DoAdjustment(nodeA);
}
template<typename ElementType>
void AVLTree<ElementType>::RRCounterClockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->RChild;
    if (!nodeC)
        return;
    nodeB->RChild = nodeC->LChild;
    if (nodeC->LChild)
        nodeC->LChild->Parent = nodeB;
    nodeC->LChild = nodeB;
    nodeB->Parent = nodeC;
    if (nodeA)
        nodeC->Parent = nodeA;
    nodeB = nodeC;
    DoAdjustment(nodeA);
}
template<typename ElementType>
void AVLTree<ElementType>::LRAdjust(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->LChild;
    BinarySearchNode<ElementType>* nodeD = nodeC->RChild;
    if (!nodeC || !nodeD)
        return;
    nodeC->RChild = nodeD->LChild;
    if (nodeD->LChild)
        nodeD->LChild->Parent = nodeC;
    nodeB->LChild = nodeD->RChild;
    if (nodeD->RChild)
        nodeD->RChild->Parent = nodeB;
    nodeD->LChild = nodeC;
    nodeC->Parent = nodeD;
    nodeD->RChild = nodeB;
    nodeB->Parent = nodeD;
    if (nodeA)
        nodeD->Parent = nodeA;
    nodeB = nodeD;
    DoAdjustment(nodeA);
}
template<typename ElementType>
void AVLTree<ElementType>::RLAdjust(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->RChild;
    BinarySearchNode<ElementType>* nodeD = nodeC->LChild;
    if (!nodeC || !nodeD)
        return;
    nodeC->LChild = nodeD->RChild;
    if (nodeD->RChild)
        nodeD->RChild->Parent = nodeC;
    nodeB->RChild = nodeD->LChild;
    if (nodeD->LChild)
        nodeD->LChild->Parent = nodeB;
    nodeD->RChild = nodeC;
    nodeC->Parent = nodeD;
    nodeD->LChild = nodeB;
    nodeB->Parent = nodeD;
    if (nodeA)
        nodeD->Parent = nodeA;
    nodeB = nodeD;
    DoAdjustment(nodeA);
}

自适应树

我们使用树来作为查找表,最关心的还是它的操作效率。 平衡二叉树把二叉树给平衡了, 自然会带来效率的提高。 自适应树(Self-adjusting Tree)则是提高效率的另一种思路。 它并没有平衡自身,而是将常用的元素向上移动, 越常用的元素,则越靠近根结点,这样访问到它也就越快。 在自适应树中,元素根据它的被访问次数,带上了优先级的属性。

实现自适应树,有四种相似的策略。

单一旋转

如果访问除根结点外的结点, 就把它围绕它的父结点进行旋转。 这样结点被访问的次数越多,它离根结点就越近。

移动到根部

如果访问除根结点外的结点, 这时就反复旋转它与它的父结点, 直到把它转成了根结点。

张开

前两种策略的平均查找时间是

。在不适宜的环境下,它们运行的并不是很好, 所以一般不采用前两种策略。

移动到根部策略的一个修改版本称为张开(Splaying)策略。 这个策略根据子结点与父结点、父结点与爷爷结点的关系, 成对地使用单一旋转。

设子结点为C,父结点为B,爷爷结点为A 子结点与父结点、父结点与爷爷结点的关系分为三种情况。

797484105d37e2add032e480a37b42c0.png
第一种情况

第一种情况是爷爷结点不存在, 这个时候父结点就是根结点。

7624da118103e85afd3373529f962dd0.png
同构配置

第二种是子结点是父结点的左子结点,父结点又是爷爷结点的左子结点, 或者俩都是右子结点, 这种情况称为同构配置(Homogeneous Configuration)。

c0a27eff9024b258325c5f0e596f97d8.png
异构配置

第三种情况就和第二种相反, 就是一个是左,一个是右, 或者一个是右,一个是左, 这种情况称为异构配置(Heterogeneous Configuration)。

无论哪种情况,张开策略的目的在于将C移动到根部。

void Splaying(A,B,C):
    while C不是根节点:
        if B是根结点:
            将C围绕B旋转
        else if A、B、C同构配置:
            将B围绕A旋转
            将C围绕B旋转
        else if A、B、C异构配置:
            将C围绕B旋转
            将C围绕A旋转

从这段代码可见,张开策略并非一味地将结点从下到上旋转, 当同构配置时, 先旋转A、B,再旋转B、C, 这样可以使得树更加平整。

对于叶节点来说,除了树不平衡时的一些初始访问外,访问时间通常是O(lg n)。 然而访问靠近根结点的结点,可能会使得树不平衡。 比如一直访问根结点的左子结点,树将会一直向右拉长。

半张开

张开策略在一部分元素比其他元素更加常用的情况下,表现得不错。 如果靠近根部的元素与底层的元素的访问频率差不多, 那么张开策略就不是一个好的选择。 这时我们可以对其作一些修改, 使之从强调结点访问频率优先级转向强调树的平衡(并非完全转向)。

这样的策略称为半张开(Semisplaying), 它与张开策略的不同在于, 同构配置下,将B围绕A旋转后,不再将C围绕B旋转, 而是将B作为新的子结点进行张开, 此时B结点成为新的C结点, A结点称为新的B结点。

实现代码中使用的即为半张开策略。

实现代码

AdaptiveTree.hpp:

#pragma once
#include <vector>
#include <initializer_list>
#include "BinarySearchNode.hpp"
template<typename ElementType>
class AdaptiveTree
{
private:
    BinarySearchNode<ElementType>* Root = nullptr;
public:
    AdaptiveTree() {}
    AdaptiveTree(const std::initializer_list<ElementType>& elements);
    AdaptiveTree(const AdaptiveTree& otherBST);
    ~AdaptiveTree();
    //If success, it will return true.
    bool Insert(ElementType value);
    bool IsIn(ElementType value);
    void Delete(ElementType value);
    std::vector<ElementType*> MiddleTraversal();
    size_t GetHeight();
private:
    void Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode);
    void Purge(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>* DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value);
    BinarySearchNode<ElementType>* DoFind(BinarySearchNode<ElementType>* node, ElementType value);
    size_t GetHeight(BinarySearchNode<ElementType>* node);
    BinarySearchNode<ElementType>*& GetLCMax(BinarySearchNode<ElementType>*& node);
    BinarySearchNode<ElementType>*& GetRCMin(BinarySearchNode<ElementType>*& node);
    void DoDelete(BinarySearchNode<ElementType>*& node);
    void DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence);
    void SemiSplaying(BinarySearchNode<ElementType>* node);
    void ClockwiseRotate(BinarySearchNode<ElementType>*& nodeB);
    void CounterclockwiseRotate(BinarySearchNode<ElementType>*& nodeB);
};

template<typename ElementType>
AdaptiveTree<ElementType>::AdaptiveTree(const std::initializer_list<ElementType>& elements)
{
    for (ElementType i : elements)
        DoInsert(Root, i);
}
template<typename ElementType>
AdaptiveTree<ElementType>::AdaptiveTree(const AdaptiveTree& otherBST)
{
    Copy(Root, otherBST.Root);
}
template<typename ElementType>
AdaptiveTree<ElementType>::~AdaptiveTree()
{
    Purge(Root);
}
template<typename ElementType>
bool AdaptiveTree<ElementType>::Insert(ElementType value)
{
    BinarySearchNode<ElementType>* node = DoInsert(Root, value);
    return (!node) ? false : true;
}
template<typename ElementType>
bool AdaptiveTree<ElementType>::IsIn(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    if (temp)
    {
        SemiSplaying(temp);
        return true;
    }
    else
        return false;
}
template<typename ElementType>
void AdaptiveTree<ElementType>::Delete(ElementType value)
{
    BinarySearchNode<ElementType>* temp = DoFind(Root, value);
    if (!temp)
        return;
    if (temp == Root)
        DoDelete(Root);
    else if (temp->Parent->LChild == temp)
        DoDelete(temp->Parent->LChild);
    else
        DoDelete(temp->Parent->RChild);
}
template<typename ElementType>
std::vector<ElementType*> AdaptiveTree<ElementType>::MiddleTraversal()
{
    std::vector<ElementType*> temp;
    DoMiddleTraversal(Root, temp);
    return temp;
}
template<typename ElementType>
size_t AdaptiveTree<ElementType>::GetHeight()
{
    return GetHeight(Root);
}
template<typename ElementType>
void AdaptiveTree<ElementType>::Copy(BinarySearchNode<ElementType>*& oneNode, BinarySearchNode<ElementType>*& otherNode)
{
    if (!otherNode)
        return;

    oneNode = new BinarySearchNode<ElementType>(otherNode->Data);
    Copy(oneNode->LChild, otherNode->LChild);
    Copy(oneNode->RChild, otherNode->RChild);
    if (!oneNode->LChild)
        oneNode->LChild->Parent = oneNode;
    if (!oneNode->RChild)
        oneNode->RChild->Parent = oneNode;
}
template<typename ElementType>
void AdaptiveTree<ElementType>::Purge(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return;
    Purge(node->LChild);
    Purge(node->RChild);
    delete node;
}
template<typename ElementType>
BinarySearchNode<ElementType>* AdaptiveTree<ElementType>::DoInsert(BinarySearchNode<ElementType>*& node, ElementType& value)
{
    if (!node)
    {
        node = new BinarySearchNode<ElementType>(value);
        return node;
    }
    if (value == node->Data)
        return nullptr;
    else if (value < node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->LChild, value);
        //Set parent for new node if it is the left child of "node".
        if (temp && node->LChild == temp)
            temp->Parent = node;
        return temp;
    }
    else if (value > node->Data)
    {
        BinarySearchNode<ElementType>* temp = DoInsert(node->RChild, value);
        //Set parent for new node if it is the right child of "node".
        if (temp && node->RChild == temp)
            temp->Parent = node;
        return temp;
    }
}
template<typename ElementType>
BinarySearchNode<ElementType>* AdaptiveTree<ElementType>::DoFind(BinarySearchNode<ElementType>* node, ElementType value)
{
    if (!node)
        return nullptr;
    if (value == node->Data)
        return node;
    else if (value < node->Data)
        return DoFind(node->LChild, value);
    else if (value > node->Data)
        return DoFind(node->RChild, value);
}
template<typename ElementType>
size_t AdaptiveTree<ElementType>::GetHeight(BinarySearchNode<ElementType>* node)
{
    if (!node)
        return 0;
    size_t l = GetHeight(node->LChild), r = GetHeight(node->RChild);
    return (l > r) ? l + 1 : r + 1;
}
template<typename ElementType>
BinarySearchNode<ElementType>*& AdaptiveTree<ElementType>::GetLCMax(BinarySearchNode<ElementType>*& node)
{
    if (!node->RChild)
        return node;
    return GetLCMax(node->RChild);
}
template<typename ElementType>
BinarySearchNode<ElementType>*& AdaptiveTree<ElementType>::GetRCMin(BinarySearchNode<ElementType>*& node)
{
    if (!node->LChild)
        return node;
    return GetRCMin(node->LChild);
}
template<typename ElementType>
void AdaptiveTree<ElementType>::DoDelete(BinarySearchNode<ElementType>*& node)
{
    if (node->LChild == nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = nullptr;
        delete temp;
    }
    else if (node->LChild != nullptr && node->RChild == nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->LChild;
        node->Parent = temp->Parent;
        delete temp;
    }
    else if (node->LChild == nullptr && node->RChild != nullptr)
    {
        BinarySearchNode<ElementType>* temp = node;
        node = node->RChild;
        node->Parent = temp->Parent;
        delete temp;
    }
    else
    {
        //Left child tree, right child tree, cut which is higher for balance.
        BinarySearchNode<ElementType>*& temp = (GetHeight(node->LChild) > GetHeight(node->RChild)) ? GetLCMax(node->LChild) : GetRCMin(node->RChild);
        node->Data = temp->Data;
        DoDelete(temp);
    }
}
template<typename ElementType>
void AdaptiveTree<ElementType>::DoMiddleTraversal(BinarySearchNode<ElementType>* node, std::vector<ElementType*>& sequence)
{
    if (!node)
        return;
    DoMiddleTraversal(node->LChild, sequence);
    sequence.push_back(&node->Data);
    DoMiddleTraversal(node->RChild, sequence);
}
template<typename ElementType>
void AdaptiveTree<ElementType>::SemiSplaying(BinarySearchNode<ElementType>* node)
{
    while (node != Root)
    {
        if (node->Parent == Root)
        {
            if (Root->LChild == node)
                ClockwiseRotate(Root);
            else if (Root->RChild == node)
                CounterclockwiseRotate(Root);
        }
        else if (node == node->Parent->LChild && node->Parent == node->Parent->Parent->LChild)
        {
            if (node->Parent->Parent->Parent && node->Parent->Parent->Parent->LChild == node->Parent->Parent)
                ClockwiseRotate(node->Parent->Parent->Parent->LChild);
            else if (node->Parent->Parent->Parent && node->Parent->Parent->Parent->RChild == node->Parent->Parent)
                ClockwiseRotate(node->Parent->Parent->Parent->RChild);
            node = node->Parent;
        }
        else if (node == node->Parent->RChild && node->Parent == node->Parent->Parent->RChild)
        {
            if (node->Parent->Parent->Parent && node->Parent->Parent->Parent->LChild == node->Parent->Parent)
                CounterclockwiseRotate(node->Parent->Parent->Parent->LChild);
            else if (node->Parent->Parent->Parent && node->Parent->Parent->Parent->RChild == node->Parent->Parent)
                CounterclockwiseRotate(node->Parent->Parent->Parent->RChild);
            node = node->Parent;
        }
        else if (node == node->Parent->LChild && node->Parent == node->Parent->Parent->RChild)
        {
            ClockwiseRotate(node->Parent);
            CounterclockwiseRotate(node->Parent);
        }
        else if (node == node->Parent->RChild && node->Parent == node->Parent->Parent->LChild)
        {
            CounterclockwiseRotate(node->Parent);
            ClockwiseRotate(node->Parent);
        }
    }
}
template<typename ElementType>
void AdaptiveTree<ElementType>::ClockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->LChild;
    if (!nodeC)
        return;
    nodeB->LChild = nodeC->RChild;
    if (nodeC->RChild)
        nodeC->RChild->Parent = nodeB;
    nodeC->RChild = nodeB;
    nodeB->Parent = nodeC;
    if (nodeA)
        nodeC->Parent = nodeA;
    nodeB = nodeC;
}
template<typename ElementType>
void AdaptiveTree<ElementType>::CounterclockwiseRotate(BinarySearchNode<ElementType>*& nodeB)
{
    BinarySearchNode<ElementType>* nodeA = nodeB->Parent;
    BinarySearchNode<ElementType>* nodeC = nodeB->RChild;
    if (!nodeC)
        return;
    nodeB->RChild = nodeC->LChild;
    if (nodeC->LChild)
        nodeC->LChild->Parent = nodeB;
    nodeC->LChild = nodeB;
    nodeB->Parent = nodeC;
    if (nodeA)
        nodeC->Parent = nodeA;
    nodeB = nodeC;
}

自适应树的实际表现

从理论上来说, AVL树是一个优化效率的思路, 自适应树也是一个思路, 然而实际上,Bell和Gupta在1993年的实验表明, AVL树的表现似乎总是优于自适应树, 甚至许多时候自适应树的表现还不如普通的二叉排序树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值