C++ Primer 学习笔记_39_STL实践与分析(13)--multimap与multiset

STL 实践与分析

--multimap 与 multiset

引言:

    map 和 set 容器中,一个键只能对应一个实例,而 multiset 和 multimap 类型则允许一个键对应多个实例。

    multimap 与 multiset 类型与相应的单元素版本具有相同的头文件定义:分别是map 与 set 头文件。

    multimap/multiset 类型与 map/set 的操作相同,只有一个例外: multimap 不支持下标运算。 因为在这类容器中,某个键可能对应多个值。 因此,在使用multimap/multiset 时,对于某个键,必须做好处理多个值的准备,而非只有单一的值

一、元素的添加与删除

    前面所描述的 insert 操作和 erase 操作同样也适用于 multimap 以及 multiset 容器。只是不同的是:由于键不要求是唯一的 , 因此每次调用 insert 总会添加一个元素。

multimap<string,string> authors;
    authors.insert(make_pair("Barth John","Sot-Weed Factor"));
    authors.insert(make_pair("Barth John","Sot-Weed Factor"));

    带有一个键参数的 erase 版本将 删除拥有该键的所有元素 , 并返回删除的个数。而带有一个或一对迭代器参数的版本只删除指定的元素,并返回 void 类型:

multimap<string,string> authors;
  authors.insert(make_pair("Barth John","Sot-Weed Factor"));
  authors.insert(make_pair("Barth John","Sot-Weed Factor"));
  authors.insert(make_pair("Barth John","Sot-Weed Factor"));
  string searchStr("Barth John");

  multimap<string,string>::size_type cnt = authors.erase(searchStr);
  cout << cnt << endl;	//cnt == 3

二、在 multimap  multiset 中查找元素

    关联容器 nap 和 set 的元素是按照顺序存储的,而 multimap 和 multiset 也一样。因此,在 multiset 和 multim 容器中, 如果某个键对应于多个实例,则这些实例在容器中必然相邻存放 。

    因此,在遍历 multimap/multiset 容器时,可以保证依次返回特定键所关联的所有元素。

1 、使用 find 和 count 操作

    使用 count 函数可以求出某个键出现的 次数 ,而 find 操作将返回一个迭代器, 指向第一个拥有正在查找的键的实例 :

multimap<string,string> authors;
  string first,second;
  while (getline(cin,first))
  {
    getline(cin,second);
    authors.insert(make_pair(first,second));
  }

  string search_item("Alain de Botton");
  typedef multimap<string,string>::size_type sz_type;
  sz_type entries = authors.count(search_item);

  multimap<string,string>::iterator iter = authors.find(search_item);
  for (sz_type cnt = 0;cnt != entries; ++cnt,++iter)
  {
    cout << iter -> second << endl;
  }


  cout << "First:\t\t\tSecond:" << endl;
  for (multimap<string,string>::iterator iter = authors.begin(); iter != authors.end(); ++iter)
  {
    cout << iter -> first << "\t\t" << iter -> second << endl;
  }

2 、与众不同的面向迭代器的解决方案

    下表列出的这些操作适用于所有的关联容器,也可用于普通的 map 和 set 容器,但是更常用于 multiamp 和 multiset 容器。所有的这些操作都需要一个键,并返回一个迭代器。

返回迭代器的关联容器操作

m.lower_bound(k)

返回一个迭代器,指向键 不小于 的第一个元素

m.upper_bound(k)

返回一个迭代器,指向键 大于 的第一个元素

m.equal_range(k)

他的 first 成员等价于 m.lower_bound(k),

second 成员等价于 m.upper_bound(k)

    在同一个键上调用 lower_bound 函数和 upper_bound 函数将产生一个迭代器范围,指出该键所关联的所有元素。如果该键在容器中存在 , 则会获得两个不同的迭代器:lower_bound 返回的迭代器指向该键关联的第一个实例 , 而 upper_bound 返回的迭代器则指向最后一个实例的下一位置。如果该键不在 multimap 中 , 这两个操作将 返回同一个迭代器 , 都指向 同一个元素或者同时指向 multimap 超出末端的位置 。

typedef multimap<string,string>::iterator authors_it;
  string searchVal = "Barth John";

  authors_it beg = authors.lower_bound(searchVal),
         end = authors.upper_bound(searchVal);

  while (beg != end)
  {
    cout << beg -> second << endl;
    ++ beg;
  }

这两个操作不会说明键的存在,其关键之处在于返回值给出了迭代器范围。

3 、 equal_range 函数

    可用通过调用 equal_range 函数来取代调用 upper_bound 和 lower_bound 函数。equal_range 函数返回存储一对迭代器的 pair 对象。如果该值存在 , 则 pair 对象中的第一个迭代器指向该键关联的第一个实例 , 第二个迭代器指向该键关联的最后一个实例的下一位置。如果找不到匹配的元素 , 则 pair 对象中的两个迭代器都将指向此键应该插入的位置。

pair<authors_it,authors_it> pos
    = authors.equal_range(searchVal);

  while (pos.first != pos.second)
  {
    cout << pos.first -> second << endl;
  ++ pos.first;
 }
//附:以上两个程序的未用typedef版本
  string searchVal = "Barth John";
  multimap<string,string>::iterator beg = authors.lower_bound(searchVal),
                    end = authors.upper_bound(searchVal);

  cout << "First:\t\t\tSecond:" << endl;
  while (beg != end)
  {
    cout << beg -> first << "\t\t" << beg -> second << endl;
    ++ beg;
  }
  cout << endl;

  pair<multimap<string,string>::iterator,multimap<string,string>::iterator> pos
    = authors.equal_range(searchVal);
  while (pos.first != pos.second)
  {
    cout << pos.first -> first << "\t\t" << pos.first -> second << endl;
    ++ pos.first;
  }
//P325 习题10.26
int main()
{
  multimap<string,string> authors;
  ifstream inFile("input");

  string first,second;
  while (getline(inFile,first))
  {
    getline(inFile,second);
    authors.insert(make_pair(first,second));
  }

  string eraseVal("Barth John");
  if (authors.find(eraseVal) != authors.end())
  {
    multimap<string,string>::size_type cnt = authors.erase(eraseVal);
    cout << "Have erased " << cnt << " books" << endl;
  }
  else
  {
    cout << "Have erased 0 book" << endl;
  }
}
//习题10.27
  multimap<string,string> authors;
  ifstream inFile("input");

  string first,second;
  while (getline(inFile,first))
  {
    getline(inFile,second);
    authors.insert(make_pair(first,second));
  }

  string eraseVal("Barth John");
  pair<multimap<string,string>::iterator,multimap<string,string>::iterator> pos
    = authors.equal_range(eraseVal);
  if (pos.first != pos.second)
  {
    authors.erase(pos.first,pos.second);
  }
  else
  {
    cout << "Have not found eraseVal " << eraseVal << endl;
  }

  cout << "First:\t\tSecond:" << endl;
  for (multimap<string,string>::iterator iter = authors.begin(); iter != authors.end(); ++iter)
  {
    cout << iter -> first << "\t" << iter -> second << endl;
  }
//习题10.28 这节中非常好的习题,值得仔细品读
int main()
{
  multimap<string,string> authors;
  string author,book;
  ifstream inFile("input");

  while (getline(inFile,author))
  {
    getline(inFile,book);

    authors.insert(make_pair(author,book));
  }

  multimap<string,string>::iterator iter = authors.begin();
  if (iter == authors.end())
  {
    cout << "map is empty" << endl;
    return 0;
  }
  /*
  for (multimap<string,string>::iterator it = authors.begin(); it != authors.end(); ++it)
  {
   cout << it -> first << ' ' << it -> second << endl;
  }
 */
  string currAuthor,preAuthor;

  do
  {
    currAuthor = iter -> first;
    if (preAuthor.empty() || currAuthor[0] != preAuthor[0])
    {
      cout << "Author Names Beginning with " << currAuthor[0] << " :" << endl;
    }

    cout << "\t" << currAuthor;
    pair<multimap<string,string>::iterator,multimap<string,string>::iterator> pos = authors.equal_range(currAuthor);
    while (pos.first != pos.second)
    {
      cout << ',' << pos.first -> second;
      ++ (pos.first);
    }
    cout << endl;

    iter = pos.second;
    preAuthor = currAuthor;
  }
  while (iter != authors.end());
}

你可能感兴趣的:(C++ Primer 学习笔记_39_STL实践与分析(13)--multimap与multiset)