map&set学习总结

在STL中map和set都是关联式容器,vector和list是序列式容器,在今天的这篇文章中主要介绍的是map和set的基本用法。
一、set
set是一种key类型的集合结构,所以set是不允许有重复元素的一种结构,set中所有元素的key值都会被自动排序为升序。set和multiset都包含在头文件#include<set>中,set和multiset的底层都是用红黑树实现的,但是set的底层插入机制时insert_unique,multiset的底层插入机制时insert_equal

template < class Key, class Compare = less<Key>,
           class Allocator = allocator<Key> > class set; 

由上述定义可知,set也是一种模板,它的第一个参数Key代表的是键值的类型;第二个参数是一个仿函数,它传入的是键值的比较方式,决定其是升序还是降序;第三个参数是空间配置器。我们主要关心的是set的第一个参数。
set的常用操作:
set的常用操作

在介绍set和map的常用操作之前,先来介绍一种模板类型pair,每个pair可以存储两个值,这两个值可以是任意类型的,pair的两个成员分别是first和second,且pair包含在头文件#include<utility>中。

pair

1、insert,set的插入有三种类型
1.1、pair<iterator,bool> insert(const value_type& x)

其中的value_type是键值的类型,这个版本的插入会返回一个pair类型的对象,其中pair对second成员为false说明插入失败,该元素已经存在,反之则说明插入成功。pair的first成员指向的是要插入位置的迭代器,如果second是false,则first就是这个已经存在元素的迭代器;如果second成员是true,则first就会指向插入位置的迭代器。

1.2、iterator insert(iterator position,const valut_type& val)

postion的类型是一个迭代器的位置,vla表示要插入的数据。如果插入成功,则会返回一个新插入位置的迭代器,否则的话返回这个传入的迭代器。

1.3、插入一段迭代器区间

template<class InputIterator>
void insert(InputIterator first,InputIterator last)

2、erase,删除
2.1、void erase(iterator position)
删除一个迭代器位置
2.2、size_type erase(const value_type& val)
删除成功返回1,删除失败返回0
2.3、void erase(iterator first,iterator last)
删除从first到last的一段迭代器空间
3、find,查找

   iterator find(const value_type& val) const;

如果找到的话就返回这个位置的迭代器,否则就返回end
4、count,统计键值出现的次数

  size_type count(const value_type& val) const;

由于set里面不允许有重复出现的键值,所以count的返回结果就只有0和1两个结果,0就表示不存在,1表示存在。这个功能不就和empty功能重复了吗?当然不会啦!count这个接口一般在multiset中使用的最多,这个主要是为了统一接口罢了。
5、set的迭代器set::iterator是一种const_iterator,所以不允许通过迭代器修改set中的值。
当然了,set中的接口还有很多,在这里只介绍这几个。


multiset的常用操作:
multiset的特性和用法和set的用法完全相同,唯一的差别就是multiset是允许键值重复出现的。
1、insert,插入

iterator insert(const value_type& val)

如果直接插入一个键值的话,在multiset中返回的是插入元素位置的迭代器。
2、count
multiset中可以出现重复的键值。count统计的是相同键值出现的次数。如果count的结果为0则表示没有出现,如果不为0则表示出现的次数 。
下面是我写的一个关于set操作的简单例子:

void TestSet()
{
    //set是K类型的
    set<string> Myset;
    Myset.insert("left");
    Myset.insert("right");
    Myset.insert("high");
    Myset.insert("low");
    Myset.insert("right");
    Myset.insert("right");
    cout<<"size?"<<Myset.size()<<endl;  //4
    cout<<"max_size?"<<Myset.max_size()<<endl;
    set<string>::iterator it=Myset.begin();
    while(it != Myset.end())
    {
        cout<<*it<<" ";
        ++it;
    }
    cout<<endl;
    cout<<Myset.count("right")<<endl;   //1 统计right出现的次数,set是去重的
    it=Myset.find("left");
    if(it != Myset.end())    //找到了
    {
        cout<<*it<<endl;     //left
    }
    //Myset.erase(it);      //删除一个迭代器
    Myset.erase(it,Myset.end());   //删除两个迭代器之间的范围
}

二、map
map是一种Key(键)、value(值)形式的结构,用于保存键和值组成的条目集合。它要求键值必须是唯一的,值可以不唯一,同一个值可以映射到多个键上(所以map在vlaue层面上是允许重复的,这一点不同于set)。所有的元素都会根据键值自动排序。map中的所有元素都是pair,同时拥有键值(Key)和实值(value),pair的first被视为键值,second被当做实值。我们是不可以修改map的key值的,但是我们可以更改map的vlaue值。map的底层是用红黑树实现的,它的insert机制是一种insert_unique()

template<class Key,class T,class Compare=less<Key>,class Alloc=allocator<pair<const Key,T> > >

map也是一个模板,他有四个模板参数类型,第一个是键值的类型(key);第二个是实值的类型(value);第三个是一个仿函数,它传入的是键值的比较方式,默认是升序排列;第四个是空间配置器。
map的常用操作:

map的常用操作

1、insert,插入
1.1、pair<iterator,bool> insert(const value_type& val);
插入一个value_type类型,返回值是一个pair类型。 pair

template<class InputIterator>
    void insert(InputIterator first,InputIterator last);

2、erase
2.1、void erase(iterator position)
删除的是position迭代器位置的元素。
2.2、size_type erase(const key_type& k)
删除这个键值所在的位置,成功返回1,失败返回0。
2.3、void erase(iterator first,iterator last);
删除一段从first到last的迭代器区间
3、find

  iterator find(const key_type& k)

如果查找成功的话则返回这个元素的迭代器,否则返回end,所以在使用find返回的迭代器之前要先判断一下。
4、count

size_type count(const key_type& k)const

map中的count与set的count功能一样。
5、operator[]

mapped_type& operator[](const key_type& k)

map中的operator[]是最常用的,map中operator[]的底层实现利用的是insert来实现的。
operator


multimap:
multimap与map的特性及用法完全相同,但是multimap是允许键值重复的。multimap和 map都包含在头文件#include<map>中,它们的底层也是用红黑树实现的,它的insert机制是insert_equal。它的count与multiset的count的用法及作用完全一样。下面看一下他们的不同:
1、insert

iterator insert(const value_type& val)

如果插入一个元素的话,multimap会返回一个这个插入位置的迭代器。
2、count
count与multiset的count完全相同,multimap中的count统计的是键值出现的次数。
3、multimap中没有重载operator[]。

简单的例子测试map的基本操作:利用map实现一个字典树,利用map统计出现次数最多的前k个水果。

//template<class K,class V>    //自己编写的一个简单的pair
//struct pair
//{
//  K first;
//  V second;
//  pair(const K& key,const V& value)
//      :first(key)
//      ,second(value)
//  {}
//};

//构造一个pair的对象返回
template<class K,class V>
pair<string,int> make_pair(const K& key,const V& value)
{
    return pair<string,int>(key,value);
}

void TestDict()
{
    //map是K,V类型的
    map<string,string> dict;
    dict.insert(pair<string,string>("value","值"));
    dict.insert(pair<string,string>("left","左边"));
    dict.insert(pair<string,string>("right","右边"));
    dict.insert(pair<string,string>("up","上"));
    dict.insert(pair<string,string>("down","下"));
    dict["left"]="剩余";    //也可以使用operator[]来插入或者修改数据的value
    map<string,string>::iterator it=dict.begin();
    while(it != dict.end())
    {
        cout<<(*it).first<<":"<<(*it).second<<endl;
        ++it;
    }
    cout<<endl;

}
vector<int> GetTopKFruits(const vector<string>& fruits)
{
    typedef map<string,int> Map;
    typedef map<string,int>::iterator MapIt;
    vector<int> v;
    //map<string,int> countMap;
    Map countMap;
    for(size_t i=0;i<fruits.size();i++)
    {
        //方法一,find和insert都遍历了这个map,效率不行,但是方便理解,简洁直观
        //map<string,int>::iterator it=countMap.find(fruits[i]);
        //if(it != countMap.end())    //找到了
        //{
        //  it->second++;
        //}
        //else    //没有找到则插入到map中
        //{
        //  //countMap.insert(pair<string,int>(fruits[i],1));
        //  countMap.insert(make_pair(fruits[i],1));
        //}

        //方法二,只查找一次,利用返回pair类型的insert函数
        //pair<MapIt,bool> res=countMap.insert(make_pair(fruits[i],1));
        //if(res.second == false)    //找到了,插入失败
        //{
        //  res.first->second++;
        //}

        //方法三,利用operator[]来实现,operator[]的底层是利用insert来实现的,具体可参考前面提到的operator[]的实现原理
        countMap[fruits[i]]++;
    }
    map<string,int>::iterator it=countMap.begin();
    while(it != countMap.end())
    {
        v.push_back(it->second);
        ++it;
    }
    return v;
}
void TestFruits()
{
    vector<string> fruits;
    fruits.push_back("菠萝");
    fruits.push_back("梨");
    fruits.push_back("水蜜桃");
    fruits.push_back("梨");
    fruits.push_back("菠萝");
    fruits.push_back("水蜜桃");
    fruits.push_back("香蕉");
    fruits.push_back("菠萝");
    fruits.push_back("梨");
    fruits.push_back("水蜜桃");
    fruits.push_back("梨");
    fruits.push_back("菠萝");
    fruits.push_back("水蜜桃");
    fruits.push_back("香蕉");

    vector<int> res=GetTopKFruits(fruits);
    for(size_t i=0;i<res.size();i++)
    {
        cout<<res[i]<<" ";
    }
    cout<<endl;   // 4 4 4 2
}

在这里就分享结束了~~~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值