C++用一棵紅黑樹同時封裝出set與map的實現(xiàn)代碼
前言
我們了解到set中存儲的一般為鍵K即可,而map存儲的一般都是鍵值對KV,也就是說他們結(jié)構(gòu)是不同的,那么我們?nèi)绾尾拍苡靡活w紅黑樹同時封裝出set與map兩種容器呢?
簡單的說就是模板的使用,對于set存儲的<K,K>,對于map存儲的是<K,pair<K,V>>;
那么紅黑樹我們就可以使用模板,比如RBTree<K,T>,T就是這個模板類,當(dāng)set使用時就是K,當(dāng)map使用時就是pair。
那么接下來我們具體地來研究下STL庫中是怎樣實現(xiàn)的,并且進行模擬實現(xiàn)。
1.紅黑樹模板參數(shù)的控制
template<class K, class T> class RBTree
那么對于set:
template<class K>
class set
{
public:
//...
private:
RBTree<K, K> _t;
};對于map:
template<class K, class V>
class map
{
public:
//...
private:
RBTree<K, pair<K, V>> _t;
};即:

思考:既然對于map來說pair中有K,那么是不是可以將第一個模板參數(shù)省略呢?
- 對于set容器來說:可以,因為set傳入紅黑樹的第二個參數(shù)與第一個參數(shù)是一樣的;
- 對于map容器來說:不行,因為map容器所提供的接口當(dāng)中有些是只要求給出鍵值Key的,比如find和erase。
2.紅黑樹節(jié)點的定義
//紅黑樹結(jié)點的定義
template<class T>
struct RBTreeNode
{
//三叉鏈
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
//存儲的數(shù)據(jù)
T _data;
//結(jié)點的顏色
int _col;
//構(gòu)造函數(shù)
RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};對于模板參數(shù)T來說,set使用就是K,map使用就是pair<K,V>,對應(yīng)著set與map中節(jié)點存儲的數(shù)據(jù)類型。
3.pair的比較規(guī)則引出紅黑樹仿函數(shù)設(shè)計
紅黑樹是一棵二叉搜索樹,所以當(dāng)我們尋找插入位置或者查找時一定會比較節(jié)點值之間的大小。
新插入節(jié)點值小于當(dāng)前節(jié)點值,就往左走;
新插入節(jié)點值大于當(dāng)前節(jié)點值,就往右走;
這是之前學(xué)習(xí)二叉搜索樹最基本的特性,那么問題來了,對于map而言,節(jié)點值存儲的是pair<K,V>,可是pair是依據(jù)什么來決定自身的大小呢?first?second?還是什么?
我們來看一下STL庫中對pair比較大小的定義:

可我們期望的比較規(guī)則是這樣么?
很明顯不是,我們期望的是set與map都只依據(jù)Key來比較大小。
那么我們就需要想辦法構(gòu)造一個我們自己比較的方式出來。
首先比較的是Key,所以我們需要想辦法取出Key,對于set而言那就是Key,對于map而言是pair的first,所以我們可以在紅黑樹中設(shè)計仿函數(shù)來統(tǒng)一設(shè)計,然后在set和map中具體實現(xiàn)即可。
set:
template<class K>
class set
{
//仿函數(shù)
struct SetKeyOfT
{
const K& operator()(const K& key) //返回鍵值Key
{
return key;
}
};
public:
//...
private:
RBTree<K, K, SetKeyOfT> _t;
};map:
template<class K, class V>
class map
{
//仿函數(shù)
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv) //返回鍵值對當(dāng)中的鍵值Key
{
return kv.first;
}
};
public:
//...
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};RBTree:
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node; //結(jié)點的類型
public:
//...
private:
Node* _root;
}即:

在實現(xiàn)紅黑樹時,只需要創(chuàng)建這個KeyOfT類對象,就相當(dāng)于實例化了對應(yīng)的set或map中實際的方法,比如:
//查找函數(shù)
iterator Find(const K& key)
{
KeyOfT kot;
Node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) //key值小于該結(jié)點的值
{
cur = cur->_left; //在該結(jié)點的左子樹當(dāng)中查找
}
else if (key > kot(cur->_data)) //key值大于該結(jié)點的值
{
cur = cur->_right; //在該結(jié)點的右子樹當(dāng)中查找
}
else //找到了目標(biāo)結(jié)點
{
return iterator(cur); //返回該結(jié)點
}
}
return end(); //查找失敗
}所以對于紅黑樹來說,所有對應(yīng)的需要比較的部分我們都需要進行修改。
4.紅黑樹的正向迭代器
紅黑樹的正向迭代器實際上就是對結(jié)點指針進行了封裝,因此在正向迭代器當(dāng)中實際上就只有一個成員變量,那就是正向迭代器所封裝結(jié)點的指針。
4.1迭代器的定義
//正向迭代器
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node; //結(jié)點的類型
typedef __TreeIterator<T, Ref, Ptr> Self; //正向迭代器的類型
Node* _node; //正向迭代器所封裝結(jié)點的指針
};4.2迭代器的構(gòu)造
我們通過一個結(jié)點的指針便可以構(gòu)造出一個正向迭代器。
//構(gòu)造函數(shù)
__TreeIterator(Node* node)
:_node(node) //根據(jù)所給結(jié)點指針構(gòu)造一個正向迭代器
{}4.3重載解引用操作符 *
當(dāng)對正向迭代器進行解引用操作時,我們直接返回對應(yīng)結(jié)點數(shù)據(jù)的引用即可。
Ref operator*()
{
return _node->_data; //返回結(jié)點數(shù)據(jù)的引用
}4.4重載箭頭操作符 ->
當(dāng)對正向迭代器進行->操作時,我們直接返回對應(yīng)結(jié)點數(shù)據(jù)的指針即可。
Ptr operator->()
{
return &_node->_data; //返回結(jié)點數(shù)據(jù)的指針
}注意:這里與鏈表List部分的->操作符重載一樣,返回的是地址,即使用時為了可讀性省略了一個->。
4.5重載 == 和 != 操作符
實現(xiàn)時直接判斷兩個迭代器所封裝的結(jié)點是否是同一個即可。
//判斷兩個正向迭代器是否不同
bool operator!=(const Self& s) const
{
return _node != s._node; //判斷兩個正向迭代器所封裝的結(jié)點是否是同一個
}
//判斷兩個正向迭代器是否相同
bool operator==(const Self& s) const
{
return _node == s._node; //判斷兩個正向迭代器所封裝的結(jié)點是否是同一個
}4.6重載 ++、-- 操作符
之前鏈表List迭代器的 ++ 操作符重載的邏輯非常簡單,只需要 node=node->next即可,但是對于一棵二叉搜索樹而言顯然不會這么簡單。
那么按照搜索的邏輯,我們知道++應(yīng)該得到的是中序遍歷的后一個節(jié)點。

根據(jù)圖像我們可以推導(dǎo)出 ++ 的邏輯:
- 如果當(dāng)前結(jié)點的右子樹不為空,則
++操作后應(yīng)該找到其右子樹當(dāng)中的最左結(jié)點。 - 如果當(dāng)前結(jié)點的右子樹為空,則
++操作后應(yīng)該在該結(jié)點的祖先結(jié)點中,找到孩子不在父親右的祖先。
//前置++
Self operator++()
{
if (_node->_right) //結(jié)點的右子樹不為空
{
//尋找該結(jié)點右子樹當(dāng)中的最左結(jié)點
Node* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
_node = left; //++后變?yōu)樵摻Y(jié)點
}
else //結(jié)點的右子樹為空
{
//尋找孩子不在父親右的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent&&cur == parent->_right)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //++后變?yōu)樵摻Y(jié)點
}
return *this;
}那么同樣的對于 -- 操作符的邏輯如下:
- 如果當(dāng)前結(jié)點的左子樹不為空,則
--操作后應(yīng)該找到其左子樹當(dāng)中的最右結(jié)點。 - 如果當(dāng)前結(jié)點的左子樹為空,則
--操作后應(yīng)該在該結(jié)點的祖先結(jié)點中,找到孩子不在父親左的祖先。
//前置--
Self operator--()
{
if (_node->_left) //結(jié)點的左子樹不為空
{
//尋找該結(jié)點左子樹當(dāng)中的最右結(jié)點
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right; //--后變?yōu)樵摻Y(jié)點
}
else //結(jié)點的左子樹為空
{
//尋找孩子不在父親左的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent&&cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //--后變?yōu)樵摻Y(jié)點
}
return *this;
}正向迭代器實現(xiàn)后,我們需要在紅黑樹的實現(xiàn)當(dāng)中進行迭代器類型的typedef。
需要注意的是,為了讓外部能夠使用typedef后的正向迭代器類型iterator,我們需要在public區(qū)域進行typedef。
然后在紅黑樹當(dāng)中實現(xiàn)成員函數(shù)begin和end:
- begin函數(shù)返回中序序列當(dāng)中第一個結(jié)點的正向迭代器,即最左結(jié)點。
- end函數(shù)返回中序序列當(dāng)中最后一個結(jié)點下一個位置的正向迭代器,這里直接用空指針構(gòu)造一個正向迭代器。
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node; //結(jié)點的類型
public:
typedef __TreeIterator<T, T&, T*> iterator; //正向迭代器
iterator begin()
{
//尋找最左結(jié)點
Node* left = _root;
while (left&&left->_left)
{
left = left->_left;
}
//返回最左結(jié)點的正向迭代器
return iterator(left);
}
iterator end()
{
//返回由nullptr構(gòu)造得到的正向迭代器(不嚴謹)
return iterator(nullptr);
}
private:
Node* _root; //紅黑樹的根結(jié)點
};但這樣實現(xiàn)的end()迭代器其實并不符合要求,因為如果對end()位置的迭代器--后,應(yīng)該得到最后一個位置的正向迭代器,但這里很明顯無法實現(xiàn)。
實際上在STL庫中是這樣設(shè)計的:
在紅黑樹的根節(jié)點新增一個頭節(jié)點,這個頭結(jié)點的左孩子為最左節(jié)點,右孩子為最右節(jié)點。
在這樣的結(jié)構(gòu)下,正向迭代器的begin()只需用頭節(jié)點的左孩子構(gòu)造即可,反向迭代器的rbegin()只需用頭結(jié)點的右孩子構(gòu)造出一個正向迭代器然后再對該正向迭代器進行封裝,得到反向迭代器即可。end和rend()
但是如果紅黑樹加入了這個頭節(jié)點,就會改變之前我們實現(xiàn)的紅黑樹的很多邏輯,這里就不實現(xiàn)了。
5.紅黑樹的反向迭代器
還記得我們之前學(xué)習(xí)過的反向迭代器的實現(xiàn)么?C++ 反向迭代器模擬實現(xiàn)_C 語言_腳本之家 (jb51.net)
反向迭代器需不需要我們從零開始寫呢?還是和適配器一樣,利用普通迭代器的結(jié)構(gòu)滿足反向迭代器的特性即可?這樣是不是比較方便?
- rbegin()相當(dāng)于end()
- rend()相當(dāng)于begin()
- 反向迭代器++相當(dāng)于正向迭代器--
- 其他操作* != ->和正向迭代器相同
//反向迭代器---迭代器適配器
template<class Iterator>
struct ReverseIterator
{
typedef ReverseIterator<Iterator> Self; //反向迭代器的類型
//限定符不能區(qū)分靜態(tài)變量和類型,所以前面可以加上typename標(biāo)識為類型
typedef typename Iterator::reference Ref; //結(jié)點指針的引用
typedef typename Iterator::pointer Ptr; //結(jié)點指針
Iterator _it; //反向迭代器所封裝的正向迭代器
//構(gòu)造函數(shù)
ReverseIterator(Iterator it)
:_it(it) //根據(jù)所給正向迭代器構(gòu)造一個反向迭代器
{}
Ref operator*()
{
return *_it; //通過調(diào)用正向迭代器的operator*返回結(jié)點數(shù)據(jù)的引用
}
Ptr operator->()
{
return _it.operator->(); //通過調(diào)用正向迭代器的operator->返回結(jié)點數(shù)據(jù)的指針
}
//前置++
Self& operator++()
{
--_it; //調(diào)用正向迭代器的前置--
return *this;
}
//前置--
Self& operator--()
{
++_it; //調(diào)用正向迭代器的前置++
return *this;
}
bool operator!=(const Self& s) const
{
return _it != s._it; //調(diào)用正向迭代器的operator!=
}
bool operator==(const Self& s) const
{
return _it == s._it; //調(diào)用正向迭代器的operator==
}
};需要注意的是,反向迭代器只接收了一個模板參數(shù),即正向迭代器的類型,也就是說,反向迭代器不知道結(jié)點的引用類型和結(jié)點的指針類型,因此我們需要在正向迭代器當(dāng)中對這兩個類型進行typedef,這樣反向迭代器才能通過正向迭代器獲取結(jié)點的引用類型和結(jié)點的指針類型。
//正向迭代器
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef Ref reference; //結(jié)點指針的引用
typedef Ptr pointer; //結(jié)點指針
};反向迭代器的rbegin():紅黑樹的最右節(jié)點;
反向迭代器的rend():空指針構(gòu)造;
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node; //結(jié)點的類型
public:
typedef ReverseIterator<iterator> reverse_iterator; //反向迭代器
reverse_iterator rbegin()
{
//尋找最右結(jié)點
Node* right = _root;
while (right&&right->_right)
{
right = right->_right;
}
//返回最右結(jié)點的反向迭代器
return reverse_iterator(iterator(right));
}
reverse_iterator rend()
{
//返回由nullptr構(gòu)造得到的反向迭代器(不嚴謹)
return reverse_iterator(iterator(nullptr));
}
private:
Node* _root; //紅黑樹的根結(jié)點
};注意:此時迭代器指向的值可以被修改,而在set中我們存儲的是<K,K>,map中存儲的是<K,pair<K,V>>,為了防止二叉樹遭到破壞,所以我們需要進行類似這樣的處理:
- set<K,const K>;
- map<K,pair<const K,V>>;
6.完整代碼
RBTree.h
#pragma once
//枚舉定義結(jié)點的顏色
enum Colour
{
RED,
BLACK
};
//紅黑樹結(jié)點的定義
template<class T>
struct RBTreeNode
{
//三叉鏈
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
//存儲的數(shù)據(jù)
T _data;
//結(jié)點的顏色
int _col; //紅/黑
//構(gòu)造函數(shù)
RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
//正向迭代器
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef Ref reference; //結(jié)點指針的引用
typedef Ptr pointer; //結(jié)點指針
typedef RBTreeNode<T> Node; //結(jié)點的類型
typedef __TreeIterator<T, Ref, Ptr> Self; //正向迭代器的類型
Node* _node; //正向迭代器所封裝結(jié)點的指針
//構(gòu)造函數(shù)
__TreeIterator(Node* node)
:_node(node) //根據(jù)所給結(jié)點指針構(gòu)造一個正向迭代器
{}
Ref operator*()
{
return _node->_data; //返回結(jié)點數(shù)據(jù)的引用
}
Ptr operator->()
{
return &_node->_data; //返回結(jié)點數(shù)據(jù)的指針
}
//判斷兩個正向迭代器是否不同
bool operator!=(const Self& s) const
{
return _node != s._node; //判斷兩個正向迭代器所封裝的結(jié)點是否是同一個
}
//判斷兩個正向迭代器是否相同
bool operator==(const Self& s) const
{
return _node == s._node; //判斷兩個正向迭代器所封裝的結(jié)點是否是同一個
}
//前置++
Self operator++()
{
if (_node->_right) //結(jié)點的右子樹不為空
{
//尋找該結(jié)點右子樹當(dāng)中的最左結(jié)點
Node* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
_node = left; //++后變?yōu)樵摻Y(jié)點
}
else //結(jié)點的右子樹為空
{
//尋找孩子不在父親右的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_right)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //++后變?yōu)樵摻Y(jié)點
}
return *this;
}
//前置--
Self operator--()
{
if (_node->_left) //結(jié)點的左子樹不為空
{
//尋找該結(jié)點左子樹當(dāng)中的最右結(jié)點
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right; //--后變?yōu)樵摻Y(jié)點
}
else //結(jié)點的左子樹為空
{
//尋找孩子不在父親左的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //--后變?yōu)樵摻Y(jié)點
}
return *this;
}
};
//反向迭代器---迭代器適配器
template<class Iterator>
struct ReverseIterator
{
typedef ReverseIterator<Iterator> Self; //反向迭代器的類型
typedef typename Iterator::reference Ref; //結(jié)點指針的引用
typedef typename Iterator::pointer Ptr; //結(jié)點指針
Iterator _it; //反向迭代器所封裝的正向迭代器
//構(gòu)造函數(shù)
ReverseIterator(Iterator it)
:_it(it) //根據(jù)所給正向迭代器構(gòu)造一個反向迭代器
{}
Ref operator*()
{
return *_it; //通過調(diào)用正向迭代器的operator*返回結(jié)點數(shù)據(jù)的引用
}
Ptr operator->()
{
return _it.operator->(); //通過調(diào)用正向迭代器的operator->返回結(jié)點數(shù)據(jù)的指針
}
//前置++
Self& operator++()
{
--_it; //調(diào)用正向迭代器的前置--
return *this;
}
//前置--
Self& operator--()
{
++_it; //調(diào)用正向迭代器的前置++
return *this;
}
bool operator!=(const Self& s) const
{
return _it != s._it; //調(diào)用正向迭代器的operator!=
}
bool operator==(const Self& s) const
{
return _it == s._it; //調(diào)用正向迭代器的operator==
}
};
//紅黑樹的實現(xiàn)
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node; //結(jié)點的類型
public:
typedef __TreeIterator<T, T&, T*> iterator; //正向迭代器
typedef ReverseIterator<iterator> reverse_iterator; //反向迭代器
reverse_iterator rbegin()
{
//尋找最右結(jié)點
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
//返回最右結(jié)點的反向迭代器
return reverse_iterator(iterator(right));
}
reverse_iterator rend()
{
//返回由nullptr構(gòu)造得到的反向迭代器(不嚴謹)
return reverse_iterator(iterator(nullptr));
}
iterator begin()
{
//尋找最左結(jié)點
Node* left = _root;
while (left && left->_left)
{
left = left->_left;
}
//返回最左結(jié)點的正向迭代器
return iterator(left);
}
iterator end()
{
//返回由nullptr構(gòu)造得到的正向迭代器(不嚴謹)
return iterator(nullptr);
}
//構(gòu)造函數(shù)
RBTree()
:_root(nullptr)
{}
//拷貝構(gòu)造
RBTree(const RBTree<K, T, KeyOfT>& t)
{
_root = _Copy(t._root, nullptr);
}
//賦值運算符重載(現(xiàn)代寫法)
RBTree<K, T, KeyOfT>& operator=(RBTree<K, T, KeyOfT> t)
{
swap(_root, t._root);
return *this; //支持連續(xù)賦值
}
//析構(gòu)函數(shù)
~RBTree()
{
_Destroy(_root);
_root = nullptr;
}
//查找函數(shù)
iterator Find(const K& key)
{
KeyOfT kot;
Node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) //key值小于該結(jié)點的值
{
cur = cur->_left; //在該結(jié)點的左子樹當(dāng)中查找
}
else if (key > kot(cur->_data)) //key值大于該結(jié)點的值
{
cur = cur->_right; //在該結(jié)點的右子樹當(dāng)中查找
}
else //找到了目標(biāo)結(jié)點
{
return iterator(cur); //返回該結(jié)點
}
}
return end(); //查找失敗
}
//插入函數(shù)
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr) //若紅黑樹為空樹,則插入結(jié)點直接作為根結(jié)點
{
_root = new Node(data);
_root->_col = BLACK; //根結(jié)點必須是黑色
return make_pair(iterator(_root), true); //插入成功
}
//1、按二叉搜索樹的插入方法,找到待插入位置
KeyOfT kot;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kot(data) < kot(cur->_data)) //待插入結(jié)點的key值小于當(dāng)前結(jié)點的key值
{
//往該結(jié)點的左子樹走
parent = cur;
cur = cur->_left;
}
else if (kot(data) > kot(cur->_data)) //待插入結(jié)點的key值大于當(dāng)前結(jié)點的key值
{
//往該結(jié)點的右子樹走
parent = cur;
cur = cur->_right;
}
else //待插入結(jié)點的key值等于當(dāng)前結(jié)點的key值
{
return make_pair(iterator(cur), false); //插入失敗
}
}
//2、將待插入結(jié)點插入到樹中
cur = new Node(data); //根據(jù)所給值構(gòu)造一個結(jié)點
Node* newnode = cur; //記錄新插入的結(jié)點(便于后序返回)
if (kot(data) < kot(parent->_data)) //新結(jié)點的key值小于parent的key值
{
//插入到parent的左邊
parent->_left = cur;
cur->_parent = parent;
}
else //新結(jié)點的key值大于parent的key值
{
//插入到parent的右邊
parent->_right = cur;
cur->_parent = parent;
}
//3、若插入結(jié)點的父結(jié)點是紅色的,則需要對紅黑樹進行調(diào)整
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent; //parent是紅色,則其父結(jié)點一定存在
if (parent == grandfather->_left) //parent是grandfather的左孩子
{
Node* uncle = grandfather->_right; //uncle是grandfather的右孩子
if (uncle && uncle->_col == RED) //情況1:uncle存在且為紅
{
//顏色調(diào)整
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
//繼續(xù)往上處理
cur = grandfather;
parent = cur->_parent;
}
else //情況2+情況3:uncle不存在 + uncle存在且為黑
{
if (cur == parent->_left)
{
RotateR(grandfather); //右單旋
//顏色調(diào)整
grandfather->_col = RED;
parent->_col = BLACK;
}
else //cur == parent->_right
{
RotateLR(grandfather); //左右雙旋
//顏色調(diào)整
grandfather->_col = RED;
cur->_col = BLACK;
}
break; //子樹旋轉(zhuǎn)后,該子樹的根變成了黑色,無需繼續(xù)往上進行處理
}
}
else //parent是grandfather的右孩子
{
Node* uncle = grandfather->_left; //uncle是grandfather的左孩子
if (uncle && uncle->_col == RED) //情況1:uncle存在且為紅
{
//顏色調(diào)整
uncle->_col = parent->_col = BLACK;
grandfather->_col = RED;
//繼續(xù)往上處理
cur = grandfather;
parent = cur->_parent;
}
else //情況2+情況3:uncle不存在 + uncle存在且為黑
{
if (cur == parent->_left)
{
RotateRL(grandfather); //右左雙旋
//顏色調(diào)整
cur->_col = BLACK;
grandfather->_col = RED;
}
else //cur == parent->_right
{
RotateL(grandfather); //左單旋
//顏色調(diào)整
grandfather->_col = RED;
parent->_col = BLACK;
}
break; //子樹旋轉(zhuǎn)后,該子樹的根變成了黑色,無需繼續(xù)往上進行處理
}
}
}
_root->_col = BLACK; //根結(jié)點的顏色為黑色(可能被情況一變成了紅色,需要變回黑色)
return make_pair(iterator(newnode), true); //插入成功
}
private:
//拷貝樹
Node* _Copy(Node* root, Node* parent)
{
if (root == nullptr)
{
return nullptr;
}
Node* copyNode = new Node(root->_data);
copyNode->_parent = parent;
copyNode->_left = _Copy(root->_left, copyNode);
copyNode->_right = _Copy(root->_right, copyNode);
return copyNode;
}
//析構(gòu)函數(shù)子函數(shù)
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
//左單旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parentParent = parent->_parent;
//建立subRL與parent之間的聯(lián)系
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
//建立parent與subR之間的聯(lián)系
subR->_left = parent;
parent->_parent = subR;
//建立subR與parentParent之間的聯(lián)系
if (parentParent == nullptr)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
}
//右單旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parentParent = parent->_parent;
//建立subLR與parent之間的聯(lián)系
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
//建立parent與subL之間的聯(lián)系
subL->_right = parent;
parent->_parent = subL;
//建立subL與parentParent之間的聯(lián)系
if (parentParent == nullptr)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
}
//左右雙旋
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
//右左雙旋
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
Node* _root=nullptr; //紅黑樹的根結(jié)點
};MySet.h
#pragma once
#include "RBTree.h"
namespace MySet
{
template<class K>
class set
{
//仿函數(shù)
struct SetKeyOfT
{
const K& operator()(const K& key) //返回鍵值Key
{
return key;
}
};
public:
typedef typename RBTree<K, const K, SetKeyOfT>::iterator iterator; //正向迭代器
typedef typename RBTree<K, const K, SetKeyOfT>::reverse_iterator reverse_iterator; //反向迭代器
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
reverse_iterator rbegin()
{
return _t.rbegin();
}
reverse_iterator rend()
{
return _t.rend();
}
//插入函數(shù)
pair<iterator, bool> insert(const K& key)
{
return _t.Insert(key);
}
//查找函數(shù)
iterator find(const K& key)
{
return _t.Find(key);
}
private:
RBTree<K, const K, SetKeyOfT> _t;
};
void test_set1()
{
set<int> s;
int a[] = { 4,2,6,1,3,5,15,7,16,14 };
for (auto e : a)
{
s.insert(e);
}
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
}MyMap.h
#pragma once
#include "RBTree.h"
namespace MyMap
{
template<class K, class V>
class map
{
//仿函數(shù)
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv) //返回鍵值對當(dāng)中的鍵值Key
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator; //正向迭代器
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::reverse_iterator reverse_iterator; //反向迭代器
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
reverse_iterator rbegin()
{
return _t.rbegin();
}
reverse_iterator rend()
{
return _t.rend();
}
//插入函數(shù)
pair<iterator, bool> insert(const pair<const K, V>& kv)
{
return _t.Insert(kv);
}
//[]運算符重載函數(shù)
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
iterator it = ret.first;
return it->second;
}
//查找函數(shù)
iterator find(const K& key)
{
return _t.Find(key);
}
private:
RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};
void test_map1()
{
map<int, int> m;
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
m.insert(make_pair(e, e));
}
map<int, int>::iterator it = m.begin();
while (it != m.end())
{
//it->first += 100;
it->second += 100;
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
}以上就是C++用一棵紅黑樹同時封裝出set與map的實現(xiàn)詳解的詳細內(nèi)容,更多關(guān)于C++紅黑樹封裝set與map的資料請關(guān)注腳本之家其它相關(guān)文章!
- C++使用一棵紅黑樹同時封裝出map和set實例代碼
- C++ map與set封裝實現(xiàn)過程講解
- C++中map和set封裝實現(xiàn)示例
- C++深入探究哈希表如何封裝出unordered_set和unordered_map
- c++容器list、vector、map、set區(qū)別與用法詳解
- C++ STL入門教程(7) multimap、multiset的使用
- C++中map和set的簡介及使用詳解
- C++中set/multiset與map/multimap的使用詳解
- C++中map和set的使用詳細攻略
- C++中常見容器類的使用方法詳解(vector/deque/map/set)
- C++實現(xiàn)map和set封裝詳解
相關(guān)文章
C++ 動態(tài)內(nèi)存分配詳解(new/new[]和delete/delete[])
這篇文章主要介紹了C++ 動態(tài)內(nèi)存分配詳解(new/new[]和delete/delete[]),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
Qt+Quick實現(xiàn)播放音樂和視頻的開發(fā)
這篇文章主要為大家詳細介紹了如何利用Qt+Quick實現(xiàn)播放音樂和視頻的開發(fā),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03

