『C++进阶』第四章--- 红黑树

目录

1 .红黑树

    1.1 红黑树的概念

 1.2 红黑树的性质

1.4 红黑树结构

    1.5 红黑树的插入操作

1.6 红黑树的验证

1.7 红黑树的删除

1.8 红黑树与AVL树的比较

1.9 红黑树的应用

2. 红黑树的迭代器

红黑树完整含头节点代码

4.map的模拟实现

4.set的模拟实现


1 .红黑树

    1.1 红黑树的概念

        红黑树,是一种二叉搜索树,在每个节点上增加一个存储位表示节点的位置,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因此是接近平衡的。

 1.2 红黑树的性质

  1.  每个结点不是红色就是黑色
  2.  根结点是黑色的
  3.  如果一个结点时红色的,则它的两个孩子结点是黑色的
  4.  对于每个节点,从该结点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
  5.  每个叶子结点都是黑色的(此时的叶子节点指的是空结点)

      那么为什么满足上面的性质,红黑树就能保证: 其最长路径中节点个数不会超过最短路径结点个数的两倍?

        因为数中最短路径应该是全是黑色结点的路径,最长路径就是路径上都是一黑一红的结点,这样因为两个路径的黑色结点数是相同的,所以最长路径应该是最短路径结点个数的二倍,但是,这两条路径都是最理想的状态,一个红黑树上不一定会存在。

enum Color
{
	RED,
	BLACK
};

template <class K,class V>
struct RBTreeNode
{

	RBTreeNode(const pair<K,V>& kv=pair<K,V>(),const Color& color=RED)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_color(color)
	{}

	pair<K, V> _kv;
	RBTreeNode<K,V>* _left;
	RBTreeNode<K,V>* _right;
	RBTreeNode<K,V>* _parent;
	Color _color;
};

      在结点的定义中,为什么要将结点的默认颜色给为红色的?

        因为如果新节点的默认颜色的黑色的话,会违反规则4,所以新结点的默认颜色得是红色,如果他的父节点是黑色,则没有出错,如果父节点是红色,则进行旋转处理。

1.4 红黑树结构

        为了后续实现关联式容器简单,红黑树的实现中增加一个头节点,因为根节点必须为黑色,为了与根节点进行区别,将头节点给成黑色,并且让头节点的parent指向红黑树的根节点,left指向红黑树中最小的结点,right指向红黑树中最大的结点,如下:

    1.5 红黑树的插入操作

        红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

        1. 按照二叉搜索树的树规则插入新结点

	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv,BLACK);
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else return false;
		}
		cur = new RBTree(kv);
		cur->_parent = parent;
		if (parent->_kv.first < kv.first) parent->_right = cur;
		else parent->_left = cur;
		return true;
	}

 2. 新节点插入之后,检测红黑树的性质是否遭到破坏

        因为新节点的默认颜色是红色,因此,如果其父结点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的父结点颜色为红色时,就违反了性质三不能有连在一起的红色结点,此时需要对红黑树分情况来讨论:

 约定: cur为当前结点,p为父结点,g为祖父结点,u为叔叔结点

  •  情况一: cur为红,p为红,g为黑,u存在且为红

       注意:此处看到的树,可能是一颗完整的树,也可能是一颗子树

        如果g是根结点,调整完之后,需要将g改为黑色

        如果g是子树,g一定要有父节点,且g的父节点如果是红色,则需要继续向上调整

         cur和p均为红,违反了性质三,此处能否将p直接改为黑?

         解决方式: 将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

  •  情况二: cur为红,p为红,g为黑,u不存在或u存在且为黑

 说明:u的情况有两种

1. 如果u结点不存在,则cur一定是一个新插入结点,如果cur不是新插入界定啊,则cur和p一定有一个节点的颜色是黑色,就不满足性质四:每条路径黑色节点个数相同

2. 如果u节点存在,则其一定是黑色的,那么cur节点的原来颜色一定是黑色的,现在看到其是红色的原因是因为cur的子树在调整的过程中将cur节点的颜色由黑色改成了红色。

p为g的左孩子,cur为p的左孩子,则进行右单旋,相反,

p为g的右孩子,cur为p的右孩子,则进行左单旋

p、g变色----p变黑,g变红

情况三: cur为红,p为红,g为黑,u不存在或u存在且为黑

 p为g的左孩子,cur为p的右孩子,则针对p进行左单旋;相反

p为g的右孩子,cur为p的左孩子,则针对p进行右单旋

这时就转变为了情况二

红黑树插入完整代码

	bool Insert(const pair<K, V>& kv)
	{
		// 二叉搜索树的正常插入流程
		if (_root == nullptr)
		{
			_root = new Node(kv,BLACK);
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else return false;
		}
		cur = new RBTree(kv);
		cur->_parent = parent;

		if (parent->_kv.first < kv.first) parent->_right = cur;
		else parent->_left = cur;
		
	//  检查树中红黑树性质是否被破坏了
		while (parent->_color == RED)
		{
			Node* grandparent = parent->_parent;
			Node* uncle = nullptr;
			// 插入节点在左右情况
			if (parent == grandparent->_left) 
			{
				uncle = grandparent->_right;
				// 如果 叔叔节点存在且为红,parent和unclue都是红的情况
				if (uncle && uncle->_color == RED)
				{
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandparent->_color = RED;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					// 叔叔节点为黑, parent为红和unclue为黑的情况
					if (cur == parent->_left)
					{
						//当cur和parent都在同一侧时 右旋+变色
						RotateR(grandparent);
						parent->_color = BLACK;
						grandparent = RED;
					}
					else
					{
						//当cur和parent在不同一侧时  先左旋变为上面情况,然后再右旋解决
						RotateL(parent);
						RotateR(grandparent);
						cur->_color = BLACK;
						grandparent = RED;
					}
					break;  // 当u为黑时,旋转结束之后,parent称为了子树的根,且为黑,
					//不会出现再出现parent与parent的父节点都为红的冲突,所以可以直接结束
				}
			}
			else
			{
				uncle = grandparent->_left;
				if (uncle && uncle->_color == RED)
				{
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandparent->_color = RED;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateL(grandparent);
						parent->_color = BLACK;
						grandparent = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(grandparent);
						cur->_color = BLACK;
						grandparent = RED;
					}
					break;
				}
			}
		}

		return true;
	}

1.6 红黑树的验证

     红黑树的检验分为两步:

  1.  检测其是否满足二叉搜索树(中序遍历是否为有序序列)
  2. 检测其是否满足红黑树的性质
public:
		bool IsBalanceTree()
	{
		return _IsBalanceTree(_root);
	}

private:

    bool _IsBalanceTree(Node* root)
	{
		if (root == nullptr) return true;

		if (root->_color != BLACK)
		{
			cout << "违反红黑树性质二: 根节点必须为黑色" << endl;
			return false;
		}
		size_t blackcount = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_color == BLACK) blackcount++;
			cur = cur->_left;
		}
		size_t k = 0;
		return _Frontorder(root, k, blackcount);



	}

	bool _Frontorder(Node* root, int k, int blackcount)
	{
		if (root == nullprt)
		{
			if (k == blackcount) return true;
			else
			{
				cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
				return false;
			}
		}
		Node* parent = cur->_parent;
		if (parent && parent->_color == RED && cur->_color == RED)
		{
			cout << "违反性质三:没有连在一起的红色节点" << endl;
			return false;
		}
		if (root->_color == BLACK) k++;
		return _Frontorder(root->_left, k, blackcount) &&
			_Frontorder(root->_right, k, blackcount);
	}

1.7 红黑树的删除

        可参考:《算法导论》或者《STL源码剖析》

        https://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html

1.8 红黑树与AVL树的比较

        红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是o(log_2 N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行的增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树用的更多。

1.9 红黑树的应用

  1.  C++ STL库------------map/set、multimap/multiset
  2.  jave库
  3. linux内核
  4. 其他的一些库

2. 红黑树的迭代器

    迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代器,需要考虑以下问题:

  •  begin()与end()

        STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在那块?能否给成nullptr呢? 答案是行不通的,因为对end()位置的迭代器进行---操作,必须要能找最后一个元素,此处就不行,因此最好的方式将end()放在头节点的位置。

  • operator++()与operator--()
Self& operator++()
	{
		// 右树存在,找右树中的最左节点
		if (_node->_right)
		{
			Node* cur = _node->_right;
			while (cur->_left) cur = cur->_left;
			_node = cur;
		}
		else
		{
			// 右树不存在
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = cur->_parent;
			}
			// 让end()为nullptr的写法
			 防止最后一个节点++为end()即nullptr
			//if (parent->_parent == cur) _node = nullptr;
			//else _node = parent;
			// 让end()为头节点的写法
			if (cur->_right != parent) _node = parent;
			else _node = cur;
		}
		return *this;
	}
	Self& operator--()
	{
		// 当当前位置在head位置时
		if (_node->_parent->_parent==_node && _node->_color==RED)   // end()情况
		{
			_node = _node->_right;
		}
		// 左树存在
		else if (_node->_left)
		{
			Node* cur = _node->_left;
			while (cur->_right) cur = cur->_right;
			_node = cur;
		}
		else 
		{
			// 左树不存在
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = cur->_parent;
			}
			// 让end为nullptr 的写法
			//if(parent->_parent==cur && parent->_color==RED) _node=nullptr;
			_node = parent;
		}
		return *this;
	}

红黑树完整含头节点代码

#pragma once
#include <iostream>
using namespace std;

enum Color
{
	RED,
	BLACK
};

template <class T>
struct RBTreeNode
{

	RBTreeNode(const T data=T(),const Color& color=RED)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_data(data)
		,_color(color)
	{}

	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Color _color;
};
//template<class K,class T>
//const K& KOFT(const pair<K, T>& data)
//{
//	return data.first;
//}

template <class T, class Ref, class Ptr>
struct RBTreeIterator
{


	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, T&, T*> Self;

	RBTreeIterator(Node* node)
		:_node(node)
	{}

	Self& operator++()
	{
		// 右树存在,找右树中的最左节点
		if (_node->_right)
		{
			Node* cur = _node->_right;
			while (cur->_left) cur = cur->_left;
			_node = cur;
		}
		else
		{
			// 右树不存在
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = cur->_parent;
			}
			// 让end()为nullptr的写法
			 防止最后一个节点++为end()即nullptr
			//if (parent->_parent == cur) _node = nullptr;
			//else _node = parent;
			// 让end()为头节点的写法
			if (cur->_right != parent) _node = parent;
			else _node = cur;
		}
		return *this;
	}
	Self& operator--()
	{
		// 当当前位置在head位置时
		if (_node->_parent->_parent==_node && _node->_color==RED)   // end()情况
		{
			_node = _node->_right;
		}
		// 左树存在
		else if (_node->_left)
		{
			Node* cur = _node->_left;
			while (cur->_right) cur = cur->_right;
			_node = cur;
		}
		else 
		{
			// 左树不存在
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = cur->_parent;
			}
			// 让end为nullptr 的写法
			//if(parent->_parent==cur && parent->_color==RED) _node=nullptr;
			_node = parent;
		}
		return *this;
	}

	bool operator==(const Self& s)
	{
		return _node == s._node;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}

	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
private:
	RBTreeNode<T>* _node;
};


template <class K,class T,class KOFT>
class RBTree
{
	typedef RBTreeNode<T> Node;
	typedef RBTree<K, T, KOFT> Tree;
public:

	typedef RBTreeIterator<T, T&, T*> Iterator;
	typedef RBTreeIterator< T, const  T&, const T*> const_Iterator;

	Iterator Begin()
	{
		return _header->_left;
	}
	Iterator End()
	{
		return _header;
	}
	Iterator Begin()const
	{
		return _header->_left;
	}
	Iterator End() const 
	{
		return _header;
	}

	RBTree() = default;

	RBTree(const Tree& t)
	{
		_root = Copy(t->_root);
	}
	Tree& operator=(const Tree t)
	{
		swap(_root, t->_root);
		return *this; 
	}
	~RBTree()
	{
		Destory(_root);
		_root = nullptr;
	}

	pair<Iterator,bool> Insert(const T& data)
	{
		// 二叉搜索树的正常插入流程
		if (_root == nullptr)
		{
			_root = new Node(data, BLACK);
			_header = new Node(T(), RED);
			_header->_parent = _root;
			_root->_parent = _header;
			_header->_left = LeftMost();
			_header->_right = RightMost();
			return make_pair(Iterator(_root), true);
		}
		Node* parent = nullptr;
		Node* cur = _root;
		KOFT Kof;
		while (cur)
		{
			if (Kof(cur->_data) < Kof(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (Kof(cur->_data) > Kof(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else return make_pair(Iterator(cur), false);
		}
		cur = new Node(data);
		cur->_parent = parent;

		if (Kof(parent->_data) < Kof(data)) parent->_right = cur;
		else parent->_left = cur;
		Node* n = cur;

		//  检查树中红黑树性质是否被破坏了
		while (parent->_parent->_parent!=parent && parent->_color == RED)
		{
			Node* grandparent = parent->_parent;
			Node* uncle = nullptr;

			// 插入节点在左右情况
			if ( parent == grandparent->_left)
			{
				uncle = grandparent->_right;
				// 如果 叔叔节点存在且为红,parent和unclue都是红的情况
				if (uncle && uncle->_color == RED)
				{
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandparent->_color = RED;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					// 叔叔节点为黑, parent为红和unclue为黑的情况
					if (cur == parent->_left)
					{
						//当cur和parent都在同一侧时 右旋+变色
						RotateR(grandparent);
						parent->_color = BLACK;
						grandparent->_color = RED;
					}
					else
					{
						//当cur和parent在不同一侧时  先左旋变为上面情况,然后再右旋解决
						RotateL(parent);
						RotateR(grandparent);
						cur->_color = BLACK;
						grandparent->_color = RED;
					}
					break;  // 当u为黑时,旋转结束之后,parent称为了子树的根,且为黑,
					//不会出现再出现parent与parent的父节点都为红的冲突,所以可以直接结束
				}
			}
			else
			{
				uncle = grandparent->_left;
				if (uncle && uncle->_color == RED)
				{
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandparent->_color = RED;
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateL(grandparent);
						parent->_color = BLACK;
						grandparent->_color = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(grandparent);
						cur->_color = BLACK;
						grandparent->_color = RED;
					}
					break;
				}
			}
		}
		_root->_color = BLACK;
		_header->_left = LeftMost();
		_header->_right = RightMost();
		return make_pair(Iterator(n),true);
	}

	bool IsBalanceTree()
	{
		return _IsBalanceTree(_root);
	}


	Node* Find(const K& key)
	{
		Node* cur = _root;
		KOFT Kof;
		while (cur)
		{
			if (Kof(cur->_data)> key)  cur = cur->_left;
			else if (Kof(cur->_data) < key) cur = cur->_right;
			else return cur;
		}
		return nullptr;
	}
	Node* LeftMost()
	{
		Node* cur = _root;
		while (cur->_left) 	cur = cur->_left;
		return cur;
	}
	Node* RightMost()
	{
		Node* cur = _root;
		while (cur->_right) cur = cur->_right;
		return cur;
	}
	int Size()
	{
		return _Size(_root);
	}
	int Height()
	{
		return _Height(_root);
	}

	void Inorder()
	{
		_Inorder(_root);
		return;
	}

	void RotateR(Node* parent)
	{

		Node* PL = parent->_left;
		Node* PLR = PL->_right;
		
		parent->_left = PLR;
		if (PLR) PLR->_parent = parent;
		PL->_right = parent;
		Node* pparent = parent->_parent;
		//parent->_parent = PL;
		if (pparent == pparent->_parent->_parent && pparent->_color==RED)
		{
			PL->_parent = _root->_parent;
			_root->_parent->_parent = PL;
			_root = PL;
		}
		else
		{
			if (pparent->_left == parent) pparent->_left = PL;
			else pparent->_right = PL;
			PL->_parent = pparent;
		}
		parent->_parent = PL;

	}
	void RotateL(Node* parent)
	{
		Node* PR = parent->_right;
		Node* PRL = PR->_left;
		parent->_right = PRL;
		if (PRL) PRL->_parent = parent;
		PR->_left = parent;
		Node* pparent = parent->_parent;
		//parent->_parent = PR;

		if (pparent == pparent->_parent->_parent && pparent->_color == RED)
		{
			PR->_parent = _root->_parent;
			_root->_parent->_parent = PR;
			_root = PR;
		}
		else
		{
			if (parent == pparent->_left) pparent->_left = PR;
			else pparent->_right = PR;
			PR->_parent = pparent;
		}
		parent->_parent = PR;

	}
	void RotateLR(Node* parent)
	{
		RotateL(parent->_left);
		RotateR(parent);

	}
	void RoatateRL(Node* parent)
	{
		RotateR(parent->_right);
		RotateL(parent);
	}


private:
	bool _IsBalanceTree(Node* root)
	{
		if (root == nullptr) return true;

		if (root->_color != BLACK)
		{
			cout << "违反红黑树性质二: 根节点必须为黑色" << endl;
			return false;
		}
		size_t blackcount = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_color == BLACK) blackcount++;
			cur = cur->_left;
		}
		size_t k = 0;
		return _Frontorder(root, k, blackcount);



	}

	bool _Frontorder(Node* root, int k, int blackcount)
	{
		if (root == nullptr)
		{
			if (k == blackcount) return true;
			else
			{
				cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
				return false;
			}
		}
		Node* cur = root;
		Node* parent = cur->_parent;
		if (parent && parent->_color == RED && cur->_color == RED)
		{
			cout << "违反性质三:没有连在一起的红色节点" << endl;
			return false;
		}
		if (root->_color == BLACK) k++;
		return _Frontorder(root->_left, k, blackcount) &&
			_Frontorder(root->_right, k, blackcount);
	}
	int _Size(Node* root)
	{
		return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
	}
	int _Height(Node* root)
	{
		if (root == nullptr) return 0;
		/*int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;*/

		return max(_Height(root->_left), _Height(root->_right)) + 1;
	}
	void Destory(Node* root)
	{
		if (root == nullptr) return;

		Destory(root->_left);
		Destory(root->_right);
		delete root;
	}

	Node* Copy(Node* root)
	{
		if (root == nullptr) return nullptr;

		Node* N = new Node(root->_date);
		N->_left = Copy(root->_left);
		N->_right = Copy(root->_right);
		return N;
	}
	void _Inorder(Node* root)
	{
		if (root == nullptr) return;

		_Inorder(root->_left);
		cout <<KOFT(root->_data)<< endl;
		_Inorder(root->_right);
	
	}	

	RBTreeNode<T>* _header;
	RBTreeNode<T>* _root;


};

4.map的模拟实现

        map的底层结构就是红黑树,因此在map中直接封装一颗红黑树,然后将其接口包装下即可

template<class K,class V>
class map
{
public:

	struct MapKOFT
	{
		const K& operator()(const pair<K,V>& data)
		{
			return data.first;
		}
	};

	typedef typename RBTree<K,  pair<const K, V>, MapKOFT>::Iterator iterator;
	typedef typename RBTree<K,  pair<const K, V>, MapKOFT>::const_Iterator const_iterator;
	
	iterator begin()
	{
		return _t.Begin();
	}
	iterator end()
	{
		return _t.End();
	}
	iterator begin() const
	{
		return _t.Begin();
	}
	iterator end() const 
	{
		return _t.End();
	}
	pair<iterator,bool> insert(const pair<K,V>& key)
	{
		//return _t.Insert(key);
		return _t.Insert(key);
	}

	iterator find(const K& key)
	{
		return _t.Find(key);
	}
	V& operator[](const K& key)
	{
		pair<iterator, bool> it = insert(make_pair(key,V()));
		return it.first->second;
	}
private:
	RBTree<K, pair<const K, V>, MapKOFT> _t;
};

4.set的模拟实现

set的底层为红黑树,同样只需在set内部封装一颗红黑树,即可将容器实现出来

emplate <class K>
class set
{
	struct SetKOFT
	{
		const K& operator()(const K& data)
		{
			return data;		}
	};
public:

	typedef typename RBTree<K, const K, SetKOFT>::Iterator iterator;
	typedef typename RBTree<K, const K, SetKOFT>::const_Iterator const_iterator;

	iterator begin()
	{
		return _t.Begin();
	}
	iterator end()
	{
		return _t.End();
	}
	const_iterator begin() const 
	{
		return _t.Begin();
	}
	const_iterator end() const 
	{
		return _t.End();
	}
	pair<iterator, bool> insert(const K& key)
	{
		return  _t.Insert(key);
	}
	iterator find(const K& key)
	{
		return _t.Find(key);
	}


private:
	RBTree<K, const K, SetKOFT> _t;
	
};

void Print(const set<int>& s)
{
	set<int>::const_iterator it = s.end();
	while (it != s.begin())
	{
		--it;
		//*it += 2;
		cout << *it << " ";
	}
	cout << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值