欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++用一棵紅黑樹(shù)同時(shí)封裝出set與map的實(shí)現(xiàn)代碼

 更新時(shí)間:2024年03月15日 11:52:53   作者:樊梓慕  
set中存儲(chǔ)的一般為鍵K即可,而map存儲(chǔ)的一般都是鍵值對(duì)KV,也就是說(shuō)他們結(jié)構(gòu)是不同的,那么我們?nèi)绾尾拍苡靡活w紅黑樹(shù)同時(shí)封裝出set與map兩種容器呢,那么接下來(lái)我們具體地來(lái)研究下STL庫(kù)中是怎樣實(shí)現(xiàn)的,并且進(jìn)行模擬實(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è)模板類(lèi),當(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ù)類(lèi)型。

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)的類(lèi)型
public:
    //...
private:
    Node* _root;
}

即:

在實(shí)現(xiàn)紅黑樹(shù)時(shí),只需要?jiǎng)?chuàng)建這個(gè)KeyOfT類(lèi)對(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)的類(lèi)型
    typedef __TreeIterator<T, Ref, Ptr> Self; //正向迭代器的類(lèi)型
 
    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)行迭代器類(lèi)型的typedef。

需要注意的是,為了讓外部能夠使用typedef后的正向迭代器類(lèi)型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)的類(lèi)型
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)始寫(xiě)呢?還是和適配器一樣,利用普通迭代器的結(jié)構(gòu)滿足反向迭代器的特性即可?這樣是不是比較方便?

  • rbegin()相當(dāng)于end()
  • rend()相當(dāng)于begin()
  • 反向迭代器++相當(dāng)于正向迭代器--
  • 其他操作* != ->和正向迭代器相同
//反向迭代器---迭代器適配器
template<class Iterator>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator> Self; //反向迭代器的類(lèi)型
    
    //限定符不能區(qū)分靜態(tài)變量和類(lèi)型,所以前面可以加上typename標(biāo)識(shí)為類(lèi)型
	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ù),即正向迭代器的類(lèi)型,也就是說(shuō),反向迭代器不知道結(jié)點(diǎn)的引用類(lèi)型和結(jié)點(diǎn)的指針類(lèi)型,因此我們需要在正向迭代器當(dāng)中對(duì)這兩個(gè)類(lèi)型進(jìn)行typedef,這樣反向迭代器才能通過(guò)正向迭代器獲取結(jié)點(diǎn)的引用類(lèi)型和結(jié)點(diǎn)的指針類(lèi)型。

//正向迭代器
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)的類(lèi)型
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)行類(lèi)似這樣的處理:

  • 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)的類(lèi)型
	typedef __TreeIterator<T, Ref, Ptr> Self; //正向迭代器的類(lèi)型
 
	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; //反向迭代器的類(lèi)型
	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)的類(lèi)型
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)代寫(xiě)法)
	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)文章!

相關(guān)文章

  • C++ 動(dòng)態(tài)內(nèi)存分配詳解(new/new[]和delete/delete[])

    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++命名空間實(shí)例解析

    C++命名空間實(shí)例解析

    這篇文章主要介紹了C++命名空間實(shí)例解析,對(duì)C++程序員來(lái)說(shuō)是非常重要的知識(shí)點(diǎn),需要的朋友可以參考下
    2014-08-08
  • C語(yǔ)言實(shí)現(xiàn)文件讀寫(xiě)操作

    C語(yǔ)言實(shí)現(xiàn)文件讀寫(xiě)操作

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)文件讀寫(xiě)操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • C語(yǔ)言趣味編程之水仙花數(shù)

    C語(yǔ)言趣味編程之水仙花數(shù)

    這篇文章介紹了C語(yǔ)言趣味編程之水仙花數(shù),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • C/C++中的sizeof運(yùn)算符和size_t類(lèi)型的詳解

    C/C++中的sizeof運(yùn)算符和size_t類(lèi)型的詳解

    今天小編就為大家分享一篇關(guān)于C/C++中的sizeof運(yùn)算符和size_t類(lèi)型的詳解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • c++11中regex正則表達(dá)式示例簡(jiǎn)述

    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
  • 深入VC回調(diào)函數(shù)的使用詳解

    深入VC回調(diào)函數(shù)的使用詳解

    本篇文章是對(duì)VC回調(diào)函數(shù)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 詳解C++中菱形繼承的原理與解決方法

    詳解C++中菱形繼承的原理與解決方法

    C++中的菱形繼承是多繼承的一種特殊情況,本文將通過(guò)海里帶大家了解一下菱形繼承形成的原因以及想應(yīng)的解決方法,感興趣的可以了解一下
    2023-02-02
  • Qt+Quick實(shí)現(xiàn)播放音樂(lè)和視頻的開(kāi)發(fā)

    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
  • 使用Matlab制作大富翁小游戲的過(guò)程詳解

    使用Matlab制作大富翁小游戲的過(guò)程詳解

    大富翁大家都玩過(guò),走到建筑的位置可以買(mǎi)地,第二圈走到買(mǎi)過(guò)的地可以升級(jí),別人經(jīng)過(guò)后需要付過(guò)路費(fèi),每次經(jīng)過(guò)起點(diǎn)都會(huì)獲得一定資金,玩到最后還沒(méi)破產(chǎn)的就是勝者,本文將制作一個(gè)Matlab版的大富翁小游戲,需要的可以參考一下
    2022-02-02

最新評(píng)論