1.二叉搜索树
顾名思义 一个用于搜索的二叉树
1.1二叉树的性质
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树
它的性质决定了它的中序遍历就是这组数据的有序排列
1.2二叉树的建立
和二叉树一样 找到一颗树只需要记录根节点就行
节点
插入节点
从根节点开始遍历 比节点值大就往右走 比节点值小就往左走 直到找到空位置就插入数据
删除节点
如果是叶子节点就直接删除 如果要删除节点存在子树就要找 左子树做大节点或者右子树最小节点替换这个节点然后删除
查找节点 直接根据特性遍历就行了
2.AVLTree
我们可以发现 二叉搜索树 正常情况下 查找数据的复杂度为log n 还是很快的
但依然存在一些特殊情况 当后面插入的数据都比根节点的值都大或都更小 那么这个树就退化成了歪脖子树 就像一个链表一样
而AVLTree就是为了解决这个问题而产生的 AVLTree又叫二叉平衡搜索树
这个树相比于二叉搜索树最大的差别就是平衡
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整)就实现了平衡
所以在节点引入了一个平衡因子 右数高度减左数高度 平衡因子绝对值小于二就表示其为平衡的
template<class T>
struct AVLTreeNode
{
AVLTreeNode(const T& data)
: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
, _data(data), _bf(0)
{}
AVLTreeNode<T>* _pLeft; // 该节点的左孩子
AVLTreeNode<T>* _pRight; // 该节点的右孩子
AVLTreeNode<T>* _pParent; // 该节点的双亲
T _data;
int _bf; // 该节点的平衡因子
};
那如何保证平衡呢
当插入数据后就可能会使某个数高度发生变化就会影响平衡因子 当平衡因子绝对值大于1时就将这个树进行旋转
2.1旋转
AVL旋转有四种情况
- 新节点插入较高左子树的左侧—左左:右单旋
void rotar(node* parent)//右单旋
{
node* nodel = parent->_left;
node* nodelr = nodel->_right;
node* ppnode = parent->_parent;
parent->_left = nodelr;
if (nodelr)
nodelr->_parent = parent;
nodel->_right = parent;
parent->_parent = nodel;
if (ppnode == nullptr)
{
_root = nodel;
nodel->_parent = nullptr;
}
else
{
if (parent == ppnode->_left)
{
ppnode->_left = nodel;
}
else if (parent == ppnode->_right)
{
ppnode->_right = nodel;
}
nodel->_parent = ppnode;
}
parent->bf = nodel->bf = 0;
}
- 新节点插入较高右子树的右侧—右右:左单旋
void rotal(node* parent)//左单旋
{
node* noder = parent->_right;
node* noderl = noder->_left;
node* ppnode = parent->_parent;
parent->_right = noderl;
if (noderl)
noderl->_parent = parent;
noder->_left = parent;
parent->_parent = noder;
if (ppnode == nullptr)
{
_root = noder;
_root->_parent = nullptr;
}
else
{
if (parent == ppnode->_left)
{
ppnode->_left = noder;
}
else if (parent == ppnode->_right)
{
ppnode->_right = noder;
}
noder->_parent = ppnode;
}
parent->bf = noder->bf = 0;
}
- 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
void rotalr(node* parent)//双旋 左右
{
node* nodel = parent->_left;
node* nodelr = nodel->_right;
int bf = parent->_left->_right->bf;
rotal(parent->_left);
rotar(parent);
if (bf == -1)
{
nodel->bf = 0;
parent->bf = 1;
nodelr = 0;
}
else if (bf == 1)
{
nodel->bf = -1;
parent->bf = 0;
nodelr = 0;
}
else if (bf == 0)
{
nodel->bf = 0;
parent->bf = 0;
nodelr = 0;
}
else
{
assert(false);
}
}
- 新节点插入较高右子树的左侧—右左:先右单旋再左单旋
void rotarl(node* parent)//双旋 右左
{
node* noder = parent->_right;
node* noderl = noder->_left;
int bf = parent->_right->_left->bf;
rotar(parent->_right);
rotal(parent);
if (bf == -1)
{
noder->bf = 1;
parent->bf = 0;
noderl->bf = 0;
}
else if (bf == 1)
{
noder->bf = 0;
parent->bf = -1;
noderl->bf = 0;
}
else if (bf == 0)
{
noder->bf = 0;
parent->bf = 0;
noderl->bf = 0;
}
else
{
assert(false);
}
}
注意更新平衡因子
AVLTree模拟