想了解红黑树,首先需要对AVL树有一定的认识.点击上篇博客浅浅学习一下吧~AVL树
AVL树绝对平衡[左右高度不超过1]===>红黑树近似平衡–最长路径不超过最短路径的2倍
查找:AVL- logN 红黑树 logN~2logN
插入/删除:红黑树旋转次数较少
红黑树是一种自平衡的二叉查找树,不同的是在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径长度是其他路径的两倍,因而接近平衡。
因为以下这种情况:
二叉搜索树,插入数据随机时接近平衡二叉树,操作效率(查询,插入,删除)效率较高,时间复杂度是O(logN)。但是当插入数据有序(递增或者递减),那么所有节点都会在一侧,此时,二叉搜索树成了一个链表,操作效率降低了,时间复杂度为O(N).
出现了AVL树,但是AVL树每插入/删除都要旋转处理,成本高,于是出现了红黑树.需要注意的是:
红黑树具备了二叉搜索树的某些特性,它是一种接近平衡的二叉树(它没有AVL树平衡因子的概念,仅靠5条性质来维持一种接近平衡的结构)。
拓展性质
思考:以上5条性质如何使得其最长路径中节点个数不会超过最短路径节点个数的两倍?
插入一个红色结点可能会出现的情况
默认插入结点为红色
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//颜色枚举
enum Colour
{
RED,
BLACK
};
//结点类
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
{
}
};
//RBTree类
template<class K, class V>
struct RBTree
{
typedef RBTreeNode<K, V> Node;
public:
//插入创建红黑树
bool Insert(const pair<K, V>& kv)
{
///二叉搜索树插入///
//根节点为空
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK; //根节点颜色为黑
return true;
}
//不为空 定位至合适位置
Node* dad = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
dad = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
dad = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//父连接子
cur = new Node(kv);
cur->_col = RED;
if (dad->_kv.first < kv.first)
{
dad->_right = cur;
}
else
{
dad->_left = cur;
}
//子继承父
cur->_parent = dad;
构建红黑树
//cur[红]此时定位新插入位置 若父为红
while (dad && dad->_col == RED)
{
//dad && dad->_col == RED
//二次循环来到此处
// 1.父为空 则cur为根 [最后控制cur变黑] 循环结束
// 2.父为黑 无需操作
Node* grandpa = dad->_parent;
//若父为红 祖父定存在且为黑
assert(grandpa);
assert(grandpa->_col == BLACK);
/判断uncle位置///
//父为左子树 uncle为右子树
if (dad == grandpa->_left)
{
Node* uncle = grandpa->_right;
//情况一、uncle存在为红 变色+回溯
//dad-uncle变黑 grandpa变红
if (uncle && uncle->_col == RED)
{
//变色
dad->_col = uncle->_col = BLACK;
grandpa->_col = RED;
//回溯
cur = grandpa;
dad = cur->_parent;
}
//情况二-三:uncle不存在 存在且为黑
else
{
if (cur == dad->_left)
{
//情况二:右单旋+变色
RotateR(grandpa);
dad->_col = BLACK;
grandpa->_col = RED;
}
else
{
//情况三:左右双旋+变色
RotateL(dad);
RotateR(grandpa);
cur->_col = BLACK;
grandpa->_col = RED;
}
break;
}
}
//父为右子树 uncle为左子树
else
{
Node* uncle = grandpa->_left;
//情况一
if (uncle && uncle->_col == RED)
{
//变色
dad->_col = uncle->_col = BLACK;
grandpa->_col = RED;
//回溯
cur = grandpa;
dad = cur->_parent;
}
else
{
if (cur == dad->_right)
{
//情况二:左单旋+变色
RotateL(grandpa);
dad->_col = BLACK;
grandpa->_col = RED;
}
else
{
//情况三:右左单旋+变色
RotateR(dad);
RotateL(grandpa);
cur->_col = BLACK;
grandpa->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
//中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//判断是否是红黑树
bool IsRBTree()
{
///空树默认为真
if (_root == nullptr)
{
return true;
}
//根节点颜色
if (_root->_col == RED)
{
cout << "根结点颜色错误!" << endl;
return false;
}
//某一条路径黑色结点数量
int certain = 0;
return PrevJudge(_root, 0, certain);
}
private:
//BNcount: black node count
bool PrevJudge(Node* root, int BNcount, int& certain)
{
//遇空 -- 当前路径结束
if (root == nullptr)
{
//指向此if时 某一条路径已结束 且 为第一条路径[第一次传参]
if (certain == 0)
{
certain = BNcount;
return true;
}
//判断性质4
if (BNcount != certain)
{
cout << "性质4违例:存在某一路径黑色节点的数量不等!" << endl;
return false;
}
else
{
return true;
}
}
//遇黑--值++
if (root->_col == BLACK)
{
++BNcount;
}
//遇红--连坐判断
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "性质3违例: 存在连续红节点!" << endl;
return false;
}
return PrevJudge(root->_left, BNcount, certain)
&& PrevJudge(root->_right, BNcount, certain);
}
//中序遍历
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* grandpa = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (grandpa->_left == parent)
{
grandpa->_left = subR;
}
else
{
grandpa->_right = subR;
}
subR->_parent = grandpa;
}
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* grandpa = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (grandpa->_left == parent)
{
grandpa->_left = subL;
}
else
{
grandpa->_right = subL;
}
subL->_parent = grandpa;
}
}
private:
Node* _root = nullptr;
};
void TestRBTree1()
{
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
int b[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
int c[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 0, 5, 30, 25, 20, 4, 13, 30, 28,27 };
RBTree<int, int> tree;
for (auto e : c)
{
tree.Insert(make_pair(e, e));
}
cout << "此树中序遍历" << endl;
tree.InOrder();
if (tree.IsRBTree())
{
cout << "此树为红黑树!" << endl;
}
else
{
cout << "此树不是红黑树!" << endl;
}
}
void TestRBTree2()
{
srand(time(0));
size_t N = 10;
RBTree<int, int> tree;
for (size_t i = 0; i < N; ++i)
{
int x = rand();
cout << "Insert:" << x << ":" << i << endl;
tree.Insert(make_pair(x, i));
}
if (tree.IsRBTree())
{
cout << "此树为红黑树!" << endl;
}
else
{
cout << "此树不是红黑树!" << endl;
}
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#include "RedBlackTree.h"
int main()
{
TestRBTree2();
return 0;
}
~RBTree()
{
_Destroy(_root);
_root=nullptr;
}
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}