#pragma once

#include<assert.h>
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
using std::pair;
using std::make_pair;
using std::string; namespace test
{ //与库中的RBT差异
/**
*
* 库中还有结点数量 count
*
* 库中RBT是带头结点哨兵卫的,头结点的左是中序第一个(最小结点),右节点是中序的最后一个(最大结点),
* 哨兵卫的parent指向根节点,根节点的parent指向哨兵卫
*
* 库中的begin直接取head的left -- 函数:leftmost() //最左结点
* 库中的end 是head的right -- 不是rightmost,rightmost是最右结点,end是最右结点的下一个
* 库中的end 需要判断一下,防止只有左子树的歪脖子树时,end == head->right,死循环
*
* 和库的区别就是end,库的end能走回到head,我的不能,只能走到空就没了d
*
*/ enum Colour { RED, BLACK }; template<class T> //T是什么,为什么只传T? T为key或pair,T是key或者key-value类型
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
T _data; //data是key或pair
Colour _col; RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
//const_iterator<T,const T&,const T*>
//iterator<T, T&, T*> template<class T, class Ref, typename Ptr>
struct __RBTree_iterator
{
typedef RBTreeNode<T> node;
node* _node;
__RBTree_iterator(node* node)
:_node(node)
{} //因为set迭代器涉及到普通迭代器转换成const迭代器,所以需要写这个拷贝构造用于类型转换,
//原因1:如果是set把constK传给T.那么const迭代器的Ref就是const constT&,显然不能这么写
//原因2:const迭代器实例化后为<T,const T&, const T*> ,接收不了<T,T&,T*>的参数 -- 同一个类模板,只要模板参数不同就是不同类型了--多一个const也不行,类模板看<>一不一样
//综上得知,问题为类型转换问题,即需要单独给const迭代器写一个构造函数,参数为普通迭代器,即可解决类型转换问题
__RBTree_iterator(const __RBTree_iterator<T,T&,T*>& it)
:_node(it._node)
{}
//这个构造函数的作用,当迭代器模板被实例化成普通迭代器时,他就是构造函数
// 被实例化成const迭代器时,他是带参构造函数 --------->那么说,这个函数起到了一石二鸟的作用?
//const类型的作为返回值的迭代器接收(带参构造)隐式类型(拷贝构造)转换过来的临时变量? --应该也没这么复杂,直接建const临时变量拿来用可能 //Ref为 T& 或 const T&
//Ptr为 T* 或 const T*
typedef __RBTree_iterator<T, Ref, Ptr> Self; Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(_node->_data);
}
bool operator!=(const Self& x)
{
return _node != x._node;
}
Self& operator++()
{
//++逻辑
/**
* 如果右子树不为空,则下一个是右子树的最左节点
*
* 如果右子树完了,则父亲也完了.
*
* 如果我是父亲的左,完了则走父亲
*
* 直到没有父亲,结束
*
* 方法1:三叉链非递归
* 方法2:借助栈,非递归
*
*/
//if (!_node) //还不知为何不需要判空
//{
// return *this;
//} /**
* 特性:
* -- 除了右子树为空,每个结点的下一个是他的右子树走到空的那一个,
*
* 1.如果右子树不为空,,每个结点的下一个是他的右子树的最左结点,右子树往左走走到空的那一个,
* 2.如果右子树为空,则下一个是他所在的左子树的那个结点(祖先),cur往父亲的右倒着走,走到第一个出现的父亲的左,这个父亲就是下一个结点
* -- 沿着到根的路径往上走,找孩子是左子树的那个祖先
*/
if (_node->_right)
{
node* cur = _node->_right;
while (cur->_left)
{
cur = cur->_left;
}
_node = cur;
}
else
{
node* cur = _node;
node* parent = _node->_parent;
while (parent && parent->_right == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
} return *this;
}
Self& operator--()
{
//和++对称
if (_node->_left)
{
node* cur = _node->_left;
while (cur->_right)
{
cur = cur->_right;
}
_node = cur;
}
else
{
node* cur = _node;
node* parent = _node->_parent;
while (parent && parent->_left == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
}; //参数K用在find,erase等,虽然K也可以被T取代了,但没必要,K更快
template<class K, class T, class keyOfT> //库中还有1个compare,先不写了
class RBTree
{
public:
typedef RBTreeNode<T> node; //T是key或pair
public:
typedef __RBTree_iterator<T, T&, T*> iterator;
typedef __RBTree_iterator<T, const T&, const T*> const_iterator; iterator begin()
{
node* cur = _root;
while (cur && cur->_left)//不能走到空
{
cur = cur->_left;
}
return iterator(cur);//返回中序的第一个结点,最左结点
} iterator end() //end是最一个位置的下一个
{
return iterator(nullptr);//暂时可以这么写
} const_iterator begin()const
{
node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
} const_iterator end() const
{
return iterator(nullptr);
} private:
node* _root = nullptr;
public:
node* find(const K& key)
{
keyOfT kot;//kot是个仿函数,根据不同参数返回不同的参数对象
node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) // -------------------------------------------- 只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_left;
}
else if (kot(cur->_data) < key) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
} pair<iterator, bool> insert(const T& data)
{
if (!_root)
{
_root = new node(data);
_root->_col = BLACK;
return std::make_pair(iterator(_root), true);
} keyOfT kot; node* cur = _root;
node* parent = nullptr;
while (cur)
{
if (kot(cur->_data) < kot(data) ) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_right;
}
else if (kot(data) < kot(cur->_data)) // --------------------------------------------只需要重载一个 '<' 或 '>' 就可以比较大小
{
parent = cur;
cur = cur->_left;
}
else
{
return std::make_pair(iterator(cur), false);
}
}
cur = new node(data);
if ( kot(parent->_data) < kot(data)) // --------------------------------------------
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent; //调整/旋转
node* newnode = cur;//调整过程cur会发生变化,将cur结点记住 -- 记住原来key的位置
while (parent && parent->_col == RED)
{
node* g = parent->_parent;
if (parent == g->_right)
{
node* u = g->_left;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateR(parent);
RotateL(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
} }
else
{
node* u = g->_right;
if (u && u->_col == RED)
{
g->_col = RED;
parent->_col = BLACK;
u->_col = BLACK;
cur = g;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(g);
parent->_col = BLACK;
g->_col = RED;
}
else
{
RotateL(parent);
RotateR(g);
g->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return std::make_pair(iterator(newnode), true);
}
public:
void InOrderTraversal()
{
_InOrderTraversal(_root);
} bool isBalanceTree()
{
//需要判断3个规则
//1.根为黑
if (_root && _root->_col == RED)
{
cout << "错误:根是红色" << endl;
return false;
} //2.不能有连续得红
//3.黑同
int benchmark = 0;
node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
++benchmark;
}
cur = cur->_left;
}
return _check(_root, 0, benchmark);
} int Height()
{
return _Height(_root);
}
~RBTree()
{
Destroy(_root);
} private:
void Destroy(node*& root)
{
if (!root)
{
return;
}
Destroy(root->_left);
Destroy(root->_right);
delete root;
root = nullptr;
} bool _check(node* root, int blackNum, int benchmark)
{
keyOfT kot;
if (!root) //
{
if (blackNum != benchmark)
{
cout << "错误:存在不同路径的黑色结点数量不相同" << endl;
return false;
}
return true;
} if (root->_col == BLACK)
{
++blackNum;
} if (root->_col == RED && root->_parent->_col == RED)
{
cout << kot(root->_data) << " 错误,与父节点同时为红色"; // --------------------------------------------
return false;
} return _check(root->_left, blackNum, benchmark) && _check(root->_right, blackNum, benchmark);
} int _Height(node* root)
{
if (!root)
{
return 0;
}
int leftH = _Height(root->_left);
int rightH = _Height(root->_right); return leftH > rightH ? leftH + 1 : rightH + 1;
} void _InOrderTraversal(node* root)
{
keyOfT kot;
if (root == nullptr)
{
return;
}
_InOrderTraversal(root->_left);
cout << kot(root->_data) << " "; // --------------------------------------------
_InOrderTraversal(root->_right);
} void RotateL(node* parent)
{
node* subR = parent->_right;
node* subRL = subR->_left; parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
} node* pparent = parent->_parent; subR->_left = parent;
parent->_parent = subR; if (!pparent)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
subR->_parent = pparent;
}
} void RotateR(node* parent)
{
node* subL = parent->_left;
node* subLR = subL->_right; parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
} node* pparent = parent->_parent; subL->_right = parent;
parent->_parent = subL; if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
}; }

STL-RBTree模拟实现的更多相关文章

  1. <泛> STL - vector 模拟实现

    今天为大家带来一个模拟STL-vector的模板实现代码. 首先看一下测试结果,之后再为大家呈现设计 测试效果 测试代码 #include<iostream> #include<ve ...

  2. 洛谷 P1739 表达式括号匹配【STL/stack/模拟】

    题目描述 假设一个表达式有英文字母(小写).运算符(+,-,*,/)和左右小(圆)括号构成,以"@"作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返 ...

  3. <泛> STL - stack 模拟实现

    今天,看C++Template的时候看到那人写了一个Stack,于是乎,手痒,自己也写了一个,在拜读了STD文件和C++模板元编程某些小节之后,你们就看到了这篇代码. 经过上述一番经历之后,我重新写了 ...

  4. STL string 模拟

    下面的代码来自c++ primer plus第5版第12章,书中代码写的非常好: // string1.h -- fixed and augmented string class definition ...

  5. UVa 12219 Common Subexpression Elimination (stl,模拟,实现)

    一般来说,把一颗子树离散成一个int,把一个结点的字符离散成一个int会方便处理 直接map离散.当然一个结点最多只有4个小写字母,也可以直接编码成一个27进制的整数,舍掉0,为了区分0和0000. ...

  6. 【STL+模拟】UVa 506 - System Dependencies

    System Dependencies  Components of computer systems often have dependencies--other components that m ...

  7. 带你深入理解STL之RBTree

    最近一直忙于校招的笔试,STL的深入理解系列也耽搁了好几天,再加上!红黑树真的是超级超级难理解,超级超级复杂,参考了好多博客上的大神的理解才稍微明白一点,勉强入个门,下面请以一个菜鸟的角度跟着我一起学 ...

  8. STL——关联式容器

    一.关联式容器 标准的STL关联式容器分为set(集合)/map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和 multimap(多键映射表).这些容器的底层机制均以RB-tre ...

  9. hiho一下 第四十七周 拓扑排序一 【静态数组链式前向星存储结构实现 + 拓扑跳出 】

    题目1 : 拓扑排序·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来. 小Ho:小Hi,你这学期有选什么 ...

  10. 【数据结构】洛谷2019 OI春令营 - 普及组 作业

    [P3662][USACO17FEB]Why Did the Cow Cross the Road II S 求解连续的k个数的最大值,利用前缀和维护即可. #include<bits/stdc ...

随机推荐

  1. 配置elementuI菜单

    :unique-opened="true" 只保留一个菜单 :router="true"开启路由标识 index="users" 是标识 它 ...

  2. webpack配置scss

    安装依赖: cnpm i sass-loader -D cnpm i node-sass -D node-sass尽量去使用cnpm去安装 创建index2.scss文件 div { h2 { bac ...

  3. Go - 基本数据类型和其字符串表示之间转换

    1. 基本数据类型和其字符串表示之间转换 基本类型的值,都有一个字符串表示,如数字类型值1 字符串表示为 "1",字符的编码为Unicode或者UTF-8,数字的编码是 int,底 ...

  4. PaddleNLP基于ERNIR3.0文本分类以CAIL2018-SMALL数据集罪名预测任务为例【多标签】

    相关项目链接: Paddlenlp之UIE模型实战实体抽取任务[打车数据.快递单] Paddlenlp之UIE分类模型[以情感倾向分析新闻分类为例]含智能标注方案) 应用实践:分类模型大集成者[Pad ...

  5. WebAssembly核心编程[2]:类型系统

    对于绝大多数编程语言来说,类型都是编程的基础,WebAssembly自然也不例外.总的来说,WebAssembly涉及的类型不多,很好掌握,接下来我们就来介绍一下WebAssembly编程涉及到的几种 ...

  6. MAC使用XQuartz调用图形界面

    DBA经常遇到需要调用图形的操作,通常Windows用户习惯使用Xmanager这类软件,MAC用户习惯使用XQuartz,之前版本系统会自带,现在需要自行下载. 比如在 https://www.xq ...

  7. Jackson objectMapper.readValue 方法 详解

    直接说结论方便一目了然: 1. 简单的直接Bean.class 2. 复杂的用 TypeReference 这样就完事了. public class TestMain2 { public static ...

  8. DbgridEh 1900-01-01 00:00:00 问题解决

    --------------------------------------------------

  9. Trino-登录WebUI页面报错,日志中提示:404 Not Foud. (Zookeeper占用8080端口,与Trino的端口冲突)

    问题描述 启动Trino客户端执行show catalogs时报错:Error starting query at http://localhost:8080/v1/statement returne ...

  10. Hbase-执行hbase shell命令时提示:ERROR: KeeperErrorCode = NoNode for /hbase/master

    1.问题描述 执行hbase  shell命令时提示: ERROR: KeeperErrorCode = NoNode for /hbase/master 2.问题原因 这是与因为服务器重启后Hado ...