#pragma once
#include <iostream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <assert.h>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _bf(0)
{}
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
//为了实现通过孩子找父亲,会在AVLTree的每个结点中多加一个成员
// 这个成员是 指向其父亲结点的 指针
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf;
};
//AVL树 是 平衡二叉树 和 搜索二叉树的交集
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
// AVL树的insert方法必须满足的条件
// 按搜索树的的规则插入,按平衡二叉树的规则更新 _bf因子:
// 平衡衡二叉树的规则:
// rule0: 树中每一个结点的左右子树的高度之差的绝对值小于等于1
// 更新_bf 因子的规则如下:
// rule1: _bf = 右子树的高度 - 左子树的高度
// case1.1: 插入的结点是其父亲结点的左孩子,那么应将该父亲结点的平衡因子 减 1
// case1.2: 插入的结点是其父亲结点的右孩子,那么应将该父亲结点的平衡因子 加 1
// rule2: 每次插入结点时,要不断更新这个新结点 对应的祖先 的_bf因子
// 更新的情况有以下几种:下面称当前更新到的结点的父亲结点为α
// case2.1: α的平衡因子 == 0,父亲的两颗子树的高度不变,不再继续往上更新,插入结束
// case2.2: α的平衡因子 == 1或-1,父亲有一颗子树的高度变了,继续往上更新
// case2.3: α的平衡因子 == 2或-2,父亲的两颗子树已经不满足rule0,需要旋转处理
// 注意:由于AVLTree类创建的对象全是平衡二叉树,那么插入节点后 按照rule2更新完平衡因子之后
// 结点的平衡因子应仍然只从 -1,1,0这三个值中取值
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent)
{
if (cur == parent->_left)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
if (parent->_bf == 0)
{
//更新结束
break;
}
else if ((parent->_bf == 1) || (parent->_bf == -1))
{
//继续往上更新
cur = parent;
parent = parent->_parent;
}
else if ((parent->_bf == 2) || (parent->_bf == -2))
{
//需要通过旋转调整当前所遍历到的结点的左右子树的高度
if (parent->_bf == -2 && cur->_bf == -1)
{
Rotateright(parent);
}
else if (parent->_bf == 2 && cur->_bf == 1)
{
Rotateleft(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
}
else
{
}
break;
}
else
{
assert(false);
}
}
return true;
}
Node* Find(const pair<K, V>& kv)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return cur;
}
// bool Erase(const K& key)
// {
// if (_root == nullptr)
// {
// return false;
// }
// Node* parent = nullptr;
// Node* cur = _root;
// while (cur)
// {
// if (cur->_key < key)
// {
// parent = cur;
// cur = cur->_right;
// }
// else if (cur->_key > key)
// {
// parent = cur;
// cur = cur->_left;
// }
//
// else
// {
// if (cur->_left == nullptr)
// {
// if (cur == _root)
// {
// _root = cur->_right;
// }
// else
// {
// if (cur == parent->_left)
// {
// parent->_left = cur->_right;
// }
// else
// {
// parent->_right = cur->_right;
// }
// }
// }
// else if (cur->_right == nullptr)
// {
// if (cur == _root)
// {
// _root = cur->_left;
// }
// else
// {
// if (cur == parent->_left)
// {
// parent->_left = cur->_left;
// }
// else
// {
// parent->_right = cur->_left;
// }
// }
// }
// else
// {
// Node* rightMinParent = cur;
// Node* rightMin = cur->_right;
// while (rightMin->_left)
// {
// rightMinParent = rightMin;
// rightMin = rightMin->_left;
// }
// swap(cur->_key, rightMin->_key);
//
// if (rightMinParent->_left == rightMin)
// {
// rightMinParent->_left = rightMin->_right;
// }
// else
// {
// rightMinParent->_right = rightMin->_right;
// }
// delete rightMin;
// }
// return true;
// }
// }
// return false;
// }
//
void InOrder()
{
shelledInOrder(_root);
cout << endl;
}
// 旋转的本质:
// 在最小的范围内将一个结点的
// 左子树的一部分链接到右子树上 或 右子树的一部分链接到左子树上
// 旋转后达到的结果:
// 1. 该节点的左右子树 高度相同,即平衡了
// 2. 该节点对应下的整棵树 与 旋转前的树 高度相同
// 要对 结点进行右旋来调成平衡,这个结点的左右子树需要满足的条件有:
// 1. 这个结点的左子树的高度比右子树的高度 高两层
// 表现为 增加了新的结点之后,左子树的高度 加一
// 2. 而且无法通过只改变左子树内部的连接关系就把高度减小
// 表现为 增加了新的结点之后,左子树内部还是平衡的
void Rotateright(Node* parent)
{
//右旋要看四个结点,三个双向链接,两种特殊情况
//四个结点:
// 1. 当前结点 2. 当前结点的父节点
// 3. 当前结点的左孩子 4. 当前结点的左孩子的右孩子结点
//三个双向链接:
// 一、 2. 和 1. 的父子关系
// 二、 1. 和 3. 的父子关系
// 三、 3. 和 4. 的父子关系
//两种特殊情况:
// case1: 1. 就是整棵树的 根节点,导致一、需要加if() else{}判断
// case2: 4. 是一个空结点,导致三、需要加if() else{}判断
Node* subLnode = parent->_left;
Node* subLRnode = subLnode->_right;
Node* pPnode = parent->_parent;
parent->_left = subLRnode;
if (subLRnode)
{
subLRnode->_parent = parent;
}
subLnode->_right = parent;
parent->_parent = subLnode;
if (parent == _root)
{
_root = subLnode;
_root->_parent = nullptr;
}
else
{
if (pPnode->_left == parent)
{
pPnode->_left = subLnode;
}
else
{
pPnode->_right = subLnode;
}
subLnode->_parent = pPnode;
}
//注意!!!!!!!!!!!!!!!!!!!!!!!
//右旋的结果是:
// 1. 将所针对的结点和该结点的左孩子结点的父子关系颠倒
// 2. 将所针对结点 和 该节点的左孩子结点的 平衡因子调为0
parent->_bf = subLnode->_bf = 0;
}
void Rotateleft(Node* parent)
{
Node* subRnode = parent->_right;
Node* subRLnode = subRnode->_left;
Node* pPnode = parent->_parent;
parent->_right = subRLnode;
if (subRLnode)
{
subRLnode->_parent = parent;
}
subRnode->_left = parent;
parent->_parent = subRnode;
if (parent == _root)
{
_root = subRnode;
_root->_parent = nullptr;
}
else
{
if (pPnode->_left == parent)
{
pPnode->_left = subRnode;
}
else
{
pPnode->_right = subRnode;
}
subRnode->_parent = pPnode;
}
parent->_bf = subRnode->_bf = 0;
}
private:
void shelledInOrder(Node* root)
{
if (root == nullptr)
{
return;
}
shelledInOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
shelledInOrder(root->_right);
}
private:
Node* _root = nullptr;
};
void testAVLTree1()
{
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
AVLTree<int, int> t1;
for (auto e : a)
{
t1.Insert({e, e});
}
t1.InOrder();
}
//void testBSTree2()
//{
// key_value::BSTree<string, string> dict;
// dict.Insert("string", "字符串");
// dict.Insert("left", "左");
// dict.Insert("insert", "插入");
//
// string str;
// while (cin >> str)
// {
// key_value::BSTreeNode<string, string>* ret = dict.Find(str);
// if (ret)
// {
// cout << ret->_value << endl;
// }
// else
// {
// cout << "无此单词,请重新输入" << endl;
// }
// }
//
//}
//
//void testBSTree3()
//{
// string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "西瓜", "西瓜" };
// key_value::BSTree<string, int> countTree;
// for (const auto& str : arr)
// {
// auto ret = countTree.Find(str);
// if (ret == nullptr)
// {
// countTree.Insert(str, 1);
// }
// else
// {
// ret->_value++;
// }
// }
// countTree.InOrder();
//}