【C++】使用红黑树封装map与set

戴墨镜的恐龙 2024-08-27 09:33:02 阅读 92

文章目录

1. 源码分析2. 调整红黑树的结构搭建map、set3. 红黑树的迭代器3.1 普通迭代器3.2 const迭代器3.3 map的operator[ ]

4. 完整代码4.1 RBTree4.2 MyMap4.3 MySet

在这里插入图片描述

对于map与set,它们一个是KV模型,一个是K模型,那我们要写两个红黑树吗?

我们来看一下源码

1. 源码分析

在这里插入图片描述

我很疑惑为什么它们两个都传了两个参数给底层的红黑树,那再看一下红黑树的源码

在这里插入图片描述

我们可以发现,红黑树在底层不知道你传给它的是什么,为了兼容map与set它搞了两个参数。

但是搞了两个参数后,第一个模板参数Key是不是有点多余呢?

对于set而言,两个K确实是有点多余;对于map来说,pair里面也有K,好像也有点多余如果只留第二个模板参数,_rb_tree_node< Value >,为set时 Value为K;为 map时 Value为pair<K,V>,好像也没问题。对于插入操作,set是k,map是pair还挺好;但是对于查找操作时,set使用Value没问题;map查找时也要使用Value,但map的Value是一个pair(有K,V),那我既然知道了K和V,我还查找什么呢?所以第一个模板参数不多于,反而是必须

但还有一个问题,在插入操作时,涉及数据比较大小。但是map的Value是一个pair,还得取里面的key;set的Value就是key,此时就比较麻烦。pair默认的比较规则是first比完second比,不符合我们的预期。因此我们还要给红黑树传递一个仿函数,以便获取key。

2. 调整红黑树的结构搭建map、set

那我们之前实现的红黑树的结构就得做一下调整了

在这里插入图片描述

除了上面呈现出来的模板参数以外,还可以传递自定义的比较规则模板Compare。

下面是map与set的基本框架

原来红黑树中涉及数据比较大小的地方,都得回调传递过来的KeyOfT获取Key后再比较

在这里插入图片描述

3. 红黑树的迭代器

3.1 普通迭代器

红黑树的迭代器无非也就是包含一个节点的指针,然后重载指针的各种操作即可。

在这里插入图片描述

一般迭代器的实现都是按照中序遍历,遍历完是有序的。所以红黑树迭代器的begin(),应该是树最左侧的节点;对于迭代器的end(),我们就按照NULL来处理。

在这里插入图片描述

那红黑树迭代器的++与- -操作是如何实现的呢?

对于++操作:

在这里插入图片描述

对于- -操作:为了方便_node == nullptr时找树最右侧的节点,我们再给迭代器加一个指针root记录树的根。

在这里插入图片描述

在这里插入图片描述

<code>template<class Value>

class RBTreeIterator

{ -- -->

typedef TreeNode<Value> Node;

typedef RBTreeIterator<Value> Self;

private:

Node* _node;

Node* _root;

public:

RBTreeIterator(Node* data,Node* root)

:_node(data)

,_root(root)

{ }

Self& operator++()

{

//右树存在,找右树的最左侧节点

if (_node->_right)

{

Node* leftMost = _node->_right;

while (leftMost && leftMost->_left)

{

leftMost = leftMost->_left;

}

_node = leftMost;//直接跳转至

}

else //右树不存在,继续向上

{

Node* cur = _node;

Node* parent = cur->_parent;

while (parent && parent->_right == cur)

{

cur = parent;

parent = cur->_parent;

}

//parent不存在或者该遍历根了

_node = parent;

}

return *this;

}

Self& operator--()

{

//特殊处理end(),找整棵树的最右侧节点

if (_node == nullptr)

{

Node* rightMost = _root;

while (rightMost && rightMost->_right)

{

rightMost = rightMost->_right;

}

_node = rightMost;

}

//左子树存在,找左子树最右侧节点

else if (_node->_left)

{

Node* rightMost = _node->_left;

while (rightMost && rightMost->_right)

{

rightMost = rightMost->_right;

}

_node = rightMost;

}

else

{

//左子树不存在,当前树遍历完,继续向上

Node* cur = _node;

Node* parent = cur->_parent;

while (parent && parent->_left == cur)

{

cur = parent;

parent = cur->_parent;

}

//parent不存在或者该遍历根了

_node = parent;

}

return *this;

}

Value& operator*(){

return _node->_data;

}

Value* operator->(){

return &_node->_data;

}

bool operator==(const Self& it)

{

return _node == it._node;

}

bool operator!=(const Self& it)

{

return _node != it._node;

}

};

3.2 const迭代器

对于const迭代器而言,无非就是数据不能被修改,那也就是针对迭代器的operator* 与operator->了。

那就先改造底层的迭代器

在这里插入图片描述

然后map与set在上层封一下就行了

在这里插入图片描述

通过上面的我们可以看到,使用const迭代器以后确实都不能修改了;但是普通迭代器存在一个问题:

在这里插入图片描述

所以上层在传递给下层时,我们可以将k设置为const

在这里插入图片描述

到这里我们的迭代器就完美了。

3.3 map的operator[ ]

我们都知道map重载的[ ]既可以充当插入,也可以充当修改。那么在底层它用的就是insert。(点击可看map的使用)

那我们就需要改变一下insert的返回值了。

在这里插入图片描述

在这里插入图片描述

到这里我们map与set的封装就结束了。

4. 完整代码

4.1 RBTree

<code>#pragma once

namespace my

{ -- -->

//颜色

enum Color

{

RED = 0,

BLACK

};

template<class Value>

struct TreeNode

{

Value _data;

TreeNode<Value>* _left;

TreeNode<Value>* _right;

TreeNode<Value>* _parent;//前驱节点

Color _col;

TreeNode(const Value& data)

: _data(data)

, _left(nullptr)

, _right(nullptr)

, _parent(nullptr)

, _col(RED)//默认新节点为红色的

{ }

};

template<class Value,class Ref,class Ptr>

class RBTreeIterator

{

typedef TreeNode<Value> Node;

typedef RBTreeIterator<Value,Ref,Ptr> Self;

private:

Node* _node;

Node* _root;

public:

RBTreeIterator(Node* data,Node* root)

:_node(data)

,_root(root)

{ }

Self& operator++()

{

//右树存在,找右树的最左侧节点

if (_node->_right)

{

Node* leftMost = _node->_right;

while (leftMost && leftMost->_left)

{

leftMost = leftMost->_left;

}

_node = leftMost;//直接跳转至

}

else //右树不存在,继续向上

{

Node* cur = _node;

Node* parent = cur->_parent;

while (parent && parent->_right == cur)

{

cur = parent;

parent = cur->_parent;

}

//parent不存在或者该遍历根了

_node = parent;

}

return *this;

}

Self& operator--()

{

//特殊处理end(),找整棵树的最右侧节点

if (_node == nullptr)

{

Node* rightMost = _root;

while (rightMost && rightMost->_right)

{

rightMost = rightMost->_right;

}

_node = rightMost;

}

//左子树存在,找左子树最右侧节点

else if (_node->_left)

{

Node* rightMost = _node->_left;

while (rightMost && rightMost->_right)

{

rightMost = rightMost->_right;

}

_node = rightMost;

}

else

{

//左子树不存在,当前树遍历完,继续向上

Node* cur = _node;

Node* parent = cur->_parent;

while (parent && parent->_left == cur)

{

cur = parent;

parent = cur->_parent;

}

//parent不存在或者该遍历根了

_node = parent;

}

return *this;

}

Ref operator*(){

return _node->_data;

}

Ptr operator->(){

return &_node->_data;

}

bool operator==(const Self& it)

{

return _node == it._node;

}

bool operator!=(const Self& it)

{

return _node != it._node;

}

};

template<class K,class Value,class KeyOfT>

class RBTree

{

typedef TreeNode<Value> Node;

public:

typedef RBTreeIterator<Value,Value&,Value*> Iterator;

typedef RBTreeIterator<Value,const Value&,const Value*> ConstIterator;

Iterator Begin()

{

Node* leftMost = _root;

//找最左侧的节点

while (leftMost && leftMost->_left)

{

leftMost = leftMost->_left;

}

return Iterator(leftMost,_root);

}

Iterator End()

{

return Iterator(nullptr,_root);

}

ConstIterator Begin() const

{

Node* leftMost = _root;

//找最左侧的节点

while (leftMost && leftMost->_left)

{

leftMost = leftMost->_left;

}

return ConstIterator(leftMost,_root);

}

ConstIterator End() const

{

return ConstIterator(nullptr,_root);

}

RBTree() = default;

RBTree(const RBTree<K, Value,KeyOfT>& tree)

{

this->_root = Copy(tree._root);

}

//类里面直接写类名,无需传递模板参数也可。

RBTree& operator=(RBTree tree)

{

swap(this->_root, tree._root);//现代写法

return *this;

}

~RBTree()

{

Destroy(_root);

}

pair<Iterator,bool> insert(const Value& data)

{

if (_root == nullptr)

{

_root = new Node(data);

//如果插入的节点是头节点,需要遵守规则2(根是黑的)

//需要默认的红色改为黑

_root->_col = BLACK;

return make_pair(Iterator(_root,_root),true);

}

KeyOfT kot;

Node* cur = _root;

Node* parent = cur->_parent;

while (cur)

{

if (kot(cur->_data) < kot(data))

{

parent = cur;

cur = cur->_right;

}

else if (kot(cur->_data) > kot(data))

{

parent = cur;

cur = cur->_left;

}

else

return make_pair(Iterator(cur, _root), false);

}

//孩子连父亲

cur = new Node(data);

Node* newnode = cur;

cur->_parent = parent;

//父亲连孩子

if (kot(parent->_data) < kot(data))

parent->_right = cur;

else

parent->_left = cur;

//检查是否违反红黑树的规则

//如果父亲存在且为红,则违反规则

while (parent && parent->_col == RED)

{

Node* grandfather = parent->_parent;

if (grandfather->_left == parent)

{

//根据爷爷节点找叔叔

Node* uncle = grandfather->_right;

//如果叔叔存在且为红,仅需要变色

if (uncle && uncle->_col == RED)

{

parent->_col = BLACK;

uncle->_col = BLACK;

grandfather->_col = RED;

//然后继续向上调整

cur = grandfather;

parent = cur->_parent;

}

//如果叔叔不存在 或者存在且为黑,需要旋转+变色

else

{

//判断单旋(直树)还是双旋(弯树)

//单旋

if (parent->_left == cur)

{

// g

// p u

//c

RotateR(grandfather);

parent->_col = BLACK;

grandfather->_col = RED;

}

//双旋

else

{

// g

// p u

// c

RotateL(parent);

RotateR(grandfather);

cur->_col = BLACK;

grandfather->_col = RED;

}

break;//旋转后已经符合规则,无需再调整了

}

}

//grandfather->_right == parent

else

{

Node* uncle = grandfather->_left;

//如果叔叔存在且为红,仅需要变色

if (uncle && uncle->_col == RED)

{

parent->_col = BLACK;

uncle->_col = BLACK;

grandfather->_col = RED;

//继续调整

cur = grandfather;

parent = cur->_parent;

}

//如果叔叔不存在 或者存在且为黑,需要旋转+变色

else

{

// g

// u p

// c

if (parent->_right == cur)

{

RotateL(grandfather);

parent->_col = BLACK;

grandfather->_col = RED;

}

// g

// u p

// c

else

{

RotateR(parent);

RotateL(grandfather);

cur->_col = BLACK;

grandfather->_col = RED;

}

break;

}

}

}

//父亲不存在,或者父亲为黑时,无需判断,直接将根变黑

_root->_col = BLACK;

return make_pair(Iterator(newnode, _root), true);

}

Iterator* find(const K& key)

{

Node* cur = _root;

KeyOfT kot;

while (cur)

{

if ( kot(cur->_data)< key)

cur = cur->_right;

else if (kot(cur->_data) > key)

cur = cur->_left;

else

return Iterator(cur,_root);

}

return End();

}

void InOrder()

{

_InOrder(_root);

cout << endl;

}

bool IsRBTree()

{

Node* root = _root;

if (root == nullptr)//空树也是

return true;

if (root->_col == RED)

{

cout << "根节点为红色,违反规则" << endl;

return false;

}

//先统计最左侧路径上有多少黑节点作为标准

Node* cur = root;

int blackNum = 0;

while (cur)

{

if (cur->_col == BLACK)

blackNum++;

cur = cur->_left;

}

//k用来记录路径中黑节点的个数

int k = 0;

//在依据标准黑节点的个数,比较其它路径

return _IsRBTree(root, blackNum, k);

}

int Size()

{

return _Size(_root);

}

int Height()

{

return _Height(_root);

}

private:

int _Height(Node* root)

{

if (root == nullptr)

return 0;

int leftH = _Height(root->_left);

int rightH = _Height(root->_right);

return leftH > rightH ? leftH + 1 : rightH + 1;

}

int _Size(Node* root)

{

if (root == nullptr)

return 0;

return 1 + _Size(root->_left) + _Size(root->_right);

}

bool _IsRBTree(Node* root, int blackNum, int k)

{

//一条路径走完,比较黑节点的个数

if (root == nullptr)

{

if (blackNum != k)

{

cout << "路径黑节点个数不相等,违反规则" << endl;

return false;

}

return true;

}

Node* parent = root->_parent;

if (parent && root->_col == RED && parent->_col == RED)

{

cout << "存在连续的红节点,违反规则" << endl;

return false;

}

//统计黑节点

if (root->_col == BLACK)

k++;

//统计完根,在依次统计左右子树

return _IsRBTree(root->_left, blackNum, k)

&& _IsRBTree(root->_right, blackNum, k);

}

void RotateR(Node* parent)

{

Node* SubL = parent->_left;

Node* SubLR = SubL->_right;

//降级连兵

parent->_left = SubLR;

if (SubLR)

SubLR->_parent = parent;

Node* parentParent = parent->_parent;

//升级连将

SubL->_right = parent;

parent->_parent = SubL;

//将连将

SubL->_parent = parentParent;

if (parentParent == nullptr)

{

_root = SubL;

}

else

{

if (parentParent->_left == parent)

parentParent->_left = SubL;

else

parentParent->_right = SubL;

}

}

void RotateL(Node* parent)

{

Node* SubR = parent->_right;

Node* SubRL = SubR->_left;

//降级连兵

parent->_right = SubRL;

if (SubRL)

SubRL->_parent = parent;

Node* parentParent = parent->_parent;

//升级连将

SubR->_left = parent;

parent->_parent = SubR;

//将连将

SubR->_parent = parentParent;

if (parentParent == nullptr)

_root = SubR;

else

{

if (parentParent->_left == parent)

parentParent->_left = SubR;

else

parentParent->_right = SubR;

}

}

void Destroy(Node* root)

{

if (root == nullptr)

return;

Destroy(root->_left);

Destroy(root->_right);

delete root;

}

Node* Copy(Node* root)

{

if (root == nullptr)

return nullptr;

_root->_left = Copy(root->_left);

_root->_right = Copy(root->_right);

return _root;

}

void _InOrder(Node* root)

{

if (root == nullptr)

return;

_InOrder(root->_left);

cout << root->_kv.first << " ";

_InOrder(root->_right);

}

Node* _root;

};

}

4.2 MyMap

#pragma once

#include"RBTree.h"

namespace my

{

template<class K, class V>

class map

{

struct MapKeyOfT

{

const K& operator()(const pair<K, V>& kv)

{

return kv.first;

}

};

public:

typedef typename RBTree<K, pair<const K, V>,MapKeyOfT>::Iterator iterator;

typedef typename RBTree<K, pair<const K, V>,MapKeyOfT>::ConstIterator const_iterator;

const_iterator begin()const

{

return _t.Begin();

}

const_iterator end() const

{

return _t.End();

}

iterator begin()

{

return _t.Begin();

}

iterator end()

{

return _t.End();

}

pair<iterator, bool> insert(const pair<K, V> kv)

{

return _t.insert(kv);

}

bool find(const K& key)

{

return _t.find(key);

}

V& operator[](const K& key)

{

pair<iterator, bool> ret = insert(make_pair(key,V()));

//如果key存在,则返回其对应的value

//如果key不存在,则插入它,其value为类型的默认值

return ret.first->second;

}

private:

RBTree<K, pair<const K, V>, MapKeyOfT> _t;

};

//void MapPrint(const map<string, string>& m)

//{

//map<string, string>::const_iterator it = m.end();

//while (it != m.begin())

//{

//it->first += "x";

//it->second += "y";

//--it;

//cout << it->first << " " << it->second << endl;

//}

//}

void testmap()

{

map<string, string> m;

m.insert({ "right","右"});

m.insert({ "up","上"});

m.insert({ "down","下"});

m.insert({ "left","左"});

m["left"] = "修改左";

m["offer"] = "新增";

//cout << m.find(3) << endl;

//for (auto& e : m)

//{

//cout << e.first << " " << e.second << endl;

//}

//MapPrint(m);

map<string,string>::iterator it = m.end();

while (it != m.begin())

{

//it->second += "y";

//it->first += "x";

--it;

cout << it->first << " " << it->second << endl;

}

cout << endl;

}

}

4.3 MySet

#pragma once

#include"RBTree.h"

namespace my

{

template<class K>

class set

{

struct SetKeyOfT

{

const K& operator()(const K& key)

{

return key;

}

};

public:

typedef typename RBTree<K, const K,SetKeyOfT>::Iterator iterator;

typedef typename RBTree<K, const K,SetKeyOfT>::ConstIterator const_iterator;

const_iterator begin() const

{

return _t.Begin();

}

const_iterator end() const

{

return _t.End();

}

iterator begin()

{

return _t.Begin();

}

iterator end()

{

return _t.End();

}

pair<iterator, bool> insert(const K& key)

{

return _t.insert(key);

}

bool find(const K& key)

{

return _t.find(key);

}

private:

RBTree<K, const K, SetKeyOfT> _t;

};

//void SetPrint(const set<int>& s)

//{

//set<int>::const_iterator it = s.end();

//while (it != s.begin())

//{

////*it = 20;

//--it;

//cout << *it << " ";

//}

//cout << endl;

//}

void testset()

{

set<int> s;

pair<set<int>::iterator,bool> ret = s.insert(5);

cout << *(ret.first) << endl;//查看insert的返回值

s.insert(2);

s.insert(8);

s.insert(15);

s.insert(2);

s.insert(9);

set<int>::iterator it = s.end();

while (it != s.begin())

{

//*it = 10;

--it;

cout << *it <<" ";

}

cout << endl;

//SetPrint(s);

}

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。