C++(14)STL分析与实践之容器适配器

来源:互联网 发布:linux wexitstatus 编辑:程序博客网 时间:2024/05/22 05:07

STL实践与分析

--容器适配器

引:

除了顺序容器,标准库还提供了三种顺序容器适配器:queue,priority_queuestack,适配器是标准库中的概念,包括容器适配器,迭代器适配器和函数适配器。

适配器通用的操作和类型

size_type

一种类型,足以存储此适配器类型的最大对象长度

value_type

0

container_type

基础容器类型,适配器在此容器类型上实现

Aa;

创建一个空适配器,命名为a

Aa(c);

创建一个名为a的新适配器,初始化为c的副本

关系操作符

所有的适配器都支持全部关系操作符:==,!=,<,<=,>,>=


1、使用适配器时,必须包含相关头文件:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stack>  
  2. #include <queue>  

2、覆盖基础容器类型

    默认的queuestack都是基于deque实现,而priority_queue则再vector容器上实现,在创建适配器时,通过将一个顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. stack<string> strStk;  
  2. stack< string,vector<string> > str_stk;  
  3. stack< string,vector<string> > str_stk2(strStk);    //Error  
  4. stack< string,vector<string> > str_stk3(str_stk);   //OK  

stack适配器所关联的基础容器可以是任意一种顺序容器类型。因此,stack栈可以建立在vectorlist或者 deque容器之上。而queue适配器要求其关联的基础容器必须提供push_front运算,因此只能建立在list容器上,而不能建立在vector容器上。priority_queue适配器要求提供随机访问功能,因此可建立在vector或 deque容器上,但不能建立在list容器上。


3、适配器的关系运算由其中的元素依次比较来实现


一、栈适配器

栈容器适配器支持的操作

s.empty()

如果栈为空,则返回true,否则返回false

s.size()

返回栈中元素的个数

s.pop()

删除栈顶元素,但不返回其值

s.top()

返回栈顶元素,但不删除该元素

s.push(item)

再栈顶压入元素

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. const stack<int>::size_type stk_size = 10;  
  2. stack<int> intStk;  
  3.   
  4. int ix = 0;  
  5. while (intStk.size() != stk_size)  
  6. {  
  7.     intStk.push(ix ++);  
  8. }  
  9.   
  10. int err_cnt = 0;  
  11. while (!intStk.empty())  
  12. {  
  13.     int val = intStk.top();  
  14.     if (val != --ix)  
  15.     {  
  16.         cerr << "oops! expected " << ix  
  17.              << " received " << val << endl;  
  18.         ++err_cnt;  
  19.     }  
  20.     intStk.pop();  
  21. }  
  22.   
  23. cout << "Our Program ran with " << err_cnt << " errors!" << endl;  

   默认情况下,栈适配器建立在deque容器上,因此采用deque提供的操作来实现栈功能。例如,执行下面的语句:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. intStack.push(ix++);  

这个操作通过调用push_back操作实现,而该intStk所基于的 deque对象提供。尽管栈是以deque容器为基础实现的,但是程序员不能直接访问deque所提供的操作

二、队列和优先级队列

使用这两种队列,必须包含queue头文件。

队列和优先级队列支持的操作

q.empty()

如果队列为空,则返回true,否则返回false

q.size()

返回队列中元素的个数

q.pop()

删除队首元素,但不返回其值

q.front()

返回队首元素,但不删除该元素

该操作只适用于队列

q.back()

返回对尾元素,但不删除该元素

该操作只适用于队列

q.top()

返回具有最高优先级的元素值,但不删除该元素

该操作只适用于优先级队列

q.push(item)

对于queue,在队尾插入一个新的元素,

对于priority_queue,在基于优先级的适当位置插入新元素

    priority_queue允许用户为队列中存储的元素设置优先级。这种队列不是直接将新元素放置在队列尾部,而是放在比它优先级低的元素前面标准库默认使用元素类型的<操作符来确定它们之间的优先级关系

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //P302 习题9.42  
  2. int main()  
  3. {  
  4. //    freopen("input","r",stdin);  
  5.     stack<string> strStk;  
  6.     string val;  
  7.   
  8.     while (cin >> val)  
  9.     {  
  10.         strStk.push(val);  
  11.     }  
  12.   
  13.     while (!strStk.empty())  
  14.     {  
  15.         val = strStk.top();  
  16.         cout << val << endl;  
  17.         strStk.pop();  
  18.     }  
  19. }  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //习题9.43  
  2. int main()  
  3. {  
  4.     freopen("input","r",stdin);  
  5.     stack<char> sexp;  
  6.     string exp;  
  7.     cin >> exp;  
  8.   
  9.     string::iterator iter = exp.begin();  
  10.     while (iter != exp.end())  
  11.     {  
  12.         if (*iter != ')')  
  13.         {  
  14.             sexp.push(*iter);  
  15.         }  
  16.         else  
  17.         {  
  18.             while (!sexp.empty() && sexp.top() != '(')  
  19.             {  
  20.                 cout << sexp.top() << endl;  
  21.                 sexp.pop();  
  22.             }  
  23.             if (sexp.top() == '(')  
  24.             {  
  25.                 sexp.pop();  
  26.                 sexp.push('@');  
  27.             }  
  28.             else  
  29.             {  
  30.                 cerr << "No match ( !" << endl;  
  31.                 return 0;  
  32.             }  
  33.         }  
  34.         ++iter;  
  35.     }  
  36.   
  37.     while (!sexp.empty())  
  38.     {  
  39.         cout << sexp.top() << endl;  
  40.         sexp.pop();  
  41.     }  
  42. }  

STL实践与分析

--引言、pair类型、关联容器



引言:

    关联容器与顺序容器的本质区别在于:关联容器通过键[key]来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序的存取元素。

    map的元素以键-值【key-value】对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据。

    set仅包含一个键,并有效的支持关于某个键是否存在的查询。

关联容器类型

map

关联数组:元素通过键来存取

Set

大小可变的集合,支持通过键来实现的快速读取

multimap

支持同一个键多次出现map类型

multiset

支持同一个键多次出现set类型


    一般来说,如果希望有效地存储不同值的集合,那么使用set容器比较合适,map容器则更适用于需要存储(乃至修改)每个键所关联的值的情况

   setmap类型的对象不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用multimapmultiset,这两种类型允许多个元素拥有相同的键

一、pair类型

pair类型在utility头文件中定义:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <utility>  


pair类型提供的操作

pair<T1,T2>p1

创建一个空的pair对象,他的两个元素分别是T1T2类型,采用值初始化

pair<T1,T2>p1(v1,v2)

创建一个pair对象,它的两个元素分别是T1T2,其中first成员初始化为v1,second成员初始化为v2

make_pair(v1,v2)

v1v2值创建一个新的pair对象,其元素类型分别为v1v2的类型

p1< p2

两个pair对象之间的小于运算,其定义遵循字典次序:如果p1.first< p2.first 或者!(p2.first< p1.first) && p1.second < p2.second,则返回true

p1== p2

如果两个pair对象的firstsecond成员依次相等,则这两个对象相等。该运算使用其元素的==操作符

p.first

返回p中名为first(公有)数据成员

p.second

返回p的名为second(公有)数据成员


1pair的创建和初始化

    在创建pair对象时,必须提供两个类型名:pair对象所包含的两个数据成员各自对应的类型名,这两个类型不必相同:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. pair<string,string> anon;  
  2. pair<string,int> word_count;  
  3. pair<string,vector<int> > line;  

可以在定义时为每个成员提供初始化式:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. pair<string,string> author("James","Joyce");  
  2. cout << "First: " << author.first << endl;  
  3. cout << "Second: " << author.second << endl;  

可以利用typedef简化pair的声明:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. typedef pair<string,string> Author;  
  2. Author proust("Marcel","Proust");  
  3. Author joyce("James","Joyce");  

2pair对象的操作

    与其他标准库类型不同:对于pair类,可以直接访问其数据成员,因为其数据成员都是公有的,分别命名为firstsecond

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. typedef pair<string,string> Author;  
  2. Author author("James","Joyce");  
  3.   
  4. string firstBook;  
  5. if (author.first == "James" && author.second == "Joyce")  
  6. {  
  7.     firstBook = "Stephen Hero";  
  8. }  

3、生成新的pair对象

    出了构造函数,标准库还定义了make_pair函数,又传递给它的两个实参生成一个新的pair对象:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. pair<string,string> next_auth;  
  2. string first,last;  
  3. while (cin >> first >> last)  
  4. {  
  5.     next_auth = make_pair(first,last);  
  6. }  

等价于:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //利用构造函数  
  2. next_auth = pair<string,string>(first,last);  

由于pair的数据成员是公有的,所以可以直接的读取输入:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. pair<string,string> next_auth;  
  2. while (cin >> next_auth.first >> next_auth.second)  
  3. {  
  4.     //...  
  5. }  

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //P308 习题10.1  
  2.     vector< pair<string,int> > paiVec;  
  3.   
  4.     pair<string,int> paiVal;  
  5.     while (cin >> paiVal.first >> paiVal.second)  
  6.     {  
  7.         paiVec.push_back(paiVal);  
  8.     }  

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //习题10.2  
  2.   //(1)  
  3.   typedef pair<string,int> str_int;  
  4.   vector< str_int > paiVec;  
  5.   
  6.   str_int paiVal;  
  7.   while (cin >> paiVal.first >> paiVal.second)  
  8.   {  
  9.       paiVec.push_back(paiVal);  
  10.   }  

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //2  
  2. vector< pair<string,int> > paiVec;  
  3. string first;  
  4. int second;  
  5.   
  6. while (cin >> first >> second)  
  7. {  
  8.     paiVec.push_back(make_pair(first,second));  
  9. }  

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //3  
  2. vector< pair<string,int> > paiVec;  
  3. string first;  
  4. int second;  
  5.   
  6. while (cin >> first >> second)  
  7. {  
  8.     paiVec.push_back(pair<string,int>(first,second));  
  9. }  

二、关联容器

1、关联容器共享大部分– 但并不是所有的顺序容器的操作:关联容器不支持frontpush_frontpop_frontbackpop_back操作。


2、顺序容器和关联容器公共的操作有一下几种:

    1)表9.2描述的前三种构造函数:

    2)关联容器不能通过容器大小来定义,因为这样的话就无法知道键所对应的值是什么。

    3)第9.3.4节中描述的关系运算。

    4)表9.6列出的beginendrbegin和 rend操作。

    5)表9.5列出的类型别名(typedef)。注意,对于map容器,value_type并非元素的类型,而是描述键及其关联值类型的pair类型。

    6)表9.11中描述的 swap和赋值操作。但关联容器不提供assign函数。

    7)表9.10列出的 clear和 erase操作,但关联容器的erase运算返回 void类型。

    8)表9.8列出的关于容器大小的操作。但resize函数不能用于关联容器。


3、根据键排列元素

    除了上述列出的操作之外,关联容器还提供了其他的操作。而对于顺序容器也提供的相同操作,关联容器也重新定义了这些操作的含义或返回类型,其中的差别在于关联容器中使用了键

    容器元素根据键的次序排列”:在迭代关联容器时,我们可以确保按照键的顺序访问元素,而与元素在容器中的位置完全无关


本文借鉴:http://blog.csdn.net/column/details/zjf666.html?&page=4




0 0
原创粉丝点击