红黑树的创建
时间:2022-07-23
本文章向大家介绍红黑树的创建,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
红黑树的创建
在二叉查找树的最后提到, 二叉树最终的形状如下图所示:
实际上,为了避免二叉树形状向最坏情况靠拢, 通常会创建能够自平衡的 2-3 树。 而 红黑树 是 2-3 树比较简单的一种实现形式:
- 红黑树将用二叉树表示 2-3 树, 实现起来相对容易;
- 内部使用向左倾斜的链接表示第三个节点;
红黑树定义如下:
- 没有任意节点拥有两个红色链接;
- 从跟节点到末节点的黑色链接数目相等;
- 红色节点向左倾斜;
用红黑树来表示 2-3 树例子:
红黑树的节点定义
节点定义
在二叉查找树节点的基础上增加一个 Color 字段, 相关代码如下:
// Color Const, Red As true, Black as false
private const bool Red = true;
private const bool Black = false;
private class Node {
public TKey Key;
public TValue Val;
public Node Left, Right;
public bool Color; // Color
}
// Check node's color.
private static bool IsRed(Node h) {
if (h == null) {
return false;
}
return h.Color == Red;
}
红黑树的创建
红黑树的创建和二叉查找树类似, 为了在添加节点时维持节点的顺序和树的平衡性, 增加了如下一些操作:
左旋
将一个临时向右倾斜的红色链接向左旋转, 如下图所示:
对应的 c# 实现代码如下:
private Node RotateLeft(Node h) {
Debug.Assert(h != null && IsRed(h.Right));
Node x = h.Right;
h.Right = x.Left;
x.Left = h;
x.Color = x.Left.Color;
h.Color = Red;
x.N = h.N;
h.N = Size(h.Left) + Size(h.Right) + 1;
return x;
}
右旋
将左倾的红色链接向右旋转为临时的向右倾斜的红色链接, 如下图所示:
对应的 c# 实现代码如下:
private Node RotateRight(Node h) {
Debug.Assert(h != null && IsRed(h.Left));
Node x = h.Left;
h.Left = x.Right;
x.Right = h;
x.Color = x.Right.Color;
h.Color = Red;
x.N = h.N;
h.N = Size(h.Left) + Size(h.Right) + 1;
return x;
}
翻转颜色
将节点的左右链接(临时情况)由红色改为黑色, 如下图所示:
对应的 c# 实现代码如下:
private void FlipColors(Node h) {
Debug.Assert(h != null && h.Left != null && h.Right != null);
Debug.Assert((!IsRed(h) && IsRed(h.Left) && IsRed(h.Right))
|| (IsRed(h) && !IsRed(h.Left) && !IsRed(h.Right)));
h.Color = !h.Color;
h.Left.Color = !h.Left.Color;
h.Right.Color = !h.Right.Color;
}
添加节点
有了上面定义的几个操作, 添加节点分两种情况:
- 向单节点添加新节点, 在底部形成双节点, 如下图所示:
这种情况下比较容易处理, 需要的步骤如下:
- 按照二叉查找树的方式添加节点, 将新节点标记为红色;
- 如果新节点是其父节点的右链接, 则进行左旋操作;
- 向双节点添加新节点, 在底部形成三节点, 如下图所示:
这种情况稍微麻烦一些, 需要的步骤如下:
- 按照二叉查找树的方式添加节点, 将新节点标记为红色;
- 如果需要, 通过旋转形成临时的四节点;
- 翻转颜色, 将红色链接上移一层;
- 如果需要, 通过旋转形成左倾的红色节点;
- 如果需要, 以此方法向上递归;
最终红黑树添加节点的 c# 代码如下:
public void Put(TKey key, TValue val) {
root = Put(root, key, val);
root.Color = Black;
Debug.Assert(Check());
}
private Node Put(Node h, TKey key, TValue val) {
if (h == null) {
return new Node(key, val, Red, 1);
}
int cmp = key.CompareTo(h.Key);
if (cmp < 0) {
h.Left = Put(h.Left, key, val);
}
else if (cmp > 0) {
h.Right = Put(h.Right, key, val);
}
else {
h.Val = val;
}
if (IsRed(h.Right) && !IsRed(h.Left)) {
h = RotateLeft(h);
}
if (IsRed(h.Left) && IsRed(h.Left.Left)) {
h = RotateRight(h);
}
if (IsRed(h.Left) && IsRed(h.Right)) {
FlipColors(h);
}
h.N = Size(h.Left) + Size(h.Right) + 1;
return h;
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux常用命令面试题(1)
- 机器学习必刷题-手撕推导篇(1)
- Python面试必刷题系列(3)
- Spark Love TensorFlow
- 用GPU加速Keras模型——Colab免费GPU使用攻略
- __init__和__new__的对比及单例模式
- 数据结构高频面试题-树
- Python面试必刷题系列(5)
- 外卖小哥
- 用 Python可视化神器 Plotly 动态演示全球疫情变化趋势
- 2个范例带你读懂TensorFlow2低阶API构建模型方法
- 2个范例带你读懂中阶API建模方法
- 2个范例带你读懂高阶API建模方法
- Keras与经典卷积——50行代码实现minst图片分类
- 算法理论+实战之PCA降维