红黑树(依照4阶B树C++实现)
RBtree源码实现
/*
* BinarySearchTree.h
* 添加元素时需自己做判断元素是否合法
* Created on: 2020年1月29日
* Author: LuYonglei
*/ #ifndef SRC_BINARYSEARCHTREE_H_
#define SRC_BINARYSEARCHTREE_H_
#include <queue> const bool RED = false;
const bool BLACK = true; template<typename Element>
class BinarySearchTree {
public: BinarySearchTree(int (*cmp)(Element e1, Element e2)); //比较函数指针 virtual ~BinarySearchTree(); int size(); //元素的数量 bool isEmpty(); //是否为空 void clear() {
//清空所有元素
NODE *node = root_;
root_ = nullptr;
using namespace std;
queue<NODE*> q;
q.push(node);
while (!q.empty()) {
NODE *tmp = q.front();
if (tmp->left != nullptr)
q.push(tmp->left);
if (tmp->right != nullptr)
q.push(tmp->right);
delete tmp;
q.pop();
}
} void add(Element e) {
//添加元素
add(e, cmp_);
} void remove(Element e) {
//删除元素
remove(Node(e, cmp_));
} bool contains(Element e) {
//是否包含某元素
return Node(e, cmp_) != nullptr;
} void preorderTraversal(bool (*visitor)(Element e)) {
//前序遍历
if (visitor == nullptr)
return;
bool stop = false; //停止标志,若stop为true,则停止遍历
preorderTraversal(root_, stop, visitor);
} void inorderTraversal(bool (*visitor)(Element e)) {
//中序遍历
if (visitor == nullptr)
return;
bool stop = false; //停止标志,若stop为true,则停止遍历
inorderTraversal(root_, stop, visitor);
} void postorderTraversal(bool (*visitor)(Element e)) {
//后序遍历
if (visitor == nullptr)
return;
bool stop = false; //停止标志,若stop为true,则停止遍历
postorderTraversal(root_, stop, visitor);
} void levelOrderTraversal(bool (*visitor)(Element e)) {
//层序遍历,迭代实现
if (visitor == nullptr)
return;
levelOrderTraversal(root_, visitor);
} int height() {
//树的高度
return height(root_);
} bool isComplete() {
//判断是否是完全二叉树
return isComplete(root_);
} private: int size_; typedef struct _Node {
Element e;
_Node *parent;
_Node *left;
_Node *right;
bool color_;
_Node(Element e_, _Node *parent_) :
e(e_), parent(parent_), left(nullptr), right(nullptr), color_(
RED) {
//节点构造函数
} inline bool isLeaf() {
return (left == nullptr && right == nullptr);
} inline bool hasTwoChildren() {
return (left != nullptr && right != nullptr);
} inline bool isLeftChild() {
//判断节点是否是父亲节点的左子结点
return parent != nullptr && parent->left == this;
} inline bool isRightChild() {
//判断节点是否是父亲节点的右子结点
return parent != nullptr && parent->right == this;
} inline _Node* sibling() {
//返回兄弟节点
if (this->parent != nullptr) {
if (this->isLeftChild())
return this->parent->right;
else
return this->parent->left;
}
return nullptr;
} } NODE; NODE *root_; int (*cmp_)(Element e1, Element e2); //为实现树的排序的个性化配置,私有成员保存一个比较函数指针 NODE* Node(Element e, int (*cmp_)(Element e1, Element e2)) {
//返回e元素所在的节点
NODE *node = root_;
while (node != nullptr) {
int cmp = cmp_(e, node->e);
if (cmp == ) //找到了元素
return node;
if (cmp > ) { //待寻找元素大于节点存储的元素
node = node->right;
} else { //待寻找元素小于节点存储的元素
node = node->left;
}
}
return nullptr;
} NODE* predecessor(NODE *node) {
//返回node的前驱节点
if (node == nullptr)
return nullptr;
//前驱节点在左子树
NODE *tmp = node->left;
if (tmp != nullptr) {
while (tmp->right != nullptr)
tmp = tmp->right;
return tmp;
}
//从父节点,祖父节点中寻找前驱节点
while (node->parent != nullptr && node == node->parent->left) {
node = node->parent;
}
return node->parent;
} NODE* successor(NODE *node) {
//返回node的后继节点
if (node == nullptr)
return nullptr;
//后继节点在右子树
NODE *tmp = node->right;
if (tmp != nullptr) {
while (tmp->left != nullptr)
tmp = tmp->left;
return tmp;
}
//从父节点,祖父节点中寻找后继节点
while (node->parent != nullptr && node == node->parent->right) {
node = node->parent;
}
return node->parent;
} bool colorOf(NODE *node) {
//返回节点的颜色
return node == nullptr ? BLACK : node->color_;
} bool isBlack(NODE *node) {
//node是否为黑色
return node == nullptr ? true : node->color_ == BLACK;
} bool isRed(NODE *node) {
//node是否为红色
return node == nullptr ? false : node->color_ == RED;
} NODE* color(NODE *node, bool color) {
//对节点染色
if (node == nullptr)
return node;
node->color_ = color;
return node;
} NODE* red(NODE *node) {
//把节点染成红色
return color(node, RED);
} NODE* black(NODE *node) {
//把节点染成黑色
return color(node, BLACK);
} void afterRotate(NODE *gNode, NODE *pNode, NODE *child) {
//在左旋转与右旋转中统一调用
pNode->parent = gNode->parent;
if (gNode->isLeftChild())
gNode->parent->left = pNode;
else if (gNode->isRightChild())
gNode->parent->right = pNode;
else
//此时gNode->parent 为nullptr,gNode为root节点
root_ = pNode;
if (child != nullptr)
child->parent = gNode;
gNode->parent = pNode; } void rotateLeft(NODE *gNode) {
//对gNode进行左旋转
NODE *pNode = gNode->right;
NODE *child = pNode->left;
gNode->right = child;
pNode->left = gNode;
afterRotate(gNode, pNode, child); } void rotateRight(NODE *gNode) {
//对gNode进行右旋转
NODE *pNode = gNode->left;
NODE *child = pNode->right;
gNode->left = child;
pNode->right = gNode;
afterRotate(gNode, pNode, child); } void afterAdd(NODE *node) {
//添加node之后的操作
NODE *parentNode = node->parent;
//没有父节点时,新添加的节点是root_或者上溢到root_
if (parentNode == nullptr) {
black(node);
return;
}
//1.当父亲节点为黑色节点时,不做任何处理,直接返回
if (isBlack(parentNode))
return;
NODE *uncleNode = parentNode->sibling();
NODE *grandNode = red(parentNode->parent);
if (isRed(uncleNode)) {
//2.uncle节点是红色,(上溢,只需要染色)
black(parentNode);
black(uncleNode);
//祖父节点当作是新添加的节点
afterAdd(grandNode);
return;
}
//3.uncle节点是黑色或者uncle节点为null
if (parentNode->isLeftChild()) {
if (node->isLeftChild()) {
//LL
black(parentNode);
} else {
//LR
black(node);
rotateLeft(parentNode);
}
rotateRight(grandNode);
} else {
if (node->isLeftChild()) {
//RL
black(node);
rotateRight(parentNode);
} else {
//RR
black(parentNode);
}
rotateLeft(grandNode);
}
} void add(Element e, int (*cmp_)(Element e1, Element e2)) {
//当树为空时,添加的节点作为树的根节点
if (root_ == nullptr) {
root_ = new NODE(e, nullptr);
size_++;
afterAdd(root_);
return;
}
//当添加的节点不是第一个节点
NODE *parent = root_;
NODE *node = root_;
int cmp = ; //比较结果
while (node != nullptr) {
parent = node; //保存父节点
cmp = cmp_(e, node->e); //由函数指针来比较
if (cmp > ) {
node = node->right; //添加的元素大于节点中的元素
} else if (cmp < ) {
node = node->left; //添加的元素小于节点中的元素
} else {
node->e = e; //相等时就覆盖
return; //添加的元素等于节点中的元素,直接返回
}
}
//判断要插入父节点的哪个位置
NODE *newNode = new NODE(e, parent); //为新元素创建节点
if (cmp > ) {
parent->right = newNode; //添加的元素大于节点中的元素
} else {
parent->left = newNode; //添加的元素小于节点中的元素
}
size_++;
afterAdd(newNode);
} void afterRemove(NODE *node) {
//删除节点之后的操作
//node是要被释放内存的节点或是是替代的节点
//1.如果删除的是红色节点,直接删掉即可
//此处代表删除的节点为红色叶子节点
if (isRed(node)) {
//2.如果删除的节点是黑色节点,且替代的节点为红色节点
//此处代表删除的节点的度为1,且要删除的节点含有一个红色子节点
black(node);
return;
}
//3.如果删除的节点是黑色节点,且替代的节点为黑色节点(nullptr)
//此处代表要删除的是黑色叶子节点或根节点
NODE *parentNode = node->parent;
//如果删除的是根节点
if (parentNode == nullptr)
return; //此时node为叶子节点
//但想获得他的兄弟节点不能调用sibling(),因为在调用afterRemove()之前,若node为parent的left就已经将parent的left置为nullptr
//若node为parent的right就已经将parent的right置为nullptr,此时再调用sibling()就会得不到准确的信息
bool left = parentNode->left == nullptr || node->isLeftChild();
NODE *siblingNode = left ? parentNode->right : parentNode->left;
if (left) {
//被删除的节点在左边,兄弟节点在右边
if (isRed(siblingNode)) {
//兄弟节点是红色,要转化成兄弟节点是黑色
black(siblingNode);
red(parentNode);
rotateLeft(parentNode);
//更换兄弟
siblingNode = parentNode->right;
}
//以下代码处理兄弟节点是黑色(兄弟节点必然为黑色)
if (isBlack(siblingNode->left) && isBlack(siblingNode->right)) {
//兄弟节点没有红色子节点,父节点要向下和兄弟节点合并
bool parentIsBlack = isBlack(parentNode);
black(parentNode);
red(siblingNode);
if (parentIsBlack) {
//如果父亲节点是黑色,会产生下溢
afterRemove(parentNode);
}
} else {
//兄弟节点至少有一个红色子节点,向兄弟节点借元素
//兄弟节点的右边是黑色的,兄弟要先旋转
if (isBlack(siblingNode->right)) {
rotateRight(siblingNode);
siblingNode = parentNode->right;
}
color(siblingNode, colorOf(parentNode));
black(parentNode);
black(siblingNode->right);
rotateLeft(parentNode);
}
} else {
//被删除的节点在右边,兄弟节点在左边
if (isRed(siblingNode)) {
//兄弟节点是红色,要转化成兄弟节点是黑色
black(siblingNode);
red(parentNode);
rotateRight(parentNode);
//更换兄弟
siblingNode = parentNode->left;
}
//以下代码处理兄弟节点是黑色(兄弟节点必然为黑色)
if (isBlack(siblingNode->left) && isBlack(siblingNode->right)) {
//兄弟节点没有红色子节点,父节点要向下和兄弟节点合并
bool parentIsBlack = isBlack(parentNode);
black(parentNode);
red(siblingNode);
if (parentIsBlack) {
//如果父亲节点是黑色,会产生下溢
afterRemove(parentNode);
}
} else {
//兄弟节点至少有一个红色子节点,向兄弟节点借元素
//兄弟节点的左边是黑色的,兄弟要先旋转
if (isBlack(siblingNode->left)) {
rotateLeft(siblingNode);
siblingNode = parentNode->left;
}
color(siblingNode, colorOf(parentNode));
black(parentNode);
black(siblingNode->left);
rotateRight(parentNode);
}
} } void remove(NODE *node_) {
//删除某一节点
if (node_ == nullptr)
return;
size_--;
//优先删除度为2的节点
if (node_->hasTwoChildren()) {
NODE *pre = successor(node_); //找到node_的后继节点
node_->e = pre->e; //用后继节点的值覆盖度为2的节点的值
//删除后继节点(后继节点的度只能为1或0)
node_ = pre;
}
//此时node_的度必然为0或1
NODE *replacement = node_->left != nullptr ? node_->left : node_->right;
if (replacement != nullptr) { //node_的度为1
replacement->parent = node_->parent;
if (node_->parent == nullptr) //度为1的根节点
root_ = replacement;
else if (node_->parent->left == node_)
node_->parent->left = replacement;
else
node_->parent->right = replacement;
afterRemove(replacement);
delete node_;
} else if (node_->parent == nullptr) { //node_是叶子节点,也是根节点
root_ = nullptr;
delete node_;
} else { //node_是叶子节点,但不是根节点
if (node_->parent->left == node_)
node_->parent->left = nullptr;
else
node_->parent->right = nullptr;
afterRemove(node_);
delete node_;
}
} void preorderTraversal(NODE *node, bool &stop, bool (*visitor)(Element e)) {
//递归实现前序遍历
if (node == nullptr || stop == true)
return;
stop = visitor(node->e);
preorderTraversal(node->left, stop, visitor);
preorderTraversal(node->right, stop, visitor);
} void inorderTraversal(NODE *node, bool &stop, bool (*visitor)(Element e)) {
//递归实现中序遍历
if (node == nullptr || stop == true)
return;
inorderTraversal(node->left, stop, visitor);
if (stop == true)
return;
stop = visitor(node->e);
inorderTraversal(node->right, stop, visitor);
} void postorderTraversal(NODE *node, bool &stop,
bool (*visitor)(Element e)) {
//递归实现后序遍历
if (node == nullptr || stop == true)
return;
postorderTraversal(node->left, stop, visitor);
postorderTraversal(node->right, stop, visitor);
if (stop == true)
return;
stop = visitor(node->e);
} void levelOrderTraversal(NODE *node, bool (*visitor)(Element e)) {
if (node == nullptr)
return;
using namespace std;
queue<NODE*> q;
q.push(node);
while (!q.empty()) {
NODE *node = q.front();
if (visitor(node->e) == true)
return;
if (node->left != nullptr)
q.push(node->left);
if (node->right != nullptr)
q.push(node->right);
q.pop();
}
} int height(NODE *node) {
//某一节点的高度
if (node == nullptr)
return ;
using namespace std;
queue<NODE*> q;
q.push(node);
int height = ;
int levelSize = ; //每一层起始的节点个数
while (!q.empty()) {
NODE *node = q.front();
levelSize--;
if (node->left != nullptr)
q.push(node->left);
if (node->right != nullptr)
q.push(node->right);
q.pop();
if (levelSize == ) {
height++;
levelSize = q.size();
}
}
return height;
} bool isComplete(NODE *node) {
if (node == nullptr)
return false;
using namespace std;
queue<NODE*> q;
q.push(node);
bool leaf = false; //判断接下来的节点是否为叶子节点
while (!q.empty()) {
NODE *node = q.front();
if (leaf && !node->isLeaf()) //判断叶子节点
return false;
if (node->left != nullptr) {
q.push(node->left);
} else if (node->right != nullptr) { //node->left == nullptr && node->right != nullptr
return false;
}
if (node->right != nullptr) {
q.push(node->right);
} else { //node->right==nullptr
leaf = true;
}
q.pop();
}
return true;
} }; template<typename Element>
BinarySearchTree<Element>::BinarySearchTree(int (*cmp)(Element e1, Element e2)) :
size_(), root_(nullptr), cmp_(cmp) {
//树的构造函数
} template<typename Element>
BinarySearchTree<Element>::~BinarySearchTree() {
// 析构函数
clear();
} template<typename Element>
inline int BinarySearchTree<Element>::size() {
//返回元素个数
return size_;
} template<typename Element>
inline bool BinarySearchTree<Element>::isEmpty() {
//判断是否为空树
return size_ == ;
} #endif /* SRC_BINARYSEARCHTREE_H_ */
main测试例程
/*
* main.cpp
*
* Created on: 2020年1月29日
* Author: LuYonglei
*/ #include "BinarySearchTree.h"
#include <iostream> using namespace std; template<typename Element>
int compare(Element e1, Element e2) {
//比较函数,相同返回0,e1<e2返回-1,e1>e2返回1
return e1 == e2 ? : (e1 < e2 ? - : );
} template<typename Elemnet>
bool visitor(Elemnet e) {
cout << e << " ";
return false; //若返回true,则在遍历时会退出
} int main(int argc, char **argv) {
BinarySearchTree<double> a(compare);
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.add();
a.remove();
a.remove();
a.remove();
// a.inorderTraversal(visitor);
// cout << endl;
// cout << a.isComplete() << endl;
// a.remove(55);
// a.clear();
a.levelOrderTraversal(visitor);
cout << endl;
// cout<<a.contains(0)<<endl;
}
红黑树(依照4阶B树C++实现)的更多相关文章
- 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树...
上篇文章我们主要介绍了线性数据结构,本篇233酱带大家康康 无所不在的非线性数据结构之一:树形结构的特点和应用. 树形结构,是指:数据元素之间的关系像一颗树的数据结构.我们看图说话: 它具有以下特点: ...
- 数据结构中很常见的各种树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
数据结构中常见的树(BST二叉搜索树.AVL平衡二叉树.RBT红黑树.B-树.B+树.B*树) 二叉排序树.平衡树.红黑树 红黑树----第四篇:一步一图一代码,一定要让你真正彻底明白红黑树 --- ...
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树 ...
- 【转】B树、B-树、B+树、B*树、红黑树、 二叉排序树、trie树Double Array 字典查找树简介
B 树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: ...
- 红黑树(Red-Black Tree),B树,B-树,B+树,B*树
(一)红黑树(Red-Black Tree) http://www.cnblogs.com/skywang12345/p/3245399.html#a1 它一种特殊的二叉查找树.红黑树的每个节点上都有 ...
- 二叉树,平衡树,红黑树,B~/B+树汇总
二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree).这四种树都具备下面几个优势: (1) 都是动态结构.在删除,插入操作的时候,都不需要彻底重建原始的索引树 ...
- AVL树、红黑树以及B树介绍
简介 首先,说一下在数据结构中为什么要引入树这种结构,在我们上篇文章中介绍的数组与链表中,可以发现,数组适合查询这种静态操作(O(1)),不合适删除与插入这种动态操作(O(n)),而链表则是适合删除与 ...
- 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树
某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...
- 二叉树,红黑树,B+树
在实际使用时会根据链表和有序数组等数据结构的不同优势进行选择.有序数组的优势在于二分查找,链表的优势在于数据项的插入和数据项的删除.但是在有序数组中插入数据就会很慢,同样在链表中查找数据项效率就很低. ...
随机推荐
- mysql5.7密码修改与报错分析
1.修改密码 修改密码: vim /etc/my.cnf 的mysqld字段加入skip-grant-tables 重启MySQL,service mysqld restart 终端输入 mysql ...
- 第二阶段:2.商业需求文档MRD:3.MRD-目标用户分析
以上是对目标市场的分析! 用户描述是定性.市场统计是定量.用用户分类模型去剖析用户分类. 例子.做百度推广时候的用户分析.不同角色的关注点不同.三个情景:广告售卖,广告投放,分析评估. 用户的使用习惯 ...
- c# T4模板生成实体类(sqlserver)
1.用vs新建tt文件. 2.tt文件保存就自动运行 3.tt文件代码如下,设置生成cs文件的命名空间和生成地址 <#@ template language="C#" hos ...
- rest_framework框架下的Django声明和生命周期
rest_framework框架下的Django声明和生命周期 Django声明周期(request) 客户端发起请求 请求经过wsgi wsgi: 是一个协议----web服务网关接口,即在web服 ...
- Mysql 最全查询语句
基本查询语句及语法: select distinct from where group by having limit 一.单表查询 前期表与数据准备: # 创建一张部门表 create table ...
- 洛谷$P4211\ [LNOI2014]\ LCA$ 树链剖分+线段树
正解:树剖+线段树 解题报告: 传送门$QwQ$ 看到$dep[lca]$啥的就想到之前托腮腮$CSP$模拟$D1T3$的那个套路,,, 然后试下这个想法,于是$dep[lca(x,y)]=\sum_ ...
- $CH5501$ 环路运输 环形$+$单调队列
CH Description 在一条环形公路旁均匀地分布着N座仓库,编号为1~N,编号为 i 的仓库与编号为 j 的仓库之间的距离定义为 dist(i,j)=min(|i-j|,N-|i-j|),也 ...
- 「CH2601」 电路维修 解题报告
CH2601 电路维修 描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障 ...
- 1055 集体照 (25 分)C语言
拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下: 每排人数为 N/K(向下取整),多出来的人全部站在最后一排: 后排所有人的个子都不比前排任何人矮: 每排中最高者站中间(中 ...
- 小小知识点(十四)——Adobe photoshop cc 2018中简单抠图的一些基本操作
一 如何抠图 1. 右键弹出选择工具,随后鼠标左键选择快速选择工具 2.通过点击鼠标,选择想要的区域: Alt+鼠标右键 左右拖动鼠标可调整画笔大小 Alt+鼠标滑轮,可放大或缩小画布大小 ctrl ...