您的位置:首页 > 编程语言 > C语言/C++

C++学习笔记-关联容器

2015-12-23 16:17 471 查看
关联容器的类型

是map还是set,关键字可不可以重复,是顺序保存元素,还是无序保存元素,组合出来8种关联容器。

map类型是元素是关键字和值对,set是关键字的简单集合

关联容器不支持顺序容器的位置相关的操作。因为关联容器中元素是根据关键字存储的,这些操作对关联容器没有意义。

关联容器不支持构造函数或插入插入操作等接受一个元素值和一个数量值的操作

关联容器中的迭代器都是双向的。(因为关联容器可以按顺序存储?)

定义关联容器

关联容器也是模板。定义map时,必须既指明关键字类型又指明值类型。定义set时,只需指明关键字类型。

构造函数

默认构造函数

用一对迭代器构造关联容器对象

用列表初始化构造对象

用复制构造函数构造对象

关键字类型的要求

有序容器的关键字类型必须支持比较该类型的对象。默认情况下,标准库使用关键字类型的<运算符来比较两个关键字。

可以自定义关键字类型的比较函数。

构造有序容器对象时,尖括号中指出元素类型,自定义的比较函数的类型紧跟着元素类型给出 。自定义的比较函数作为参数传递给构造函数。例:

bool com(const char *s1,const char *s2)   //比较函数

{

    return strlen(s1)<strlen(s2);

}

int _tmain(int argc, _TCHAR* argv[])

{

    char *ps[]={"hello","hi","china","you"};

    multiset<const char *,decltype(com)*> ms(com);
   //multiset<const char *,bool (*)(const char*,const char*)> ms(com); 

    ms.insert("hello");

    ms.insert("hi");

    ms.insert("china");

    ms.insert("you");

    multiset<const char *,bool (*)(const char*,const char*)>::iterator beg=ms.cbegin();

    multiset<const char *,bool (*)(const char*,const char*)>::iterator e=ms.cend();

    for(;beg!=e;beg++)

    {

        cout<<*beg<<ends;   //输出hi you hello china

    }

    return 0;

}

pair类型

pair是一种标准库类型,定义在头文件utility中。它是一个 类模板,因此,创建一个pair时,我们必须提供两个类型名。分别是pair两个数据成员的类型。

构造函数

默认构造函数  例  pair<string,int> p1;

列表初始化  例 pair<string,int> p2{"hello",5};

带参数的构造函数  pair<string,int> p1("hello",5);

函数返回pair类型的对象

函数中用return make_pair(v1,v2);

或者 return pair<string,int>();

或者 return pair<string,int>(v1,v2);

关联容器中定义的类型

key_type       

value_type

mapped_type

set的key_type  和value_type是一样的。

mapped_type只适用于map

访问这些类型时用作用域运算符,例

map<string,int> m;

map<string,int>::key_type mk;  //string

map<string,int>::value_type mv;  //pair<const string,int> (不能改变元素的关键字。注意set中的元素是const的)

map<string,int>::mapped_type mv;  //int

关联容器迭代器

当解引用一个关联容器迭代器时,会得到一个类型为容器的value_type类型的值的引用



    map<string,int> m;

    m.insert(make_pair("hello",5));

    auto it=m.begin();

    cout<<it->first<<ends<<it->second<<endl; //输出hello 5

遍历关联容器

    map<string,int> m;

    m.insert(make_pair("hello",5));

    m.insert(make_pair("you",4));

    m.insert(make_pair("hi",6));

    auto it=m.cbegin();

    auto e=m.cend();

    while(it!=e){

        cout<<it->first<<ends<<it->second<<endl;

        it++;

    }


关联容器和算法

我们通常不对关联容器使用泛型算法。因为map和set的关键字都是const的。但是可以将关联容器用于只读取元素的算法。用于写的算法时,可以将关联容器作为源序列。也可以作为目标序列,用inserter向关联容器中写入元素。

向关联容器中添加元素

使用insert或emplace向map和set中添加元素

c.insert(v)

c.emplace(args)  //args用来构造一个元素

c.insert(b,e)  //b,e是一对迭代器类型

c.insert(il)  //il是元素列表

c.insert(p,v);  //p是一个迭代器。指示从p开始搜索新元素应该存储的位置

c.emplace(p,args) 

用函数向map和set中插入一个元素时,函数返回一个pair。pair的第一个 元素是一个迭代器,指向具有指定关键字的元素(无论是新插入的,还是容器中已经存在的。)。pair的第二个元素是一个 bool值,指示插入是否成功(c.insert(v)和c.emplace(args))

用函数向multimap和multiset中插入一个元素时,函数返回一个迭代器,指向新插入的元素(因为元素总是插入成功)

用函数向map,multimap,set和multiset中插入多个元素时,函数返回void(c.insert(b,e) 和c.insert(il))

用c.insert(p,v)和c.emplace(p,args)时,返回一个迭代器,指向具有给定关键字的元素

c.insert(v)的返回类型



string word="hello";

map<string,size_t> m;

pair<map<stirng,size_t>::iterator,bool> ret=m.insert(make_pair(word,1)); //auto ret=m.insert(make_pair(word,1));

删除元素

c.erase(p)  //删除迭代器p指向的元素,返回指向p之后元素的迭代器

c.erase(b,e)  //删除迭代器b,e范围内的元素,返回e

c.erase(k)  //删除关键字是k的元素,返回一个size_type类型的值,指出删除的元素的数量

例  auto cnt=m.erase(word);//cnt是1

map的下标操作

map和unordered_map提供了下标操作和一个对应的at函数(其它类型的map和所有类型的set都没有下标操作)

map下标运算符比较特别。如果关键字 不在map中,会为它创建一个元素并插入到map中。关联值将进行值初始化。

map<string,size_t> m;

m["hello"]=1;//添加一个关键字为hello的元素。关联值进行值初始化;然后将1赋予它

对map进行下标操作时,会获得一个mapped_type对象。

当解引用一个map迭代器,会得到一个value_type类型的对象。

访问元素

用find和count

c.find(k)  //返回一个迭代器,指向第一个 关键字是k的元素。如果未找到,返回尾后迭代器

c.count(k) //返回关键字等于k的元素的数量

c.lower_bound(k) //返回一个迭代器,指向第一个关键字不小于k的元素

c.upper_bound(k)   //返回一个迭代器,指向第一个关键字大于k的元素

c.equal_range(k)  //返回一个迭代器pair,表示关键字等于k的元素的范围。若k不存在,pair的两个成员均等于c.end()

在multimap和multiset中查找元素

找到第一个等于关键字的元素:c.find(k)

统计关键字等于k的元素的数量:c.count(k)

遍历所有关键字等于k的元素

第一种方法

for(auto beg=m.lower_bound("hello"),end=m.upper_bound("hello");beg!=end;beg++)

{}

第二种方法(更简便的方法)

for(auto pos=m.equal_range("hello");pos.first!=pos.second;++pos.first){}

无序容器

无序容器使用哈希函数和关键字类型的等于运算符来组织元素。

无序容器的应用场合:

1.关键字类型没有明显的序关系

2.维护元素的序代价太高。

3.性能测试发现问题可以用哈希技术解决

无序容器提供了与有序容器相同的操作(insert,find等)

元素的存储

无序容器在存储上组织为一组桶,每个桶保存零个或多个元素。函数用一个哈希函数将元素映射到桶。将具有一个特定哈希值的所有元素都保存在同一个桶中。(同一个关键字的元素会在同一个桶中。但是也允许不同关键字的元素映射到相同的桶)

无序容器对关键字类型的要求

可以直接定义关键字是内置类型(包括指针类型)、string或智能指针类型的无序容器

不能直接定义关键字类型为自定义类型的无序容器。为了能将自定义类作为关键字类型,我们需要提供函数来替代==运算符和哈希值计算函数。



class Sales_data{

public:

string isbn() const{return bookNo;}

private:

string bookNo;

unsigned units_sold;

double revenue;

};

size_t hasher(const Sales_data &sd)

{

return hash<string>()(sd.isdn());

}

bool eqOp(const Sales_data &lhs,const Sales_data &rhs)

{

return lhs.isbn()==rhs.isbn();

}

unordered_multiset<Sales_data,decltype(hasher)*,decltype(eqOp)*> bookeStore(42,hasher,eqOp);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: