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

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

可我們期望的比較規(guī)則是這樣么?
很明顯不是,我們期望的是set與map都只依據(jù)Key來(lái)比較大小。
那么我們就需要想辦法構(gòu)造一個(gè)我們自己比較的方式出來(lái)。
首先比較的是Key,所以我們需要想辦法取出Key,對(duì)于set而言那就是Key,對(duì)于map而言是pair的first,所以我們可以在紅黑樹(shù)中設(shè)計(jì)仿函數(shù)來(lái)統(tǒng)一設(shè)計(jì),然后在set和map中具體實(shí)現(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) //返回鍵值對(duì)當(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é)點(diǎn)的類型
public:
//...
private:
Node* _root;
}即:

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

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

