红黑树
定义:红黑树本质上是一个二叉搜索树,AVL树也是一个二次搜索树,它们之前的不同点在于AVL偏向于查询数据,而红黑树偏向于做增删改查的二叉搜索树(同志们,一定要把二叉搜索树和红黑树区分开来噢)。
首先来介绍一下红黑树经典的五个特性吧
- 根结点一定是黑色的
- "叶子结点"也就是常规意义上的叶子结点左右子树为空,我们假定也为黑色
- 一个结点要么为红色,要么为黑色
- 一个红色结点相邻部分不能为红,太红了不太好
- 黑高要相等——从任意一个节点到其叶子结点所有路径中的黑结点个数相等。这样注意是黑高
上面这些定义,也在一定程度上规定了根到叶子节点最长距离不可以大于两倍的最大可能路径距离。
上面的属性说完了,你会发现其实大致上avl与红黑树中还是很多相同点的。
红黑树的使用场景:
由于红黑树在时间和增删改方面做了一定的compromise,所以我们编程语言中大有身手可以展示,比如在C++中的stl,set、map就很是其底层实现
重点:旋转和颜色变化规则
-
添加结点为红色
-
变色情况——红红相互斥
- 如果出现父节点为红色,叔叔结点为红色,改变父节点和叔叔结点的颜色为黑色,爷爷结点修改为红色
- 如果爷爷结点为根的话,颜色直接翻转过来,如果不是为根的话。把爷爷结点想想成我们刚刚插入的点然后重复上一步,直到遇到根节点
-
旋转情况:当父亲为红色,叔叔结点为黑色,并且当前结点是右子树
- 对父节点进行左旋
-
旋转情况:当父亲为红色,叔叔结点为黑色,并且当前结点是左子树
- 把父节点变成黑色
- 把爷爷结点变成红色
- 对父节点进行右旋
红黑树,到处基本就是这样,现在来一个红黑树入门题:
//题意:给定一组数的前序遍历,求该树是否为red-black-tree
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
vector<int> arr;
struct node{
int data;
struct node *left,*right;
};
node* build(node *root, int v) {
if(root == NULL) {
root = new node();
root->data = v;
root->left = root->right = NULL;
} else if(abs(v) <= abs(root->data))
root->left = build(root->left, v);
else
root->right = build(root->right, v);
return root;
}
bool judge1(node *root)
{
if(root==NULL)
return true;
if(root->data<0)
{
if(root->left->data<0&&root->left!=NULL)
return false;
if(root->right->data<0&&root->right!=NULL)
return false;
}
return judge1(root->left)&&judge1(root->right);
}
int getnum(node *root)
{
if(root==NULL)
return 0;
int l=getnum(root->left);
int r=getnum(root->right);
return root->data>0?max(l,r)+1:max(l,r);
}
bool judge2(node *root)
{
if(root==NULL)
return true;
int l=getnum(root->left);
int r=getnum(root->right);
if(l!=r)
return false;
return judge2(root->left)&&judge2(root->right);
}
int main()
{
int k,n;
scanf("%d",&k);
for(int i=0;i<k;i++)
{
scanf("%d",&n);
arr.resize(n);
node *root=NULL;
for(int j=0;j<n;j++)
{
scanf("%d",&arr[j]);
root=build(root,arr[j]);
}
if (arr[0] < 0 || judge1(root) == false || judge2(root) == false)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}
我人当场爆炸了,tmd,哭了。i,j不分
注:
- 还是老问题,在处理递归问题容易出错,可能题目做的太少了,应该记忆一些常见的递归模板,比如计入一个树的高度,
- 数形结合解决问题
- 一个下午就这样过去了
- 下一篇,介绍树的旋转
注:部分参考于柳神