C++STL详解(八)-- set,map,multiset,multimap的介绍与使用

关联式容器

序列式容器:底层为线性序列的数据数据结构,里面存储的是元素本身.比如:vector,list,deque.

关联式容器: 用来存储数据,与序列式容器不同的是,其里面存储的是<key,value>结构的键值对,在数据检索时比序式容器的效率更高.

键值对

用来表示具有一一对应关系的一种结构,该结构一般只包括两个成员变量: key和value.key代表键值,value表示与value对应的信息.

template<classT1, classT2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1first;
T2second;
pair(): first(T1()), second(T2()){}
pair(constT1&a, constT2&b): first(a), second(b){}
};

set

set的介绍

1: 与map/multimap不同,map/multimap存放的是真正的键值对<key,value>,set中只放value,但在底层实际上存放的是<value,value>中所构成的键值对.

2: set中插入元素时,只需要插入value即可,不需要构造键值对.

3 set中的元素不可重复(因此可以去重),因为set底层是搜索二叉树,搜索二叉树的特征便是升序+去重.

4: set构造函数中的伪函数默认是less,代表的是升序,如果我们想用降序,可以采用great.

5: set不支持修改,因为搜索二叉树不支持修改.

set的定义方式

方式一: 构造一个set容器,默认仿函数为less,功能为升序+去重.

	set <int> s1{ 1,2,3,4 };      //升序+去重

方式二: 使用拷贝构造,构造与s1一样的set容器.

set<int> s2(s1);

方式三: 使用迭代器区间构造.

string str("yzhzzs");   
set<char> s3(str.begin(), str.end());//构造与str内容相同,但是排列按照ASCLL码升序排列.

方式四: 构造一个降序的set容器.

set<int, greater<int>> s4{ 4,5,2,1};//降序+去重

set的简单使用

使用代码示例:

int main()
{
	set <int> s;
	s.insert(1);                      //插入
	s.insert(3);
	s.insert(5);
	s.insert(4);
	s.insert(6);
	
	auto itlow = s.lower_bound(1);        //返回的是大于或者等于val的值.
	auto itup = s.upper_bound(3);         //返回的是大于val的值了.
	cout << "[" << *itlow << "," << *itup << "]" << endl;
	s.erase(itlow, itup);                //删除.
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	auto pos = s.find(3);              //查找
    if (pos != s.end())                
	{
		s.erase(pos);         //删除之前要先判断找没找到指定数
	}                    
	auto it = s.begin();               //正向迭代器.
	while (it != s.end())       
	{
		cout << *it++ << " ";
	}
	cout << endl;
	auto rit = s.rbegin();             //反向迭代器
	while (rit != s.rend())
	{
		cout << *rit++ << " ";
	}
	cout << endl;
	s.clear();                       //清空容器          
	cout << s.empty() << endl;       //判断容器是否为空

}

multiset

1: multiset和set的底层都由红黑树实现.

2: multiset中,存储的也是<value,value> 组成的键值对,multiset的值不能再容器中进行修改(防止破坏红黑树的性质),但可以在multiset中插入删除.

3: multiset的默认排列方式为由小到大.

4: multiset中的元素可以重复,set中的value是唯一的.

使用代码:

int main()
{
	multiset<int> s;
	s.insert(1);
	s.insert(1);
	s.insert(3);
	s.insert(1);
	s.insert(4);
	auto pos = s.find(1);    //返回的是底层搜索树中第一个值为val的位置.
	s.erase(1); 
	for (auto e : s)
	{
		cout << e << " ";  //  3 4;
	}
}

map的介绍

1: map是关联式容器,它能按照特定的次序进行比较(按照key来比较),
存储的是pair<key,val>结构的键值对,键值key与值key的类型可能不同.

2: map通常由红黑树实现,并且map中的元素总是按照key来排布的.

3: map支持下标访问符,即在通过[key],就可以找到与key对应的value.

4: map通过键值key访问value的速度通常比unordered_map慢,但是map可以直接迭代得到一个有序序列.

map的定义方式

方式一: 使用make_pair构造map.

map<int, double> m1{ make_pair(1,2),make_pair(2,3) };

方式二: 使用拷贝构造一个与m1相同的容器map.

map<int, double> m2(m1);

方式三: 使用迭代器区间指定区间构造.

map<int, double>m3(m2.begin(), m2.end());

方式四: 构造一个降序map.

map<int, double, greater<int>> m4{ make_pair(1, 2));

map的插入

函数声明:
1: 如果x已经在map中,返回pair( x_iterator,false ),x_iterator指的是指向x的迭代器,插入失败时为false.

2: 如果x不在map中,返回pair( new_x_iterator,true),
new_x_iterator指的是指向新插入节点x的迭代器,插入成功时为true,.

总结:
不管插入成功还是失败,返回pair中的iterator都指向x;

pair<iterator,bool> insert ( const value_type& x )

map的插入即将pair插入到红黑树的节点,我们可以调用make_pair模板构造并获取pair.
make_pair:

template <lass T1,class T2)
pair<T1,T2> make_pair( T1 x, T2 y )
{
       return ( pair< T1,T2>(x,y));
}
//map插入
int main()
{
	map <int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	for (auto& e : m)
	{
		cout << e.first << "," << e.second << endl;
	}
}

map的查找

函数声明:
在map中查找插入key为x的元素,找到返回该元素的位置的迭代器,否则返回指向最后一个元素的下一个位置的迭代器.

iterator find ( const key_type& x)

代码示例:

int main()
{
	map <int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	auto it = m.find(1);
	cout << it->first<<":" << it->second << endl;
}

map的删除

函数声明:
删除键值为x的元素,返回值为实际删除的元素个数.

size_type erase ( const key_type& x )

删除position位置上的元素,返回值为void.

void erase ( iterator position )

代码示例:

int main()
{
	map <int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	cout << m.erase(1) << endl;           //1
    
	auto it1 = m.find(2);
	if (it1 != m.end())
	{
		m.erase(it1);                     //void
	}
}

map的[]运算符重载

函数声明:
1: map中有这个key,返回的是value的引用.(查找,修改value)

2: map中没有这个key,插入pair(key,V()),返回的是value的引用(可读可写)

mapped_type& operator[] (const key_type& k)

注意:
V()是一个匿名对象,正式有了模板,T(),这个匿名对象能够根据实参转换为各种类型的对象,这个对象会主动调用默认构造.

map中的[]底层实现:
1: 不管插入成功或者失败,返回的pair中的iterator都指向key.所以我们可以像调用insert.

2: 获取insert调用的pair.

3:获取pair中的first(是一个指向key的iterator),进而获取key中pair的second.

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

使用代码:

int main() 
{
	map<int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	m[2] = "榴莲";           //查找+修改
	m[4] = "西红柿";         //插入+修改.
	for (auto e : m)
	{
		cout  << e.first << "," << e.second << " ";
	}
}

map中的迭代器遍历

map中迭代器遍历三种方法与其他STL容器遍历方式一样.

int main() 
{
	map<int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	m[2] = "榴莲";
	m[3] = "百香果";
	m[4] = "西红柿";
	for (auto e : m)                //范围for遍历
	{
		cout  << e.first << "," << e.second << " ";
		cout << endl;
	}
	auto it1 = m.begin();
	while (it1 != m.end())       //正向迭代器遍历
	{
		cout << it1->first << "," << it1->second << " ";
		++it1;
	}
	cout << endl;
	auto it2 = m.rbegin();     //反向迭代器遍历
	while (it2 != m.rend())
	{
		cout << it2->first << "," << it2->second << " ";
		++it2;
    }
	cout << endl;
}

multimap

multimap大多数的功能与map相同,唯一的区别就是:
map的key是唯一的,而multimap中的key是可以重复的.
对value没有要求,可以重复,也可以不重复.

使用代码:

int main()
{
	multimap<int, string> m;
	m.insert(make_pair(1, "苹果"));
	m.insert(make_pair(1, "百香果"));
	m.insert(make_pair(1, "百香果"));
	m.insert(make_pair(2, "香蕉"));
	m.insert(make_pair(3, "西瓜"));
	for (auto e : m)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
}
	

注意:
因为multimap允许键值冗余,所以当使用[key]时,编译器无法查找确定对应的value,所以在multimap中没有[]重载运算符.

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暂停更新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值