第十一章标准模板库(STL)习题一. 基本概念与基础知识自测题11.1填空题11.1.1 STL大量使用继承和虚函数是(1)(填对或错)。
因为(2)。
答案:(1)错(2)它使用的是模板技术,追求的是运行的效率,避免了虚函数的开销11.1.2 有两种STL容器:(1)和(2)。
STL不用new和delete,而用(3)实现各种控制内存分配和释放的方法。
答案:(1)第一类容器(2)近容器(3)分配子(allocator)11.1.3 五种主要迭代子类型为(1)、(2)、(3)、(4)和(5)。
STL算法用(6)间接操作容器元素。
sort算法要求用(7)迭代子。
答案:(1)输入(InputIterator)(2)输出(OutputIterator)(3)正向(ForwardIterator)(4)双向(BidirectionalIterator)(5)随机访问(RandomAccessIterator)(6)迭代子(7)随机访问(RandomAccessIterator)11.1.4 三种STL容器适配器是(1)、(2)和(3)。
答案:(1)stack(栈)(2)queue(队列)(3)priority_queue(优先级队列)11.1.5 成员函数end()得到容器(1)的位置,而rend得到容器(2)的位置。
算法通常返回(3)。
答案:(1)最后一个元素的后继位置(2)引用容器第一个元素的前导位置。
实际上这是该容器前后反转之后的end()(3)迭代子11.1.6 适配器是(1),它依附于一个(2)容器上,它没有自己的(3)函数和(4)函数,而借用其实现类的对应函数。
答案:(1)不独立的(2)顺序(3)构造函数(4)析构函数11.1.7 返回布尔值的函数对象称为(1),默认的是(2)操作符。
答案:(1)谓词(predicate)(2)小于比较操作符“<”11.1.8C++标准库中给出的泛型算法包括(1)种算法。
主要包括以下几类:(2)、(3)、(4),每一类都有十种以上算法。
答案:(1)70余(2)查找算法(3)排序(sorting)和通用整序(ordering)算法(4)删除和代替算法11.2简答题11.2.1简述STL中迭代子与C++指针的关系与异同点。
答:迭代子包含内存地址的获得,是面向对象版本的指针。
迭代子与指针有许多相同之处,但迭代子保存所操作的特定容器需要的状态信息,从而实现与每种容器类型相适应的迭代子。
而且有些迭代子操作在所有容器中是一致的,这带来了很大的方便。
如++运算符总是返回容器下一个元素的迭代子,就像数组指针++后指向下一个元素;间接引用符“*”,总是表示迭代子指向的容器元素,就像数组指针加*号后代表指针所指的元素。
迭代子在STL中起粘结剂的作用,用来将STL的各部分结合在一起。
从本质上说,STL 提供的所有算法都是模板,我们可以通过使用自己指定的迭代子来对这些模板实例化。
迭代子可以包括指针,但迭代子又不仅是一个指针。
11.2.2顺序容器包括哪三种?它们各以什么数据结构为基础?各有哪些特点?答:C++标准模板库提供三种顺序容器:vector,list和deque。
vector类和deque 类是以数组为基础的,list类是以双向链表为基础的。
矢量(vector)类提供了具有连续内存地址的数据结构。
它和C/C++的数组一样通过下标运算符[ ]直接有效地访问矢量的任何元素。
与数组不同,vector的内存用尽时,vector自动分配更大的连续内存区,将原先的元素复制到新的内存区,并释放旧的内存区。
内存分配由分配子(allocator)完成。
矢量可以用来实现队列、堆栈、列表和其他更复杂的结构。
vector支持随机访问迭代子,具有最强的功能。
vector的迭代子通常实现为vector元素的指针。
列表(list)是由双向链表(doubly linked list)组成的。
支持的迭代子类型为双向迭代子。
双端队列(deque)(double-ended queue)类。
双端队列允许在队列的两端进行操作。
它是以顺序表为基础的,所以它能利用下标提供有效的索引访问,它支持随机访问迭代子。
它放松了访问的限制,对象既可从队首进队,也可以从队尾进队,同样也可从任一端出队。
而且除了可从队首和队尾移走对象外,也支持通过使用下标操作符“[ ]”进行访问。
当要增加双端队列的存储空间时,可以在内存块中对deque两端分别进行分配。
并且新分配的存储空间保存为指向这些块的指针数组,这样双端队列可以利用不连续内存空间。
因此它的迭代子比vector的迭代子更加智能化。
为双端队列分配的存储块,往往要等删除双端队列时才释放,它比重复分配(再分配和释放)更有效,但也更浪费内存。
使用双端队列容器类来实现矢量容器类所能实现的各种数据结构要更灵活,方便。
11.2.3关联容器有哪四种?简单介绍它们是怎样组成的?各有什么特点?答:四个关联容器为:集合(set),多重集合(multiset),映射(map)和多重映射(multimap)。
集合和多重集合类提供了控制数值集合的操作,其中数值是关键字,即不必另有一组值与每个关键字相关联。
集合与多重集合类的主要差别在于多重集合允许重复的关键字(key),而集合不允许重复的关键字。
集合和多重集合通常实现为红黑二叉排序树。
元素的顺序由比较器函数对象(comparator function object)确定。
如对整型multiset,只要用比较器函数对象less<int>排序关键字,元素即可按升序排列。
映射和多重映射类提供了操作与关键字相关联的映射值(mapped value)的方法。
映射和多重映射的主要差别在于多重映射允许存放与映射值相关联的重复关键字,而映射只允许存放与映射值一一对应的单一关键字。
多重集合关联容器用于快速存储和读取关键字。
多重映射和映射关联容器类用于快速存储和读取关键字与相关值(关键字/数值对,key/value pair)。
11.2.4什么是函数对象?它通常用在什么地方?答:函数对象是一个类,它重载了函数调用操作符(operator())。
该操作符封装了应该被实现为一个函数的操作。
典型情况下,函数对象被作为实参传递给泛型算法,以完全解决类型依赖性的问题。
和“引用”一样,“函数对象”很少独立使用。
函数对象与函数指针相比较有三个优点:第一,函数指针是间接引用,不能作为内联函数,而函数对象可以,这样速度更快;第二,类有数据域,函数对象可以拥有任意数量的额外数据,用这些数据可以用来缓冲当前数据和结果,提高运行质量;第三,编译时对函数对象作类型检查。
11.2.5泛型算法函数名加有后缀_if是什么意思?而加有后缀_copy又代表什么意思?答:_if 表示函数采用的操作是在元素上(满足给定谓词),而不是对元素的值本身进行操作。
如find_if算法表示:在容器指定范围中查找一些特征满足函数指定条件的(满足给定谓词)元素,也就是使某一函数对象返回值第一次为真的元素。
例如;小于特定值的第一个元素。
而find查找含特定值的第一个元素。
_copy 表示算法不仅操作元素的值,而且还把修改的值复制到一个目标范围中。
如reverser 算法颠倒范围中元素的排列顺序,而reverse_copy算法同时把结果复制到目标范围中。
二.编程题与综合练习题11.3编程测试顺序容器矢量(vector)的主要功能和使用方法。
(参考附录C,下同)解:#include<algorithm>#include<vector>#include<iostream>#include<functional>using namespace std;int main(){ostream_iterator<int>output(cout," ");//用输出迭代子output来输出,其中第二参数" "表示用空格分隔各个整数。
int ia[18]={47,29,5,37,13,23,11,61,7,31,41,2,59,19,17,53,43,3};vector<int> vec(ia,ia+9); //数据填入vector;vector共有7个构造函数,常用3个//vector(),用以声明空的vector;vector(n),用以声明有n个元素的vector;//vector(first,last),用以声明一个vector,//其元素的初值是从区间[first,last)所指定的序列中的元素复制而来的;vector<int> vec2(18);if(vec.empty()) cout<<"vector空"<<endl;else{cout<<"vector不空,"<<"vector中的元素:"<<endl;unique_copy(vec.begin(),vec.end(),output);cout<<endl;}cout<<"当前分配元素空间数量:"<<vec.capacity()<<endl;vec.reserve(12);cout<<"当前为vector保留的最小分配元素空间数量:"<<vec.capacity()<<endl; vec.erase(vec.begin(),vec.end());cout<<"当前分配元素空间数量:"<<vec.capacity()<<endl;vec.resize(10);cout<<"当前重新分配元素空间数量为10,实际分配元素空间数量:"<<vec.capacity()<<endl;vec.assign(ia+10,ia+16);cout<<"vector存放序列容许最大长度:"<<vec.max_size()<<endl;cout<<"vector中的元素:"<<endl;unique_copy(vec.begin(),vec.end(),output);cout<<endl;vec.assign(ia,ia+18);cout<<"vector中的元素:"<<endl;unique_copy(vec.begin(),vec.end(),output);cout<<endl;sort(vec.begin(),vec.end(),greater<int>());//降序排列cout<<"vector中的元素:"<<endl;unique_copy(vec.begin(),vec.end(),output);cout<<endl;cout<<"用反转迭代子输出vector中的元素:"<<endl;unique_copy(vec.rbegin(),vec.rend(),output);cout<<endl;cout<<"第1个元素:"<<vec.front()<<endl;cout<<"最后1个元素:"<<vec.back()<<endl;cout<<"第8个元素:"<<vec[6]<<endl;cout<<"原vector2中的元素:"<<endl;unique_copy(vec2.begin(),vec2.end(),output);cout<<endl;vec2.swap(vec);cout<<"交换后vector2中的元素:"<<endl;unique_copy(vec2.begin(),vec2.end(),output);cout<<endl;return 0;}11.4编程测试顺序容器列表(list)的主要功能和使用方法。