c++简单实现-map&set (有序)

STL容器分为两类, 一类是序列式容器(vector、list、string等),另一类是关联式容器(map、set、unordered_map、unordered_set)。

两者有何区别呢?
      1、序列式容器内部存储的是元素本身。 而关联式容器内部存储的是键值对。
      2、底层实现的算法不同。 序列式容器底层实现的数据结构为线性的(线性表、链表等), 而关联式容器底层实现的数据结构为非线性的(树)。

(ps:说这些是为了唤醒大家数据结构方面的联想!)

准确来讲这个树是红黑树。

基于上次写的红黑树那节文章代码, 我做了一些修正和添加了一些新接口实现了一些简单的map、set功能。
(ps:有兴趣的大佬可以光顾下本人红黑树篇章, 或阅读其他大佬的文章!谢谢~)
链接:https://editor.csdn.net/md/?articleId=105442405

分析:
1)、这个是map类内部调用红黑树

RBTree<K, pair<K, V>, MapKeyOfValue> _rb;

这个是set的

RBTree<K, K, SetKeyOfValue> _rb;

这个是红黑树的泛型

template<class K, class V, class KeyOfValue>

K是key值。 对于map:V值是一个键值对, 对于set:V值是K值,第三个泛型是一个仿函数, 这个仿函数是是关键, 通过它可以得出对应map、set的V值。
(不然双方调用同一份代码, key值没什么说的, 但是V值不一样出现错误!)

2)、其次map、set容器中insert、迭代器接口都是封装了红黑树中的。
3)、关于迭代器, 采用一个类封装。和list容器相似。

这块关于迭代的++--操作,会遵循一定的原则。
对于++, 判断该结点是否存在右子树,如果存在右子树, 
那么右子树的最左结点就是下一个结点,也就是迭代器指向的结点
如果不存在右子树,就需要向上回溯!
迭代器--操作同理

4)、map容器中[]运算符重载,内部时调用insert接口实现的, map中[]既可以修改、又可以插入。

这个接口是红黑树类中insert接口

pair<iterator, bool> insert(const V& value)

这个接口时map调用红黑树insert接口实现operator[]内容

return ((*(_rb.insert(make_pair(key, V())).first)).second);
简单分析一下:上面的可以分以下3部分:
pair<iterator, bool> ret = _rb.insert(make_pair(key, V()));
iterator it = ret.first;
return (*it).second;

1)红黑树的insert()返回值是一个pair<iterator, bool>键值对, 
ret是得到insert的返回值。因此ret是一个pair<iterator, bool>类型。
2)it 是得到ret键值对的first成员, 对应就是iterator类
3)对it取*, 实质上调用了iterator类中*运算符重载, 会得到存入的键值对类型, 
取second会得到存入键值对的V值, 也就是我们要操作的元素。

源码:

#include<iostream>
#include<utility>
#include<time.h>

using namespace std;

enum COLOR {
	BLACK,
	RED
};


//结点只关心V
template<class V>
struct RBNode {
	//定义RB树的节点信息

	RBNode<V>* _left;
	RBNode<V>* _right;
	RBNode<V>* _parent;
	V _value;
	COLOR _color;		//定义一个枚举变量

	RBNode(const V& value = V())	//相当传递一个匿名的对象
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _value(value)	//pair类中自动赋值	
		, _color(RED)
	{

	}
};

//封装迭代器类
template<class V>
struct RBIterator {

	typedef RBIterator<V> Self;
	typedef RBNode<V> Node;
	typedef Node* pNode;
	pNode _node;

	RBIterator(pNode node) {
		_node = node;
	}

	V& operator*() {
		return _node->_value;
	}

	V* operator->() {
		return &_node->_value;
	}

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

	//前置++接口
	Self& operator++() {
		if (_node->_right) {
			pNode cur = _node->_right;
			while (cur->_left) {
				cur = cur->_left;
			} 
			_node = cur;
		}
		else {
			//这块有问题
			pNode parent = _node->_parent;
			//继续往上回溯
			while (_node == parent->_right) {
				_node = parent;
				parent = parent->_parent;
			}
			//特殊情况 - 根节点无右子树
			//if(_node->right != parent)如果不加这个条件,就_node = parent;
			//如果是无右子树的情况 - parent = _header 而 _header->_right == _root
			//满足上述循环, 则_node = _header, parent = _root;
			//但是下面又走_node = parent = root,这样永远不能到end(_header)
			//因此需要加下面条件 - 防止根节点无右子树造成的死循环!
			if (_node->_right != parent)
				_node = parent;	
		}
		return *this;
	}

	//前置--
	Self& operator--() {
		if (_node->_left) {
			//存在左子树
			_node = _node->_left;
			while (_node->_right) {
				_node = _node->_right;
			}
		}
		else {
			//不存在左子树, 向上回溯
			pNode parent = _node->_parent;
			while (parent->_left == _node) {
				_node = parent;
				parent = parent->_parent;
			}
			//特殊情况 - 根结点无左子树的情况
			if (_node->_left != parent) {
				_node = parent;
			}
		}

		return *this;
	}

};


//传递是3个泛型类型
template<class K, class V, class KeyOfValue>
class RBTree {
public:
	typedef RBNode<V> Node;
	typedef Node* pNode;
	typedef RBIterator<V> iterator;		//重命名iterator,  这块迭代器就是一个类。 和list实现很像。

	RBTree() {
		//无参构造 - 空树
		_header = new Node;
		_header->_left = _header;
		_header->_right = _header;
		_header->_parent = nullptr;
	}

	//iterator begin接口
	iterator begin() {
		return iterator(_header->_left);
	}

	iterator end() {
		return iterator(_header);
	}

	iterator cbegin() {
		return iterator(_header->_right);
	}

	iterator cend() {
		return iterator(_header);
	}

	void RotateL(pNode& parent) {

		pNode SubR = parent->_right;
		pNode SubRL = SubR->_left;

		SubR->_left = parent;
		parent->_right = SubRL;
		pNode pp = parent->_parent;
		if (pp != _header) {
			if (pp->_left == parent) {
				pp->_left = SubR;
			}
			else {
				pp->_right = SubR;
			}
		}
		else {
			_header->_parent = SubR;
		}

		SubR->_parent = pp;
		if (SubRL) {
			SubRL->_parent = parent;
		}
		parent->_parent = SubR;
	}

	void RotateR(pNode& parent) {

		pNode SubL = parent->_left;
		pNode SubLR = SubL->_right;

		SubL->_right = parent;
		parent->_left = SubLR;
		pNode pp = parent->_parent;
		if (pp != _header) {
			if (pp->_left == parent) {
				pp->_left = SubL;
			}
			else {
				pp->_right = SubL;
			}
		}
		else {
			_header->_parent = SubL;
		}

		SubL->_parent = pp;
		if (SubLR) {
			SubLR->_parent = parent;
		}
		parent->_parent = SubL;
	}

	pair<iterator, bool> insert(const V& value) {

		//判断是否为空树
		if (_header->_parent == nullptr) {
			//创建根节点
			pNode root = new Node(value);
			root->_color = BLACK;	//更改根节点颜色为黑色

			//根的父节点 == 头, 头节点的父节点 == 根
			root->_parent = _header;
			_header->_parent = root;

			//头节点的左右节点==根
			_header->_left = root;
			_header->_right = root;

			return make_pair(iterator(root), true);
		}

		//从根节点开始查找合适位置
		pNode cur = _header->_parent;
		pNode parent = nullptr;

		//通过仿函数对象获取V对应的K
		KeyOfValue kov;

		//现在有个问题: 如何区分是pair 还是 value。
		while (cur) {
			parent = cur;
			if (kov(cur->_value) == kov(value))
				return make_pair(iterator(cur), false);
			else if (kov(cur->_value) > kov(value))
				cur = cur->_left;
			else
				cur = cur->_right;
		}

		cur = new Node(value);
		pNode newNode = cur;
		if (kov(parent->_value) > kov(cur->_value))
			parent->_left = cur;
		else
			parent->_right = cur;
		cur->_parent = parent;

		//调整阶段
		while (cur != _header->_parent && cur->_parent->_color == RED) {
			//父亲的节点为红色(红红需要调整,) && 可以判断parent不为根 - 祖父就会存在

			parent = cur->_parent;
			pNode gfather = parent->_parent;
			if (gfather->_left == parent) {
				//叔叔节点在右边
				pNode uncle = gfather->_right;
				if (uncle && uncle->_color == RED) {
					//叔叔节点存在, 并且为红
					//调整方式1
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;

					//继续向上更新
					cur = gfather;
				}
				else {
					//叔叔节点存在, 但为黑 or 叔叔不存在
					//调整完毕之后对gfather往上的节点无影响, 停止调整

					//双旋情况 cur和parent不在同一遍
					if (cur == parent->_right) {
						RotateL(parent);
						swap(parent, cur);
					}

					RotateR(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					//退出
					break;
				}
			}
			else if (gfather->_right == parent) {
				//叔叔节点在左边
				pNode uncle = gfather->_left;
				if (uncle && uncle->_color == RED) {
					//叔叔节点存在, 并且为红
					//调整方式1
					parent->_color = uncle->_color = BLACK;
					gfather->_color = RED;

					//持续往上更新
					cur = gfather;
				}
				else {
					//叔叔节点存在, 但为黑 or 叔叔不存在
					//调整完毕之后对gfather往上的节点无影响, 停止调整

					//双旋 - parent和cur不在一边
					if (cur == parent->_left) {
						RotateR(parent);
						swap(cur, parent);
					}

					//左旋
					RotateL(gfather);
					parent->_color = BLACK;
					gfather->_color = RED;
					//退出
					break;
				}
			}
		}

		//根节点强转为黑色
		_header->_parent->_color = BLACK;

		//更新, 更新最左节点和最右节点 - 方便迭代器的设计
		pNode leMostNode = LeftMost();
		pNode riMostNode = RightMost();
		_header->_left = leMostNode;
		_header->_right = riMostNode;

		return make_pair(iterator(newNode), true);
	}

	//寻找最左节点
	pNode& LeftMost() {
		pNode cur = _header->_parent;
		if (!cur) {
			//无根节点
			return _header->_parent;
		}

		while (cur->_left != nullptr) {
			cur = cur->_left;
		}
		return cur;
	}
	//寻找最右节点
	pNode& RightMost() {
		pNode cur = _header->_parent;
		if (!cur) {
			return _header->_parent;
		}

		while (cur->_right != nullptr) {
			cur = cur->_right;
		}
		return cur;
	}

	//中序遍历
	void InOrder() {
		_InOrder(_header->_parent);
		cout << endl;
	}

	bool isRBTree() {

		pNode root = _header->_parent;
		//根结点为空
		if (!root) {
			return false;
		}
		//根结点为红色
		if (root->_color == RED) {
			return false;
		}

		pNode cur = root;
		int blackCount = 0;
		//统计最左路径下黑色结点的个数
		while (cur) {
			if (cur->_color == BLACK) {
				blackCount++;
			}
			cur = cur->_left;
		}

		//以blackCount左子树的黑色结点为判断, 判断所有路径下的黑色结点个数
		int k = 0;
		return _isRBTree(root, k, blackCount);
	}

	bool _isRBTree(pNode& root, int k, int blackCount) {

		//判断是否到一条路径下结尾
		if (root == nullptr) {
			if (k != blackCount) {
				cout << "每条路径下黑色结点个数不相同!" << endl;
				return false;
			}
			return true;
		}

		//判断是否存在红红情况
		if (root->_color == BLACK) {
			++k;
		}

		pNode parent = root->_parent;
		if (root->_color == RED && parent->_color == RED) {
			cout << "有连续红色的结点" << endl;
			return false;
		}

		return _isRBTree(root->_left, k, blackCount) &&
			_isRBTree(root->_right, k, blackCount);
	}
private:
	void _InOrder(const pNode& root) {
		if (root) {
			_InOrder(root->_left);
			cout << '<' << root->_value.first << "-->" << root->_value.second << '>' << endl;
			_InOrder(root->_right);
		}
	}

private:
	pNode _header;
};

//Map类
template<class K, class V>
class Map {
	
	//实现一个内部类
	struct MapKeyOfValue {
		const K& operator()(const pair<K, V>& data) {
			return data.first;	
		}
	};

public:
	
	//重新定义下RBtree类中iterator, 由于是泛型, 因此这块需要添加typename设置为类型
	typedef typename RBTree<K, pair<K, V>, MapKeyOfValue>::iterator iterator;

	iterator begin() {
		return _rb.begin();
	}

	iterator end() {
		return _rb.end();
	}

	iterator cbegin() {
		return _rb.cbegin();
	}

	iterator cend() {
		return _rb.cend();
	}

	V& operator[](const K& key){
		//return ((*(_rb.insert(make_pair(key, V())).first)).second);
		
		//分解操作
		pair<iterator, bool> ret = _rb.insert(make_pair(key, V()));
		iterator it = ret.first;
		return (*it).second;
	}

	//MAP insert接口
	pair<iterator, bool> insert(const pair<K, V>& data) {
		return _rb.insert(data);
	}

	//MAP test遍历
	void traverse() {
		_rb.InOrder();
	}

private:
	RBTree<K, pair<K, V>, MapKeyOfValue> _rb;
};


//Set类
template<class K>
class Set {

	//定义仿函数
	struct SetKeyOfValue {
		const K& operator() (const K& data) {
			return data;
		}
	};

public:
	typedef typename RBTree<K, K, SetKeyOfValue>::iterator iterator;
	
	iterator begin() {
		return _rb.begin();
	}

	iterator end() {
		return _rb.end();
	}

	iterator cbegin() {
		return _rb.cbegin();
	}

	iterator cend() {
		return _rb.cend();
	}

	//Set插入接口
	pair<iterator, bool> insert(const K& data) {
		return _rb.insert(data);
	}

private:
	RBTree<K, K, SetKeyOfValue> _rb;
};

int main() {

	Map<int, int> mp;
	Set<int> st;
	
	mp.insert(make_pair(4, 1));
	mp.insert(make_pair(5, 1));
	mp.insert(make_pair(6, 1));
	mp.insert(make_pair(7, 1));
	mp.insert(make_pair(1, 1));
	mp.insert(make_pair(2, 1));
	mp.insert(make_pair(3, 1));
	
	st.insert(10);
	st.insert(1);
	st.insert(9);
	st.insert(7);
	st.insert(4);
	st.insert(5);

	cout << "----测试set阶段----" << endl;
	for (auto it : st) {
		cout << it << " ";
	}
	cout << endl;
	cout << endl;
	
	cout << "----测试map阶段---" << endl;
	for (auto it : mp) {
		cout << it.first << "--->" << it.second << endl;
	}

	cout << endl;

	cout << "test[] mp[7] = 77, mp[14] = 14" << endl;
	cout << endl;
	mp[7] = 77;
	mp[14] = 14;

	for (auto it : mp) {
		cout << it.first << "--->" << it.second << endl;
	}

	return 0;
}

这是本人插入顺序:

set:  (10); (1); (9); (7); (4); (5);
map: (4,1);(5,1);(6,1);(7,1);(1,1);(2,1);(3,1);

结果图:
在这里插入图片描述
有兴趣的朋友的可以跑一下这个代码, 研究下。

发布了25 篇原创文章 · 获赞 16 · 访问量 915

猜你喜欢

转载自blog.csdn.net/weixin_44024891/article/details/105480881