[C++]map,set


一、set


1.set简介和基本用法


set底层的实现就是红黑树

相较于算法中的 find O(N)
set用AVL树实现的find可以达到 O(logN)
用红黑树实现的find可以达到O(2logN)

将数据放入set中后会自动去重排序


2.multiset

相较于set少了去重的部分,可以让数据重复

find,erase等成员删除的都是中序遍历中第一个成员


二、map


1.pair(键值对)

template<class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;

	T1 first;
	T2 second;

	pair()
		:first(T1()) //传入类型默认值构造
		,second(T2())
	{}

	pair(const T1& a,const T2& b)
		:first(a)
		,second(b)
	{}
};

2.插入

	map<int, int> m;
	m.insert(pair<int, int>(1, 1)); //相当于传入pair临时构造的匿名对象
									//pair构造函数,构造一个匿名对象
	m.insert(make_pair(2, 2));      //函数 模板 构造一个pair对象
									//实际上更推荐用make_pair,不用声明模板参数,自动推断

map的插入返回值为

pair<iterator, bool> Insert(const T& data)
//当插入的数在map中没有时,则插入成功,返回插入val的迭代器(引用),和true
//当插入的数在map中已经有了,则插入失败,返回已经和val相同值的迭代器(引用),和false

作为其operator[]的底层


3.operator[]


map用来计数

	map<string, int> countmap;
	string strs[] = { "iphone","iphone","huawei","honor","huawei","summim" };
	for (auto& e : strs)
	{
		map<string, int>::iterator ret = countmap.find(e);
		if (ret != countmap.end())
			//(*ret).second++;
			ret->second++;
		else
			countmap.insert(make_pair(e, 1));
	}

	for (auto& e : countmap)
	{
		cout << e.first << ":" << e.second << endl;
	}

也可以用operator[]更加便捷

	map<string, int> countmap;
	string strs[] = { "iphone","iphone","huawei","honor","huawei","summim" };
	for (auto& e : strs)
	{
		//如果不在map中,则operator[]会插入pair<str,0> (0 == int() 即默认类型值)  返回映射对象(次数)的引用并且++
		//如果在map中	,则operator[]返回key对应的映射对象(次数)的应用,对其++
		countmap[e]++;
	}

operator的底层可以看作为

mapped_type& operator[](const key_type& k)
		{
			return (*((this->insert (make_pair(k, mapped_type()) )).first)).second;
			//this->insert (make_pair(k, mapped_type()) 返回值为 pair<map<string,int>::iterator,bool>
			//.first                                    取 map<string,int>::iterator
			//*											取 pair<key_type,mapped_type>
			//.second									取 mapped_type 并返回其引用
			//返回引用的作用是,方便对其进行以后的操作
		}

所以operator有三种用途
1.插入
2.查找k对应的映射对象
3.修改k对应的映射对象的值

	map<string, int> countmap;
	countmap["vivo"];     //插入
	countmap["vivo"] = 1; //修改
	cout << countmap["vivo"] << endl; //查找
	countmap["oppo"] = 2; //插入+修改

	map<string, string> dict;
	dict.insert(make_pair("string", "字符串"));
	dict["string"] = "字字符串";
	dict["sort"] = "排序";

4.multimap

multimap也是去掉了查重的功能,但没有 operator[]
当有多个相同的键值时,不知道返回哪一个对应的val


三、模拟实现set,map


底层都是由红黑树实现的,为了方便了解逻辑,删除了红黑树部分接口

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

template <class T, class Ref, class Ptr>
struct __BRTreeIterator
{
	typedef BRTreeNode <T> Node;
	Node* _node;
	typedef __BRTreeIterator<T, Ref, Ptr> Self;
	typedef __BRTreeIterator<T, T&, T*> iterator;
	
	__BRTreeIterator(Node* node)
		:_node(node)
	{}

	//普通迭代器时,是拷贝构造
	//const迭代器,指出迭代器构造const迭代器
	__BRTreeIterator(const iterator& s)
		:_node(s._node)
	{}
	
	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}

	Self operator++()
	{
		if (_node->_right)
		{
			Node* min = _node->_right;
			while (min->_left)
			{
				min = min->_left;
			}
			_node = min;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self operator--()
	{
		if (_node->_left)
		{
			Node* max = _node->_left;
			while (max->_right)
			{
				max = max->_right;
			}
			_node = max;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

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

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


template<class K, class T, class KeyOfT>
class BRTree
{
public:
	typedef BRTreeNode<T> Node;
	typedef __BRTreeIterator<T, T&, T*> iterator;
	typedef __BRTreeIterator<T, const T&, const T*> const_iterator;

	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return iterator(left);
	}

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

	const_iterator begin() const
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		return const_iterator(left);
	}

	const_iterator end() const
	{
		return const_iterator(nullptr);
	}

	pair<iterator, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = Black;
			return make_pair(iterator(_root), true);
		}
		KeyOfT kot;
		//父子节点确定插入的位置
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else
				return make_pair(iterator(cur), false);
		}

		//走到这cur就是要插入的位置
		//cur要连接parent,parent也要连接cur---判断靠kv的大小
		cur = new Node(data);
		Node* newnode = cur;
		if (kot(parent->_data) > kot(cur->_data))
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = cur;
			cur->_parent = parent;
		}

		while (parent && parent->_col == Red)
		{
			Node* grandparent = parent->_parent;
			//parent分在grandparent左右
			if (grandparent->_left == parent)
			{
				//关键是看uncle节点不存在/红色/黑色的情况
				Node* uncle = grandparent->_right;
				if (uncle && uncle->_col == Red)
				{
					grandparent->_col = Red;
					parent->_col = uncle->_col = Black;
					.....
					
		return make_pair(iterator(newnode), true);
	}

private:
	Node* _root = nullptr;
};

1.set

#include "RBTree.hpp"

namespace 9TSe
{
	template<class K>
	class Set
	{
	public:
		struct SetKeyOfT
		{
			const K& operator()(const K& k)
			{
				return k;
			}
		};
		typedef typename BRTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename BRTree<K, K, SetKeyOfT>::const_iterator const_iterator;

		pair<iterator, bool> Insert(const K& k)
		{
			return _t.Insert(k);
		}

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

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

		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end() const
		{
			return _t.end();
		}

	private:
		BRTree<K, K, SetKeyOfT> _t;
	};

set内数据本身是不能修改的
否则会破坏树的结构
所以迭代器都是由红黑树的const_iterator构成的


2.map

#include "RBTree.hpp"

namespace 9TSe
{
	template<class K, class V>
	class Map
	{
	public:
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};

		V& operator[](const K& k)
		{
			pair<iterator, bool> ret = Insert(make_pair(k, V()));
			return ret.first->second;
		}

		typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
		typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

		pair<iterator, bool> Insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}

		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end() const
		{
			return _t.end();
		}

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

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

	private:
		BRTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值