发现了一个avl树的在线动画https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
平衡树节点
#pragma once
//平衡树节点
template<typename T>
class AVLTreeNode {
public:
//关键字
T value;
//左子树
AVLTreeNode* left;
//右子树
AVLTreeNode* right;
//高度
int height;
AVLTreeNode() :height(1), left(nullptr), right(nullptr) {}
AVLTreeNode(const T &value) :value(value), height(1), left(nullptr), right(nullptr) {}
};
旋转
LL型(右旋)
template<typename T>
AVLTreeNode<T>* AVLTree<T>::LeftLeftRotation(AVLTreeNode<T>* rt)
{
AVLTreeNode<T>* temp = rt->left;
rt->left = temp->right;
temp->right = rt;
updateHeight(rt);
updateHeight(temp);
return temp;
}
RR型(左旋)
template<typename T>
AVLTreeNode<T>* AVLTree<T>::RightRightRotation(AVLTreeNode<T>* rt)
{
AVLTreeNode<T>* temp = rt->right;
rt->right = temp->left;
temp->left = rt;
updateHeight(rt);
updateHeight(temp);
return temp;
}
LR型
先对左子树RR旋转(左旋)
后对根LL旋转(右旋)
template<typename T>
AVLTreeNode<T>* AVLTree<T>::LeftRightRotation(AVLTreeNode<T>* rt)
{
rt->left = RightRightRotation(rt->left);
return LeftLeftRotation(rt);
}
RL型
先对右子树LL旋转(右旋)
后对根RR旋转(左旋)
template<typename T>
AVLTreeNode<T>* AVLTree<T>::RightLeftRotation(AVLTreeNode<T>* rt)
{
rt->right = LeftLeftRotation(rt->right);
return RightRightRotation(rt);
}
删除
左子树为空则用右子树代替
右子树为空则用左子树代替
否则如果左子树比右子树高或一样
则用左子树上的最大值替换,再删除左子树的最大值
如果右子树比左子树高
则用右子树的最小值替换,再删除右子树的最小值
template<typename T>
AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* rt, const T & value)
{
if (rt == nullptr)return nullptr;
//要删的节点在左子树
if (value < rt->value) {
rt->left = remove(rt->left, value);
//失衡
if (getHeight(rt->right) - getHeight(rt->left) == 2) {
AVLTreeNode<T>* right = rt->right;
//右子树的左子树失衡,进行RL旋转
if (getHeight(right->left) > getHeight(right->right)) {
rt = RightLeftRotation(rt);
}
//右子树的右子树失衡,进行RR旋转
else {
rt = RightRightRotation(rt);
}
}
}
//要删的节点在右子树
else if (value > rt->value) {
rt->right = remove(rt->right, value);
//失衡
if (getHeight(rt->left) - getHeight(rt->right) == 2) {
AVLTreeNode<T>* left = rt->left;
//左子树的左子树失衡,进行LL旋转
if (getHeight(left->left) >= getHeight(left->right)) {
rt = LeftLeftRotation(rt);
}
//左子树的右子树失衡,进行LR旋转
else {
rt = LeftRightRotation(rt);
}
}
}
//就删这
else {
//左子树或右子树是空的
if (rt->left == nullptr || rt->right == nullptr) {
AVLTreeNode<T>* removeNode = rt;
if (rt->left == nullptr)rt = rt->right;
else rt = rt->left;
delete removeNode;
}
//左子树比右子树高或者一样高
else if (getHeight(rt->left) >= getHeight(rt->right)) {
AVLTreeNode<T>* maxNode = getMax(rt->left);
rt->value = maxNode->value;
rt->left = remove(rt->left, maxNode->value);
}
//右子树比左子树高
else {
AVLTreeNode<T>* minNode = getMin(rt->right);
rt->value = minNode->value;
rt->right = remove(rt->right, minNode->value);
}
}
return rt;
}
完整版
头文件AVLTree.h
#pragma once
#include "AVLTreeNode.h"
//平衡树
template<typename T>
class AVLTree {
private:
AVLTreeNode<T>* root;
/*
更新以rt为根节点的树的高度
@param rt 根节点
*/
void updateHeight(AVLTreeNode<T> * rt);
/*
获得以tree为根节点的树的高度
@param tree 树
*/
int getHeight(AVLTreeNode<T>* tree) const;
/*
对以rt根节点的树进行右旋(LL旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
AVLTreeNode<T>* LeftLeftRotation(AVLTreeNode<T>* rt);
/*
对以rt根节点的树进行左旋(RR旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
AVLTreeNode<T>* RightRightRotation(AVLTreeNode<T>* rt);
/*
对以rt根节点的树的进行LR旋转
先对rt的左子树做左旋(RR旋转),然后对rt进行右旋(LL旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
AVLTreeNode<T>* LeftRightRotation(AVLTreeNode<T>* rt);
/*
对以rt根节点的树的进行RL旋转
先对rt的右子树做右旋(LL旋转),然后对rt进行左旋(RR旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
AVLTreeNode<T>* RightLeftRotation(AVLTreeNode<T>* rt);
/*
插入值为value的节点
@param value 要插入的值
@return 插入节点后的树
*/
/*
对以rt为根节点的树插入值为value的节点
@param rt 要插入的树
@param value 要插入的值
@return 插入节点后的树
*/
AVLTreeNode<T>* insert(AVLTreeNode<T>* rt, const T &value);
/*
对以rt为根节点的树删除值为value的节点
@param rt 要删除的树
@param value 要删除的值
@return 删除节点后的树
*/
AVLTreeNode<T>* remove(AVLTreeNode<T>* rt, const T &value);
/*
对以rt为根节点的树寻找拥有最大值的节点
@param rt 要找的树
@return 包含最大值的节点
*/
AVLTreeNode<T>* getMax(AVLTreeNode<T>* rt);
/*
对以rt为根节点的树寻找拥有最小值的节点
@param rt 要找的树
@return 包含最小值的节点
*/
AVLTreeNode<T>* getMin(AVLTreeNode<T>* rt);
/*
对以rt为根节点的树进行销毁
@param rt 要销毁的树
*/
void destory(AVLTreeNode<T>* rt);
/*
对以rt为根节点的树进行前序遍历
@param rt 根节点
*/
void preOrder(AVLTreeNode<T>* rt) const;
/*
对以rt为根节点的树进行中序遍历
@param rt 根节点
*/
void inOrder(AVLTreeNode<T>* rt) const;
/*
对以rt为根节点的树进行后序遍历
@param rt 根节点
*/
void postOrder(AVLTreeNode<T>* rt) const;
/*
对以rt为根节点的树进行层遍历
@param rt 根节点
*/
void layerOrder(AVLTreeNode<T>* rt) const;
/*
对以rt为根节点的树查找值为value的节点
@param rt 根节点
@param value 查找的值
@return 包含value的节点
*/
AVLTreeNode<T>* search(AVLTreeNode<T>* rt, const T &value) const;
public:
AVLTree();
~AVLTree();
//获得树的高度
int getHeight() const;
/*
插入值为value的节点
@param value 要插入的值
*/
void insert(const T &value);
/*
删除值为value的节点
@param value 要删除的值
*/
void remove(const T &value);
//前序遍历
void preOrder() const;
//中序遍历
void inOrder() const;
//后序遍历
void postOrder() const;
//层序遍历
void layerOrder() const;
/*
查找值为value的节点
@param value 查找的值
@return 包含value的节点
*/
AVLTreeNode<T>* search(const T &value) const;
//销毁树
void destory();
};
cpp文件AVLTree.cpp
#include "AVLTree.h"
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
/*
对以rt为根节点的树删除值为value的节点
@param rt 要删除的树
@param value 要删除的值
@return 删除节点后的树
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* rt, const T & value)
{
if (rt == nullptr)return nullptr;
//要删的节点在左子树
if (value < rt->value) {
rt->left = remove(rt->left, value);
//失衡
if (getHeight(rt->right) - getHeight(rt->left) == 2) {
AVLTreeNode<T>* right = rt->right;
//右子树的左子树失衡,进行RL旋转
if (getHeight(right->left) > getHeight(right->right)) {
rt = RightLeftRotation(rt);
}
//右子树的右子树失衡,进行RR旋转
else {
rt = RightRightRotation(rt);
}
}
}
//要删的节点在右子树
else if (value > rt->value) {
rt->right = remove(rt->right, value);
//失衡
if (getHeight(rt->left) - getHeight(rt->right) == 2) {
AVLTreeNode<T>* left = rt->left;
//左子树的左子树失衡,进行LL旋转
if (getHeight(left->left) >= getHeight(left->right)) {
rt = LeftLeftRotation(rt);
}
//左子树的右子树失衡,进行LR旋转
else {
rt = LeftRightRotation(rt);
}
}
}
//就删这
else {
//左子树或右子树是空的
if (rt->left == nullptr || rt->right == nullptr) {
AVLTreeNode<T>* removeNode = rt;
if (rt->left == nullptr)rt = rt->right;
else rt = rt->left;
delete removeNode;
}
//左子树比右子树高或者一样高
else if (getHeight(rt->left) >= getHeight(rt->right)) {
AVLTreeNode<T>* maxNode = getMax(rt->left);
rt->value = maxNode->value;
rt->left = remove(rt->left, maxNode->value);
}
//右子树比左子树高
else {
AVLTreeNode<T>* minNode = getMin(rt->right);
rt->value = minNode->value;
rt->right = remove(rt->right, minNode->value);
}
}
return rt;
}
/*
对以rt为根节点的树寻找拥有最大值的节点
@param rt 要找的树
@return 包含最大值的节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::getMax(AVLTreeNode<T>* rt)
{
if (rt == nullptr)return nullptr;
AVLTreeNode<T>* temp = rt;
while (temp->right != nullptr)temp = temp->right;
return temp;
}
/*
对以rt为根节点的树寻找拥有最小值的节点
@param rt 要找的树
@return 包含最小值的节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::getMin(AVLTreeNode<T>* rt)
{
if (rt == nullptr)return nullptr;
AVLTreeNode<T>* temp = rt;
while (temp->left != nullptr)temp = temp->left;
return temp;
}
/*
对以rt为根节点的树进行销毁
@param rt 要销毁的树
*/
template<typename T>
void AVLTree<T>::destory(AVLTreeNode<T>* rt)
{
if (rt == nullptr)return;
if (rt->left != nullptr)destory(rt->left);
if (rt->right != nullptr)destory(rt->right);
delete rt;
}
/*
对以rt为根节点的树进行前序遍历
@param rt 根节点
*/
template<typename T>
void AVLTree<T>::preOrder(AVLTreeNode<T>* rt) const
{
if (rt == nullptr)return;
cout << rt->value << ' ';
if (rt->left != nullptr)preOrder(rt->left);
if (rt->right != nullptr)preOrder(rt->right);
}
/*
对以rt为根节点的树进行中序遍历
@param rt 根节点
*/
template<typename T>
void AVLTree<T>::inOrder(AVLTreeNode<T>* rt) const
{
if (rt == nullptr)return;
if (rt->left != nullptr)inOrder(rt->left);
cout << rt->value << ' ';
if (rt->right != nullptr)inOrder(rt->right);
}
/*
对以rt为根节点的树进行后序遍历
@param rt 根节点
*/
template<typename T>
void AVLTree<T>::postOrder(AVLTreeNode<T>* rt) const
{
if (rt == nullptr)return;
if (rt->left != nullptr)postOrder(rt->left);
if (rt->right != nullptr)postOrder(rt->right);
cout << rt->value << ' ';
}
/*
对以rt为根节点的树进行层遍历
@param rt 根节点
*/
template<typename T>
void AVLTree<T>::layerOrder(AVLTreeNode<T>* rt) const
{
queue<AVLTreeNode<T>*> q;
if (rt != nullptr)q.push(rt);
while (!q.empty()) {
AVLTreeNode<T>* temp = q.front();
q.pop();
cout << temp->value << ' ';
if (temp->left != nullptr)q.push(temp->left);
if (temp->right != nullptr)q.push(temp->right);
}
}
/*
对以rt为根节点的树查找值为value的节点
@param rt 根节点
@param value 查找的值
@return 包含value的节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::search(AVLTreeNode<T>* rt, const T & value) const
{
while (rt != nullptr&&rt->value != value) {
if (value < rt->value)rt = rt->left;
else if (value > rt->value)rt = rt->right;
else break;
}
return rt;
}
template<typename T>
AVLTree<T>::AVLTree():root(nullptr)
{
}
template<typename T>
AVLTree<T>::~AVLTree()
{
destory();
}
/*
获得以tree为根节点的树的高度
@param tree 树
*/
template<typename T>
int AVLTree<T>::getHeight(AVLTreeNode<T>* tree) const
{
if (tree == nullptr)return 0;
return tree->height;
}
/*
对以rt根节点的树进行右旋(LL旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::LeftLeftRotation(AVLTreeNode<T>* rt)
{
AVLTreeNode<T>* temp = rt->left;
rt->left = temp->right;
temp->right = rt;
updateHeight(rt);
updateHeight(temp);
return temp;
}
/*
对以rt根节点的树进行左旋(RR旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::RightRightRotation(AVLTreeNode<T>* rt)
{
AVLTreeNode<T>* temp = rt->right;
rt->right = temp->left;
temp->left = rt;
updateHeight(rt);
updateHeight(temp);
return temp;
}
/*
对以rt根节点的树的进行LR旋转
先对rt的左子树做左旋(RR旋转),然后对rt进行右旋(LL旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::LeftRightRotation(AVLTreeNode<T>* rt)
{
rt->left = RightRightRotation(rt->left);
return LeftLeftRotation(rt);
}
/*
对以rt根节点的树的进行RL旋转
先对rt的右子树做右旋(LL旋转),然后对rt进行左旋(RR旋转)
@param rt 要旋转的树的根节点
@return 旋转后的根节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::RightLeftRotation(AVLTreeNode<T>* rt)
{
rt->right = LeftLeftRotation(rt->right);
return RightRightRotation(rt);
}
/*
插入值为value的节点
@param value 要插入的值
*/
template<typename T>
void AVLTree<T>::insert(const T & value)
{
//insert(root, value);
root = insert(root, value);
}
/*
删除值为value的节点
@param value 要删除的值
*/
template<typename T>
void AVLTree<T>::remove(const T & value)
{
root = remove(root, value);
}
//前序遍历
template<typename T>
void AVLTree<T>::preOrder() const
{
preOrder(root);
cout << endl;
}
template<typename T>
void AVLTree<T>::inOrder() const
{
inOrder(root);
cout << endl;
}
template<typename T>
void AVLTree<T>::postOrder() const
{
postOrder(root);
cout << endl;
}
//层序遍历
template<typename T>
void AVLTree<T>::layerOrder() const
{
layerOrder(root);
cout << endl;
}
/*
查找值为value的节点
@param value 查找的值
@return 包含value的节点
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::search(const T & value) const
{
return search(root, value);
}
//销毁树
template<typename T>
void AVLTree<T>::destory()
{
destory(root);
}
/*
对以rt为根节点的树插入值为value的节点
@param rt 要插入的树
@param value 要插入的值
@return 插入节点后的树
*/
template<typename T>
AVLTreeNode<T>* AVLTree<T>::insert(AVLTreeNode<T>* rt, const T & value)
{
//就插这
if (rt == nullptr) {
rt = new AVLTreeNode<T>(value);
}
//插左边
else if (value < rt->value) {
rt->left = insert(rt->left, value);
//左子树比右子树高2,失衡了
if (getHeight(rt->left) - getHeight(rt->right) == 2) {
//插入在左子树的左子树上,说明要LL旋转
if (value < rt->left->value) {
rt = LeftLeftRotation(rt);
}
//插入在左子树的右子树上,说明要LR旋转
else {
rt = LeftRightRotation(rt);
}
}
}
//插右边
else if (value > rt->value) {
rt->right = insert(rt->right, value);
//右子树比左子树高2,失衡了
if (getHeight(rt->right) - getHeight(rt->left) == 2) {
//插入在右子树的左子树上,说明要RL旋转
if (value < rt->right->value) {
rt = RightLeftRotation(rt);
}
//插入在右子树的右子树上,说明要RR旋转
else {
rt = RightRightRotation(rt);
}
}
}
//插入了重复的数据
else {
return rt;
}
//更新高度
updateHeight(rt);
return rt;
}
/*
更新以rt为根节点的树的高度
@param rt 根节点
*/
template<typename T>
void AVLTree<T>::updateHeight(AVLTreeNode<T>* rt)
{
if (rt == nullptr)return;
rt->height = max(getHeight(rt->left), getHeight(rt->right)) + 1;
}
//获得树的高度
template<typename T>
int AVLTree<T>::getHeight() const
{
return getHeight(root);
}
main.cpp
使用模板貌似要引入.cpp文件而不是.h
#include<iostream>
#include "AVLTree.cpp"
using namespace std;
int main() {
int arr[] = { 3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9 };
AVLTree<int> t;
for (int a : arr)
t.insert(a);
t.preOrder();
t.inOrder();
t.remove(13);
t.preOrder();
t.inOrder();
t.remove(4);
t.preOrder();
t.inOrder();
return 0;
}