AVL树
概念
- 背景:二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下,因此两位俄罗斯的数学家G.M.Adelson-Velskii 和 E.M.Landis 在 1962 年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过 1 (需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度;
- 性质:
- 它的左右子树都是 AVL 树;
- 左右子树高度之差 (简称平衡因子) 的绝对值不超过 1 (具体有:-1 / 0 / 1);

- 调整:在插入节点之后,需要向上调整平衡因子,这个很简单,具体看下面的代码,平衡因子调整完毕之后,有可能会导致平衡树不再平衡,所以需要对结构进行调整,这个来具体分析:
假如以 parent 为根的子树不平衡,即 parent 的平衡因子为 2 或者 -2,分以下情况考虑:
- parent 的平衡因子为 2,说明 parent 的右子树高,设 parent 的右子树的根为 subR,设 subR 的左子树的根为 subRL;
- 当 subR 的平衡因子为 1 时,对 parent 执行左单旋,旋转之后 parent 平衡因子为 0,subR 平衡因子为 0(平衡因子的调整在旋转的过程中已经修改了,外部不需要修改);
- 当 subR 的平衡因子为 -1 时,先对 subR 进行右旋,再对 parent 进行左旋,旋转之后,要对平衡因子进行外部调整,平衡因子的调整分为三种情况,设旋转前 subRL 的平衡因子为 bf:
bf == 1
:parent 的平衡因子修改为 -1,subR 的平衡因子修改为 0;bf == -1
:parent 的平衡因子修改为 0,subR 的平衡因子修改为 1;bf == 0
:无需任何改动;
- parent 的平衡因子为 -2,说明 parent 的左子树高,设 parent 的左子树的根为 subL,设 subL 的右子树的根为 subLR;
- 当 subL 的平衡因子为 -1 是,对 parent 执行右单旋,旋转之后 parent 平衡因子为 0,subL 平衡因子为 0(平衡因子的调整在旋转的函数中已经修改了,外部不需要修改);
- 当 subL 的平衡因子为 1 时,先对 subL 进行左旋,再对 parent 进行右旋,旋转之后,要对平衡因子进行外部调整,平衡因子的调整分为两种情况,设旋转前 subLR 的平衡因子为 bf:
bf == 1
:parent 的平衡因子修改为 0,subL 的平衡因子修改为 -1;bf == -1
:parent 的平衡因子修改为 1,subL 的平衡因子修改为 0;bf == 0
:无需任何改动;
- 旋转完成后,原 parent 为根的子树个高度降低,已经平衡,不需要再向上更新;
- 总结:AVL 树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过 1,这样可以保证查询时高效的时间复杂度,即 log2N 。但是如果要对 AVL 树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置;
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑 AVL 树,但一个结构经常修改,就不太适合;
实现
#include<iostream>
using namespace std;
template<class T>
struct AVLNode {
T _data;
int _bf;
AVLNode* _left;
AVLNode* _right;
AVLNode* _parent;
AVLNode(const T& val = T())
:_parent(nullptr)
,_left(nullptr)
,_right(nullptr)
,_data(val)
,_bf(0)
{}
};
template<class T>
class AVLTree {
public:
typedef AVLNode<T> Node;
AVLTree()
:_root(nullptr)
{}
void RotateL(Node* parent) {
Node* node = parent->_right;
Node* nodeleft = node->_left;
parent->_right = nodeleft;
if(nodeleft)
nodeleft->_parent = parent;
if (parent == _root) {
_root = node;
node->_parent = nullptr;
}
else {
Node* tmp = parent->_parent;
node->_parent = tmp;
if (tmp->_left == parent)
tmp->_left = node;
else
tmp->_right = node;
}
parent->_parent = node;
node->_left = parent;
parent->_bf = node->_bf = 0;
}
void RotateR(Node* parent) {
Node* node = parent->_left;
Node* noderight = node->_right;
parent->_left = noderight;
if (noderight)
noderight->_parent = parent;
if (parent == _root) {
_root = node;
node->_parent = nullptr;
}
else {
Node* tmp = parent->_parent;
node->_parent = tmp;
if (tmp->_left = parent)
tmp->_left = node;
else
tmp->_right = node;
}
parent->_parent = node;
node->_right = parent;
parent->_bf = node->_bf = 0;
}
bool insert(const T& val) {
if (_root == nullptr) {
_root = new Node(val);
return true;
}
Node* parent = nullptr;
Node* node = _root;
while (node) {
parent = node;
if (node->_data == val)
return false;
else if (node->_data > val)
node = node->_left;
else
node = node->_right;
}
node = new Node(val);
if (parent->_data > val)
parent->_left = node;
else
parent->_right = node;
node->_parent = parent;
while (parent) {
if (parent->_left == node)
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0)
break;
else if (parent->_bf == -1 || parent->_bf == 1) {
node = parent;
parent = parent->_parent;
}
else if (parent->_bf == -2 || parent->_bf == 2) {
if (parent->_bf == -2 && node->_bf == -1)
RotateR(parent);
else if(parent->_bf == 2 && node->_bf == 1)
RotateL(parent);
else if (parent->_bf == -2 && node->_bf == 1) {
int bf = node->_right->_bf;
RotateL(node);
RotateR(node);
if (bf == -1) {
parent->_bf = 1;
node->_bf = 0;
}
else if (bf == 1) {
parent->_bf = 0;
node->_bf = -1;
}
}
else if (parent->_bf == 2 && node->_bf == -1) {
int bf = node->_left->_bf;
RotateR(node);
RotateL(node);
if (bf == -1) {
parent->_bf = 0;
node->_bf = 1;
}
else if(bf == 1) {
parent->_bf = -1;
node->_bf = 0;
}
}
break;
}
}
return true;
}
void inorder() {
_inorder(_root);
cout << endl;
}
bool isBalance(Node* root) {
if (root == nullptr)
return true;
int left = High(root->_left);
int right = High(root->right);
if (right - left == root->_bf)
return false;
return abs(root->_bf) < 2 && isBalance(root->left) && isBalance(root->right);
}
int High(Node* root) {
if (root == nullptr)
return 0;
int left = High(root->_left);
int right = High(root->_right);
return left > right ? left + 1 : right + 1;
}
private:
void _inorder(Node* root) {
if (root == nullptr)
return;
_inorder(root->_left);
cout << root->_data << " ";
_inorder(root->_right);
}
Node* _root;
};
int main() {
return 0;
}
红黑树
概念
- 概念:红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是 Red 或 Black,通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的;
- 性质:
- 每个结点在插入时,默认是红色的,最后要经过调整,调整之后不是红色就是黑色;
- 根节点是黑色的;
- 如果一个节点是红色的,则它的两个孩子结点是黑色的,也就是不允许出现连续的红色结点;
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点;
- 每个叶子结点都是黑色的 (此处的叶子结点指的是空结点);
- 结构:红黑树中包含了一个头结点,它不包含任何数据,它的父指针指向根结点,左指针指向该树的最左节点,有指针指向该树的最右节点;
插入操作
- 插入操作会有可能改变红黑树的结构,所以需要对红黑树的插入操作进行细细分析,下面是一些会出现的情况,以及做出的应对之法;
- 插入节点的父结点为插入节点的父结点,父节点的父结点为插入节点的祖父节点,祖父节点除过父节点之外的另一个结点为插入节点的叔叔结点;
- 父节点为黑色:直接插入,因为不会破坏红黑树的性质;
- 父节点为红色、叔叔节点存在且为红色:插入后将父结点和叔叔节点都修改为黑色,祖父节点修改为红色,并将祖父节点的位置当做当前位置,向上循环遍历查看情况,直到无连续红色结点即可结束;
- 父节点为红色、叔叔节点不存在或者为黑色:
- 插入节点为父节点的左子树,父节点为祖父节点的左子树:对祖父节点进行右旋,并将祖父节点改为红色,父结点改为黑色;
- 插入节点为父节点的右子树,父节点为祖父节点的左子树:先对父结点进行左旋,旋转后就变成了上一种情况,因此对祖父节点进行右旋,并将祖父节点改为红色,父结点改为黑色;
- 父节点为红色、叔叔节点不存在或者为黑色:
- 插入节点为父节点的右子树,父节点为祖父节点的右子树:对祖父节点进行左旋,并将祖父节点改为红色,父结点改为黑色;
- 插入节点为父节点的左子树,父节点为祖父节点的右子树:先对父结点进行右旋,旋转后就变成了上一种情况,因此对祖父节点进行左旋,并将祖父节点改为红色,父结点改为黑色;
迭代器
- 红黑树的迭代器和链表的迭代器原理是相通的,就是封装了红黑树的结点,然后重载了一些迭代器所能用到的运算符;
- 因为红黑树的性质,所以遍历红黑树可以得到一个有序的序列,所以红黑树的正向迭代器的
++
操作走的是(左中右)的中序遍历移动,而反向迭代器的++
操作走的是(右中左)的中序遍历移动; - 此时我们再回过头来看看,头结点中的左 / 右指针分别指向红黑树的最左 / 右结点,这是非常有意义的,这样
begin()
中封装的就是最左节点,这个刚好是正向遍历的起始位置,rbegin()
中封装的就是最右节点,这正好是反向遍历的起始位置,而end() / rend()
中封装的就是头结点;
实现
- 说明:由于
map
、set
等容器都是由红黑树实现的,所以在红黑树的实现过程中,顺便就将结构设计为方便实现map
、set
的底层结构,这中间的许多细节、要点都写在代码的注释中的,可以仔细查看;
#include<iostream>
using namespace std;
enum COLOR {
BLACK,
RED
};
template<class V>
struct RBNode {
RBNode* _parent;
RBNode* _left;
RBNode* _right;
COLOR _color;
V _val;
RBNode(const V& val = V())
:_parent(nullptr)
,_left(nullptr)
,_right(nullptr)
,_color(RED)
,_val(val)
{}
};
template<class V>
struct RBTreeIterator {
typedef RBNode<V> Node;
typedef RBTreeIterator<V> Self;
Node* _node;
RBTreeIterator(Node* node)
:_node(node)
{}
V& operator*() {
return _node->_val;
}
V* operator->() {
return &(_node->_val);
}
bool operator!=(const Self& it) {
return _node != it._node;
}
Self& operator++() {
if (_node->_right) {
_node = _node->_right;
while (_node->_left)
_node = _node->_left;
}
else {
Node* parent = _node->_parent;
while (parent->_right = _node) {
_node = parent;
parent = _node->_parent;
}
if (_node->_right != parent)
_node = parent;
}
return *this;
}
Self& operator--() {
if (_node->_left) {
_node = _node->_left;
while (_node->_right)
_node = _node->_right;
}
else {
Node* parent = _node->_parent;
while (parent->_left == _node) {
_node = parent;
parent = _node->_parent;
}
if (_node->_left != parent)
_node = parent;
}
return *this;
}
};
template<class K, class V, class keyofval>
class RBTree {
public:
typedef RBNode<V> Node;
typedef RBTreeIterator<V> iterator;
RBTree()
:_header(new Node)
{
_header->_left = _header->_right = _header;
}
iterator begin() {
return iterator(_header->_left);
}
iterator end() {
return iterator(_header);
}
iterator rbegin() {
return iterator(_header->_right);
}
iterator rend() {
return iterator(_header);
}
pair<iterator, bool> insert(const V& val) {
if (_header->_parent == nullptr) {
Node* root = new Node(val);
root->_parent = _header;
_header->_parent = _header->_left = _header->_right = root;
root->_color = BLACK;
return make_pair(iterator(_header->_parent), true);
}
keyofval kov;
Node* parent = nullptr;
Node* cur = _header->_parent;
while (cur) {
parent = cur;
if (kov(cur->_val) == kov(val))
return make_pair(iterator(cur), false);
else if (kov(cur->_val) > kov(val))
cur = cur->_left;
else
cur = cur->_right;
}
cur = new Node(val);
if (kov(parent->_val) > kov(cur))
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
Node* tmp = cur;
while (cur->_color == RED && cur->_parent->_color == RED) {
parent = cur->_parent;
Node* gfather = parent->_parent;
if (gfather->_left == parent) {
Node* uncle = gfather->_right;
if (uncle && uncle->_color == RED) {
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
cur = gfather;
}
else {
if (parent->_right == cur) {
RotateL(parent);
swap(cur, parent);
}
RotaleR(gfather);
parent->_color = BLACK;
gfather->_color = RED;
break;
}
}
else{
Node* uncle = gfather->_right;
if (uncle && uncle->_color == RED) {
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
cur = gfather;
}
else {
if (parent->_left == cur) {
RotateR(parent);
swap(cur, parent);
}
RotaleL(gfather);
parent->_color = BLACK;
gfather->_color = RED;
break;
}
}
}
_header->_parent->_color = BLACK;
_header->_left = LeftMost();
_header->_right = RightMost();
return make_pair(iterator(tmp), true);
}
bool isBalance() {
if (_header->_parent == nullptr)
return true;
if (_header->_parent->_color == RED)
return false;
int count = 0, num = 0;
Node* cur = _header->_parent;
while (cur) {
if (cur->_color == BLACK)
num++;
cur = cur->_left;
}
return _isBalance(_header->_parent, count, num);
}
void inorder() {
_inorder(_header->_parent);
cout << endl;
}
private:
void RotateL(Node* cur) {
Node* curR = cur->_right;
Node* curRL = curR->_left;
cur->_right = curRL;
curR->_left = cur;
if (curRL)
curRL->_parent = cur;
if (cur == _header->_parent) {
_header->_parent = curR;
curR->_parent = _header;
}
else {
Node* node = cur->_parent;
curR->_parent = node;
if (node->_left == cur)
node->_left = curR;
else
node->_right = curR;
}
cur->_parent = curR;
}
void RotateR(Node* cur) {
Node* curL = cur->_left;
Node* curLR = curL->_right;
cur->_left = curLR;
curL->_right = cur;
if (curLR)
curLR->_parent = cur;
if (cur == _header->_parent) {
_header->_parent = curL;
curL->_parent = _header;
}
else {
Node* node = cur->_parent;
curL->_parent = node;
if (node->_left == cur)
node->_left = curL;
else
node->_right = curL;
}
cur->_parent = curL;
}
Node* LeftMost() {
Node* cur = _header->_parent;
while (cur && cur->_left)
cur = cur->_left;
return cur;
}
Node* RightMost() {
Node* cur = _header->_parent;
while (cur && cur->_right)
cur = cur->_right;
return cur;
}
bool _isBalance(Node* node, int count, int num) {
if (node == nullptr)
return count == num;
if (node->_parent && node->_color == RED && node->_parent->_color == RED)
return false;
if (node->_color == BLACK)
count++;
return _isBalance(node->_left, count, num)
&& _isBalance(node->_right, count, num);
}
void _inorder(Node* root) {
if (root) {
_inorder(root->_left);
cout << root->_val << ' ';
_inorder(root->_right);
}
}
Node* _header;
};
int main() {
return 0;
}
map
与set
的简单实现
代码
template<class K, class V>
class Map {
struct keyofval {
const K& operator()(const pair<K, V>& val) {
return val.first;
}
};
RBTree<K, pair<K, V>, keyofval> rbt;
public:
typedef typename RBTree<K, pair<K, V>, keyofval>::iterator iterator;
pair<iterator, bool> insert(const pair<K, V>& kv) {
return rbt.insert(kv);
}
iterator begin() {
return rbt.begin();
}
iterator end() {
return rbt.end();
}
iterator rbegin() {
return rbt.rbegin();
}
iterator rend() {
rbt.rend();
}
V& operator[](const K& key) {
pair<iterator, bool> ret = rbt.insert(make_pair(key, V()));
return ret.first->second;
}
};
template<class V>
class Set {
struct keyofval {
const V& operator()(const V& key) {
return key;
}
};
RBTree<V, V, keyofval> rbt;
public:
typedef typename RBTree<V, V, keyofval>::iterator iterator;
pair<iterator, bool> insert(const V& val) {
return rbt.insert(val);
}
};