AVL树:
特性:
满足普通的二叉搜索树的特性的同时,对每一个节点,有一个平衡因子,其
值为左子树的高度减去右子树的高度,AVL树需满足每个节点的平衡因子的值的绝对值小于2。
搜索:
同普通的二叉搜索树的搜索算法。
插入:
首先执行普通的二叉搜索树的插入操作,但是因为插入元素可能会改变节点的平衡因子的值,所以插入后还需对树进行调整。
在遍历树的同时,找到距离插入位置最近的一个可能在插入后不平衡的节点avl,即平衡因子为-1或1的节点,若没有,则不需旋转,若有的话,对其旋转操作进行分类。
1.RR型左旋
在avl的右孩子的右子树进行插入操作。
插入后,avl的平衡因子为-2,其右孩子temp的平衡因子为-1,
选取temp为旋转后子树的根。旋转后,temp的左子树为avl,并 把avl的右子树修改为temp的原左子树,temp的右子树不变。 此时,旋转后所旋子树的高度与插入前相同,AVL树依然保持平 衡。
2.RL型双旋
在avl的右孩子的左子树进行插入操作。
插入后,avl的平衡因子为-2,其右孩子temp的平衡因子为1,选取temp的左孩子temp_为旋转后子树的根。旋转后,temp_的左子树为avl,右子树为temp,并把avl的右子树修改为temp_的原左子树,把temp的左子树修改为temp_的原右子树。此时,旋转后所旋子树的高度与插入前相同,AVL树依然保持平衡。
3.LL型右旋
在avl的左孩子的左子树进行插入操作。
插入后,avl的平衡因子为2,其左孩子temp的平衡因子为1,
选取temp为旋转后子树的根。旋转后,temp的右子树为avl,并 把avl的左子树修改为temp的原右子树,temp的左子树不变。 此时,旋转后所旋子树的高度与插入前相同,AVL树依然保持平 衡。
4.LR型双旋
在avl的左孩子的右子树进行插入操作。
插入后,avl的平衡因子为2,其左孩子temp的平衡因子为-1,选取temp的右孩子temp_为旋转后子树的根。旋转后,temp_的右子树为avl,左子树为temp,并把avl的左子树修改为temp_的原右子树,把temp的右子树修改为temp_的原左子树。此时,旋转后所旋子树的高度与插入前相同,AVL树依然保持平衡。
删除:
首先进行普通的二叉搜索树的删除操作,然后找到真正删除的节点的父节点,对1类删除来说为被删除叶子节点的父节点,对2345类删除来说为替代被删除的节点的节点。找到距离其位置最近的一个可能在删除后不平衡的节点,即平衡因子为1或-1的节点,若没有,则不需旋转,若有的话,对其旋转操作进行分类。
1.R0型右旋
在avl的右子树进行删除操作,且删除前avl的左孩子的平衡因子为0。
以avl的左孩子temp为旋转后子树的根,右子树为avl,并把avl的左子树修改为temp的原右子树,temp的左子树不变。此时,旋转后所旋子树的高度与删除前相同,AVL树依然保持平衡。
2.R1型右旋
在avl的右子树进行删除操作,且删除前avl的左孩子的平衡因子为1。
以avl的左孩子temp为旋转后子树的根,右子树为avl,并把avl的左子树修改为temp的原右子树,temp的左子树不变。此时,旋转后所旋子树的高度比删除前减少1,AVL树可能不保持平衡。相当于temp为被删节点的父节点并找到距离其最近的一个不平衡的节点判断其旋转类型继续旋转迭代。
3.R-1型双旋
在avl的右子树进行删除操作,且删除前avl的左孩子的平衡因子为-1。
以avl的左孩子temp的右孩子temp_为旋转后子树的根,左子树为temp,右子树为avl,并修改temp的右子树为temp_的原左子树,修改avl的左子树为temp_的原右子树。此时,旋转后所旋子树的高度比删除前减少1,AVL树可能不保持平衡。相当于temp为被删节点的父节点并找到距离其最近的一个不平衡的节点判断其旋转类型继续旋转迭代。
4.L0型左旋
在avl的左子树进行删除操作,且删除前avl的右孩子的平衡因子为0。
以avl的右孩子temp为旋转后子树的根,左子树为avl,并把avl的右子树修改为temp的原左子树,temp的右子树不变。此时,旋转后所旋子树的高度与删除前相同,AVL树依然保持平衡。
5.L1型双旋
在avl的左子树进行删除操作,且删除前avl的右孩子的平衡因子为1。
以avl的右孩子temp的左孩子temp_为旋转后子树的根,右子树为temp,左子树为avl,并修改temp的左子树为temp_的原右子树,修改avl的右子树为temp_的原左子树。此时,旋转后所旋子树的高度比删除前减少1,AVL树可能不保持平衡。相当于temp为被删节点的父节点并找到距离其最近的一个不平衡的节点判断其旋转类型继续旋转迭代。
6.L-1型左旋
在avl的右子树进行删除操作,且删除前avl的右孩子的平衡因子为-1。
以avl的右孩子temp为旋转后子树的根,左子树为avl,并把avl的右子树修改为temp的原左子树,temp的右子树不变。此时,旋转后所旋子树的高度比删除前减少1,AVL树可能不保持平衡。相当于temp为被删节点的父节点并找到距离其最近的一个不平衡的节点判断其旋转类型继续旋转迭代。
AVLSearchTree.h
#pragma once
#ifndef AVLSEARCHTREE_H
#define AVLSEARCHTREE_H
#include"BinaryTreeNode.h"
template<typename T>
class AVLSearchTree {
public:
AVLSearchTree() {
this->root = nullptr;
}
//为方便测试而写的构造函数,实际AVL树不能通过BinaryTreeNode构造
AVLSearchTree(BinaryTreeNode<T>* e) {
this->root = e;
}
AVLSearchTree(AVLSearchTree<T>* tree) {
this->root = tree->Root();
}
AVLSearchTree(T element) {
this->root = new BinaryTreeNode<T>(element);
}
BinaryTreeNode<T>* Root() {
return root;
}
void PreOrder() {
root->PreOrder();
}
void InOrder() {
root->InOrder();
}
void PostOrder() {
root->PostOrder();
}
int Size() {
return root->Size();
}
int Height() {
return root->Height();
}
bool Search(const T& k) {
BinaryTreeNode<T>* p = root;
while (p)
{
if (k < p->Data()) {
p = p->LeftChild();
}
else if (k > p->Data()) {
p = p->RightChild();
}
else {
return true;
}
}
return false;
}
bool Search(const T& k, T& e) {
BinaryTreeNode<T>* p = root;
while (p)
{
if (k < p->Data()) {
p = p->LeftChild();
}
else if (k > p->Data()) {
p = p->RightChild();
}
else {
e = p->Data();
return true;
}
}
return false;
}
bool Search(const T& k, BinaryTreeNode<T>* e) {
BinaryTreeNode<T>* p = root;
while (p)
{
if (k < p->Data()) {
p = p->LeftChild();
}
else if (k > p->Data()) {
p = p->RightChild();
}
else {
e = p;
return true;
}
}
return false;
}
AVLSearchTree<T>& Insert(const T& e) {
BinaryTreeNode<T>* p = root;
BinaryTreeNode<T>* p_p = root;//parent of p
BinaryTreeNode<T>* avl = nullptr;//最近的一个可能不平衡的节点
BinaryTreeNode<T>* p_avl = nullptr;//parent of avl,不平衡节点的父节点
BinaryTreeNode<T>* temp = nullptr;//为进行左旋或右旋后所旋子树的根节点
BinaryTreeNode<T>* temp_ = nullptr;//为进行双旋时所旋子树的根节点
//根不存在时,以被插入元素创建根
if (!root) {
root = new BinaryTreeNode<T>(e);
return *this;
}
//遍历树,找到:
// 插入位置的父节点:p_p
// 最近一个不平衡节点:avl
// avl的父节点:p_avl
while (p)
{
if (p->AVL() != 0) {
avl = p;
p_avl = p_p;
}
//pp为插入位的父节点
p_p = p;
if (e < p->Data()) {
p = p->LeftChild();
}
else if (e > p->Data()) {
p = p->RightChild();
}
else {
return *this;
}
}
//插入新节点
if (e > p_p->Data()) {
p_p->SetRightChild(new BinaryTreeNode<T>(e));
}
else {
p_p->SetLeftChild(new BinaryTreeNode<T>(e));
}
if (!avl) {
//插入前全为平衡节点,插入后无需旋转
return *this;
}
//R型
else if (avl->AVL() == -2) {
temp = avl->RightChild();
//需要进行双旋
/* 平衡因子为-2, 插入后,判断temp的平衡因子为1,需要进行双旋, 以temp的左节点为根(temp_),左子树为avl(设定右孩子为temp_的左孩子),右子树为temp(设定左孩子为temp_的右孩子), */
//RL型
if (temp->AVL() == 1) {
temp_ = temp->LeftChild();
temp_->SetLeftChild(
avl->SetRightChild(
temp_->LeftChild()
)
)
->SetRightChild(
temp->SetLeftChild(
temp_->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp_);
}
else if(p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp_);
}
else {
root = temp_;
}
}
//左旋
/* 插入后,平衡因子为-2, 以temp为子树的根,并修改temp的左节点为avl(avl的右节点修改为原来temp的左节点) */
//RR型
else {
temp->SetLeftChild(
avl->SetRightChild(temp->LeftChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp);
}
else {
root = temp;
}
}
}
//L型
else if (avl->AVL() == 2) {
temp = avl->LeftChild();
//需要进行双旋
/* 平衡因子为2, 插入后,判断temp的平衡因子为-1,需要进行双旋, 以temp的右节点为根(temp_),左子树为temp(设定右孩子为temp_的左孩子),右子树为avl(设定左孩子为temp_的右孩子), */
//LR型
if (temp->AVL()==-1) {
temp_ = temp->RightChild();
temp_->SetLeftChild(
temp->SetRightChild(
temp_->LeftChild()
)
)
->SetRightChild(
avl->SetLeftChild(
temp_->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp_);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp_);
}
else {
root = temp_;
}
}
//右旋
/* 平衡因子为1, 插入后,平衡因子为2, 以temp为子树的根,并修改temp的右节点为avl(avl的左节点修改为原来temp的右节点) */
//LL型
else {
temp->SetRightChild(
avl->SetLeftChild(temp->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp);
}
else {
root = temp;
}
}
}
return *this;
}
AVLSearchTree<T>& Delete(const T& k) {
BinaryTreeNode<T>* p = root;
BinaryTreeNode<T>* p_p = root;//parent of p
BinaryTreeNode<T>* temp = nullptr;//替代被删除位的节点
BinaryTreeNode<T>* p_temp = nullptr;//parent of temp
//找到要删除的元素k
while (p)
{
if (k < p->Data()) {
//pp为删除位的父节点
p_p = p;
p = p->LeftChild();
}
else if (k > p->Data()) {
//pp为删除位的父节点
p_p = p;
p = p->RightChild();
}
else {
break;
}
}
if (!p) {
return *this;
}
//被删除位为子节点,直接删除即可
if (!p->LeftChild() && !p->RightChild()) {
if (p_p->LeftChild() == p) {
p_p->SetLeftChild(nullptr);
_Delete_(p_p->Data());
}
else if (p_p->RightChild() == p) {
p_p->SetRightChild(nullptr);
_Delete_(p_p->Data());
}
else {
root = nullptr;
}
}
//被删除位只有左孩子
else if (p->LeftChild() && !p->RightChild()) {
if (p_p->LeftChild() == p) {
p_p->SetLeftChild(p->LeftChild());
}
else if (p_p->RightChild() == p) {
p_p->SetRightChild(p->LeftChild());
}
else {
root = p->LeftChild();
}
_Delete_(p->LeftChild()->Data());
}
//被删除位只有右孩子
else if (!p->LeftChild() && p->RightChild()) {
if (p_p->LeftChild() == p) {
p_p->SetLeftChild(p->RightChild());
}
else if (p_p->RightChild() == p) {
p_p->SetRightChild(p->RightChild());
}
else {
root = p->RightChild();
}
_Delete_(p->RightChild()->Data());
}
//被删除位的左孩子没有右孩子,用被删除位的左孩子代替
else if (p->LeftChild() && !p->LeftChild()->RightChild()) {
if (p_p->LeftChild() == p) {
p_p->SetLeftChild(p->LeftChild()->SetRightChild(p->RightChild()));
}
else if (p_p->RightChild() == p) {
p_p->SetRightChild(p->LeftChild()->SetRightChild(p->RightChild()));
}
else {
root = p->LeftChild()->SetRightChild(p->RightChild());
}
_Delete_(p->LeftChild()->Data());
}
//用被删除位的右子树的最小孩子代替被删除位
else {
temp = p->RightChild();
while (temp->LeftChild()) {
p_temp = temp;
temp = temp->LeftChild();
}
if (p_temp) {
p_temp->SetLeftChild(temp->RightChild());
}
//被删除位的右孩子没有左孩子,用被删除位的右孩子代替
else {
p->SetRightChild(temp->RightChild());
}
temp->SetLeftChild(p->LeftChild())->SetRightChild(p->RightChild());
if (p_p->LeftChild() == p) {
p_p->SetLeftChild(temp);
}
else if (p_p->RightChild() == p) {
p_p->SetRightChild(temp);
}
else {
root = temp;
}
if (p_temp) {
_Delete_(p_temp->Data());
}
else {
_Delete_(temp->Data());
}
}
return *this;
}
private:
//只在删除迭代时调用,实际并不删除元素,只做旋转
AVLSearchTree<T>& _Delete_(const T& k) {
BinaryTreeNode<T>* p = root;
BinaryTreeNode<T>* p_p = root;//parent of p
BinaryTreeNode<T>* temp = nullptr;//进行左旋或右旋后所旋子树的根节点
BinaryTreeNode<T>* temp_ = nullptr;//为进行双旋时所旋子树的根节点
BinaryTreeNode<T>* avl = nullptr;//最近的一个可能不平衡的节点
BinaryTreeNode<T>* p_avl = nullptr;//parent of avl,不平衡节点的父节点
int temp_type = 0;//判断temp的平衡因子类型
//注释为:测试共调用了多少次旋转
/*static int num = 0; num++; cout << num << endl;*/
//找到要删除的元素k
while (p)
{
if (k < p->Data()) {
if (p->AVL() == -1) {
avl = p;
p_avl = p_p;
}
//pp为删除位的父节点
p_p = p;
p = p->LeftChild();
}
else if (k > p->Data()) {
if (p->AVL() == 1) {
avl = p;
p_avl = p_p;
}
//pp为删除位的父节点
p_p = p;
p = p->RightChild();
}
else {
break;
}
}
if (p->AVL() == -2 || p->AVL() == 2) {
avl = p;
p_avl = p_p;
}
if (!avl) {
//删除前全为平衡节点,删除后无需旋转
return *this;
}
//L型
else if (avl->AVL() == -2) {
temp = avl->RightChild();
temp_type = temp->AVL();
//L1型双旋
if (temp_type == 1) {
temp_ = temp->LeftChild();
temp_->SetLeftChild(
avl->SetRightChild(
temp_->LeftChild()
)
)
->SetRightChild(
temp->SetLeftChild(
temp_->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp_);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp_);
}
else {
root = temp_;
}
//L1型左旋继续迭代
_Delete_(temp_->Data());
}
//L0型左旋和L-1型左旋
else {
temp->SetLeftChild(
avl->SetRightChild(
temp->LeftChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp);
}
else {
root = temp;
}
//L-1型左旋继续迭代
if (temp_type == -1) {
_Delete_(temp->Data());
}
}
}
//R型
else if (avl->AVL() == 2) {
temp = avl->LeftChild();
temp_type = temp->AVL();
//R-1型双旋
if (temp_type == -1) {
temp_ = temp->RightChild();
temp_->SetLeftChild(
temp->SetRightChild(
temp_->LeftChild()
)
)
->SetRightChild(
avl->SetLeftChild(
temp_->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp_);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp_);
}
else {
root = temp_;
}
//R-1型左旋继续迭代
_Delete_(temp_->Data());
}
//R0型左旋和R1型左旋
else {
temp->SetRightChild(
avl->SetLeftChild(
temp->RightChild()
)
);
if (p_avl->LeftChild() == avl) {
p_avl->SetLeftChild(temp);
}
else if (p_avl->RightChild() == avl) {
p_avl->SetRightChild(temp);
}
else {
root = temp;
}
//R1型左旋继续迭代
if (temp_type == 1) {
_Delete_(temp->Data());
}
}
}
return *this;
}
BinaryTreeNode<T>* root;
};
#endif
BinaryTreeNode.h
#pragma once
#ifndef BINARYTREENODE_H
#define BINARYTREENODE_H
template<typename T>
class BinaryTreeNode {
public:
BinaryTreeNode(const T& e) {
this->data = e;
this->leftChild = nullptr;
this->rightChild = nullptr;
}
BinaryTreeNode(const T& e, BinaryTreeNode<T>* l, BinaryTreeNode<T>* r) {
this->data = e;
this->leftChild = l;
this->rightChild = r;
}
BinaryTreeNode(const T& e, const T& l, const T& r) {
BinaryTreeNode(e, new BinaryTreeNode<T>(l), new BinaryTreeNode<T>(r));
}
T Data() {
return data;
}
BinaryTreeNode<T>* LeftChild() {
return leftChild;
}
BinaryTreeNode<T>* RightChild() {
return rightChild;
}
BinaryTreeNode<T>* SetLeftChild(BinaryTreeNode<T>* left) {
this->leftChild = left;
return this;
}
BinaryTreeNode<T>* SetRightChild(BinaryTreeNode<T>* right) {
this->rightChild = right;
return this;
}
int Size() {
if (!this) {
return 0;
}
return leftChild->Size() + rightChild->Size() + 1;
}
int Height() {
if (!this) {
return 0;
}
int l = leftChild->Height();
int r = rightChild->Height();
return (l > r ? l : r) + 1;
}
int AVL() {
return leftChild->Height() - rightChild->Height();
}
void Visit() {
cout << data << " ";
//cout << endl;
}
void PreOrder() {
Visit();
if (leftChild) {
leftChild->PreOrder();
}
if (rightChild) {
rightChild->PreOrder();
}
}
void InOrder() {
if (leftChild) {
leftChild->InOrder();
}
Visit();
if (rightChild) {
rightChild->InOrder();
}
}
void PostOrder() {
if (leftChild) {
leftChild->PostOrder();
}
if (rightChild) {
rightChild->PostOrder();
}
Visit();
}
private:
T data;
BinaryTreeNode<T>* leftChild;
BinaryTreeNode<T>* rightChild;
};
#endif