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

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

 更新時間:2024年03月15日 11:52:53   作者:樊梓慕  
set中存儲的一般為鍵K即可,而map存儲的一般都是鍵值對KV,也就是說他們結(jié)構(gòu)是不同的,那么我們?nèi)绾尾拍苡靡活w紅黑樹同時封裝出set與map兩種容器呢,那么接下來我們具體地來研究下STL庫中是怎樣實現(xiàn)的,并且進行模擬實現(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就是這個模板類,當set使用時就是K,當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容器所提供的接口當中有些是只要求給出鍵值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>,對應著set與map中節(jié)點存儲的數(shù)據(jù)類型。

3.pair的比較規(guī)則引出紅黑樹仿函數(shù)設計

紅黑樹是一棵二叉搜索樹,所以當我們尋找插入位置或者查找時一定會比較節(jié)點值之間的大小。

新插入節(jié)點值小于當前節(jié)點值,就往左走;

新插入節(jié)點值大于當前節(jié)點值,就往右走;

這是之前學習二叉搜索樹最基本的特性,那么問題來了,對于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ù)來統(tǒng)一設計,然后在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) //返回鍵值對當中的鍵值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類對象,就相當于實例化了對應的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é)點的左子樹當中查找
		}
		else if (key > kot(cur->_data)) //key值大于該結(jié)點的值
		{
			cur = cur->_right; //在該結(jié)點的右子樹當中查找
		}
		else //找到了目標結(jié)點
		{
			return iterator(cur); //返回該結(jié)點
		}
	}
	return end(); //查找失敗
}

所以對于紅黑樹來說,所有對應的需要比較的部分我們都需要進行修改。 

4.紅黑樹的正向迭代器 

紅黑樹的正向迭代器實際上就是對結(jié)點指針進行了封裝,因此在正向迭代器當中實際上就只有一個成員變量,那就是正向迭代器所封裝結(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重載解引用操作符 * 

當對正向迭代器進行解引用操作時,我們直接返回對應結(jié)點數(shù)據(jù)的引用即可。

Ref operator*()
{
    return _node->_data; //返回結(jié)點數(shù)據(jù)的引用
}

4.4重載箭頭操作符 -> 

當對正向迭代器進行->操作時,我們直接返回對應結(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即可,但是對于一棵二叉搜索樹而言顯然不會這么簡單。

那么按照搜索的邏輯,我們知道++應該得到的是中序遍歷的后一個節(jié)點。

根據(jù)圖像我們可以推導出 ++ 的邏輯: 

  • 如果當前結(jié)點的右子樹不為空,則++操作后應該找到其右子樹當中的最左結(jié)點。
  • 如果當前結(jié)點的右子樹為空,則++操作后應該在該結(jié)點的祖先結(jié)點中,找到孩子不在父親右的祖先。
//前置++
Self operator++()
{
	if (_node->_right) //結(jié)點的右子樹不為空
	{
		//尋找該結(jié)點右子樹當中的最左結(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;
}

那么同樣的對于 -- 操作符的邏輯如下:

  • 如果當前結(jié)點的左子樹不為空,則--操作后應該找到其左子樹當中的最右結(jié)點。
  • 如果當前結(jié)點的左子樹為空,則--操作后應該在該結(jié)點的祖先結(jié)點中,找到孩子不在父親左的祖先。
//前置--
Self operator--()
{
	if (_node->_left) //結(jié)點的左子樹不為空
	{
		//尋找該結(jié)點左子樹當中的最右結(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)當中進行迭代器類型的typedef。

需要注意的是,為了讓外部能夠使用typedef后的正向迭代器類型iterator,我們需要在public區(qū)域進行typedef。

然后在紅黑樹當中實現(xiàn)成員函數(shù)begin和end:

  • begin函數(shù)返回中序序列當中第一個結(jié)點的正向迭代器,即最左結(jié)點。
  • end函數(shù)返回中序序列當中最后一個結(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()位置的迭代器--后,應該得到最后一個位置的正向迭代器,但這里很明顯無法實現(xiàn)。

實際上在STL庫中是這樣設計的:

在紅黑樹的根節(jié)點新增一個頭節(jié)點,這個頭結(jié)點的左孩子為最左節(jié)點,右孩子為最右節(jié)點。

在這樣的結(jié)構(gòu)下,正向迭代器的begin()只需用頭節(jié)點的左孩子構(gòu)造即可,反向迭代器的rbegin()只需用頭結(jié)點的右孩子構(gòu)造出一個正向迭代器然后再對該正向迭代器進行封裝,得到反向迭代器即可。end和rend()

但是如果紅黑樹加入了這個頭節(jié)點,就會改變之前我們實現(xiàn)的紅黑樹的很多邏輯,這里就不實現(xiàn)了。

5.紅黑樹的反向迭代器

還記得我們之前學習過的反向迭代器的實現(xiàn)么?C++ 反向迭代器模擬實現(xiàn)_C 語言_腳本之家 (jb51.net)

反向迭代器需不需要我們從零開始寫呢?還是和適配器一樣,利用普通迭代器的結(jié)構(gòu)滿足反向迭代器的特性即可?這樣是不是比較方便?

  • rbegin()相當于end()
  • rend()相當于begin()
  • 反向迭代器++相當于正向迭代器--
  • 其他操作* != ->和正向迭代器相同
//反向迭代器---迭代器適配器
template<class Iterator>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator> Self; //反向迭代器的類型
    
    //限定符不能區(qū)分靜態(tài)變量和類型,所以前面可以加上typename標識為類型
	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é)點的指針類型,因此我們需要在正向迭代器當中對這兩個類型進行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é)點右子樹當中的最左結(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é)點左子樹當中的最右結(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é)點的左子樹當中查找
			}
			else if (key > kot(cur->_data)) //key值大于該結(jié)點的值
			{
				cur = cur->_right; //在該結(jié)點的右子樹當中查找
			}
			else //找到了目標結(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值小于當前結(jié)點的key值
			{
				//往該結(jié)點的左子樹走
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(data) > kot(cur->_data)) //待插入結(jié)點的key值大于當前結(jié)點的key值
			{
				//往該結(jié)點的右子樹走
				parent = cur;
				cur = cur->_right;
			}
			else //待插入結(jié)點的key值等于當前結(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) //返回鍵值對當中的鍵值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)容,更多關于C++紅黑樹封裝set與map的資料請關注腳本之家其它相關文章!

相關文章

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

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

    這篇文章主要介紹了C++ 動態(tài)內(nèi)存分配詳解(new/new[]和delete/delete[]),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • C++命名空間實例解析

    C++命名空間實例解析

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

    C語言實現(xiàn)文件讀寫操作

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

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

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

    C/C++中的sizeof運算符和size_t類型的詳解

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

    c++11中regex正則表達式示例簡述

    這篇文章主要給大家介紹了關于c++11中regex正則表達式的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用c++11具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-11-11
  • 深入VC回調(diào)函數(shù)的使用詳解

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

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

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

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

    Qt+Quick實現(xiàn)播放音樂和視頻的開發(fā)

    這篇文章主要為大家詳細介紹了如何利用Qt+Quick實現(xiàn)播放音樂和視頻的開發(fā),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-03-03
  • 使用Matlab制作大富翁小游戲的過程詳解

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

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

最新評論