第五节 标准模板库
一、容器
——————————————————————————————————--------
| 头文件 | 内容 |
——————————————————————————————————--------
| <vector> | 总是在序列末尾添加和删除对象 ,可随机访问 |
| | |
——————————————————————————————————---------
| <deque> | 具备在序列开头添加和删除功能 ,可随机访问 |
| | |
———————————————————————————————————————————
| <list> | 可以有效地在任何位置添加或删除。 但是不能随机访问内容,访问对象 |
| | 的唯一方式是在列表的内部从头开始遍历内容,或从末尾开始反向遍历 |
———————————————————————————————————————————
| <map> | |
| | |
———————————————————————————————————————————
| <set> | |
| | |
———————————————————————————————————————————
| <bitset> | |
| | |
———————————————————————————————————————————
| <stack> | |
| | |
——————————————————————————————————————————-
1、创建矢量容器
vector<int> mydata; 创建矢量容易
mydata.push_back(99); 在矢量末尾添加一个新元素。
vector<int> mydata(100); 创建含有100个元素的矢量,全部初始化为0.
mydata[2]=999; 在第三个元素中存储一个值。
vector<int> mydata(100,-1); 创建100个初始化为-1的元素。
vector<int> mydata;
mydata.reserve(100); 确定要容纳的最小元素个数。如果实参小于矢量的当前容量,
那么调用reserve()就没用。
double data[]={1.5,2.5,.3.5,4.5,5.5,
6.5,7.5,8.5,9.8,10.5}; 创建10个double类型的数组。
vector<double> mydata(data,data+8); 创建一个矢量来存储double类型的元素,其中8个元素的初值对应于data[0]~data[7]的值。
vector<double>构造函数的实参是指针,其中第一个指针指向数组中的第一个初始化元素,第二个指针指向最后一个初始化元素的下一个位置。
因此mydata矢量将含有8个元素。
vector<double> values(mydata.begin(),mydata.end()); values矢量将含有与 mydata矢量中相同的元素。
v.begin() v.end()
_ _ ____|______________________________________ _ |_ _
| obj | obj | obj | obj | obj | obj | obj | obj | |
|_ _ _|_____|_____|_____|_____|_____|_____|_____|_ _ _ |
| |
v.rend() v.rbegin()
调用一个矢量的rbegin()函数将返回指向最后一个元素的迭代器,rend()函数指向第一个元素的下一个位置。
下面创建一个逆序包含另一个矢量中的内容的矢量:
double data[]={1.5,2.5,.3.5,4.5,5.5,6.5,7.5,8.5,9.8,10.5};
vector<double> mydata(data,data+8);
vector<double> values(mydata.rbegin(),mydata.rend());
2、矢量元素的大小
容量(capacity): 容量是在不分配更多内存的情况下容器当前可以容纳的最大对象数目。
大小(size): 大小是实际存储在容器中的对象数目,返回0表示 矢量中没有元素 此时等同 empty();
大小不能大于容量。它们的返回值类型都是vector<T>::size_type
resize()函数可以修改矢量大小,这个函数可以增加或减笑矢量的大小,如果我们指定一个小于当前大小的新大小,
那么会从矢量的末尾删除足够的元素,使它减小到新的大小。如果新大小大于旧大小,那么会向矢量的末尾添加新
元素将长度增加到新的大小。
vector<int> values(5,66);
values.resize(7,88); 第一个实参是矢量的新大小,第二个实参是组成新的大小需要添加的新元素的值。
3、访问矢量中的元素
at(): 它的实参是要访问的元素索引。
[]下标:下标访问。
如果用超出合法范围的下标运算符进行下标,结果就不确定。如果用at()函数进行下标,那么会抛出out_of_range类型的异常。
front(): 访问矢量容器中的第一个元素。
back(): 访问矢量容器中最后一个元素。
for(vector<int>::iterator iter=numbers.begin(); iter<numbers.end(); iter++)
cout<<"" <<*iter;
迭代器访问。
4、在矢量中插入和删除元素
vec.pop_back(): 删除矢量vec中的最后一个元素,并将大小减去1.如果该矢量中没有元素,那么调用pop_back()就没有用。
vec.clear(): 删除vec中的所有元素,因此大小将变成0. 当然,容量保持不变。
vector<int> vec(5,99);
vec.insert(vec.begin()+1,88): 在第一个元素后面插入88,因此执行这个语句后矢量中将包含:99,98,99,99,99,99
vec.insert(ver.begin()+2,3,77): 第一个参数是指定要插入的位置,第二个参数要插入元素的个数,第三个参数是要插入的元素。
vector<int> newvec(5,22);
newvec.insert(newvec.begin()+1,vec.begin()+1,vec.begin()+5); 插入vec中从第二个元素开始的4个元素。
erase():函数可以删除矢量中任何位置的一个或多个元素,但是它也是线性时间函数,通常比较慢。
newvec.erase(newvec.end()-2); 实参是一个指向要删除的元素的迭代器,因此这个语句删除newvec中比最后一个元素的位置小2的元素。
为了删除多个元素,需提供两个迭代器实参来指定间隔。
newvec.erase(newvec.begin()+1,newvec.begin()+4); 这样会删除newvec中的第二个、第三个和第四个元素。
第二个迭代器实参指向的元素不包括在这个操作中。
swap():函数用来交换两个矢量的内容,前提当然是假定这两个矢量中的元素类型相同。
vector<int> first(5,77);
vector<int> second(8,-1);
first.swap(second); 矢量first和second的内容就已经交换了。 注意:矢量的容量和内容交换了,大小当然也交换了。
assign():函数用来用另一个序列替换一个矢量中的全部内容。
vector<double> values;
for(int i=1;i<=50;i++)
values.push_back(2.5*i);
vector<double> newdata(5,3.5);
newdata.assign(values.begin()+1,values.end()-1); 删除newdata中的所有元素,任何插入values中除第一个和第二个元素外的所有元素
的副本。
newdata.assign(30,99.5); 第一个实参是替换序列中的元素的个数,第二个实参是要使用的元素。
newdata的内容被删除并用30个元素替换,每个元素的值都是99.5.
5、在矢量中存储类对象
class T
{
public:
T();
T(const T& t);
~T();
T& operator=(const T& t);
};
对于矢量中存储对象 基本满足上面类的格式。 如果我们不给编译器提供类成员,编译器会提供这些类成员的默认版本。
6、排序矢量元素
sort():可以排序对象,但是该对象必须实现了<运算符。也就是该对象可以用<运算符能进行比较。
7、排序矢量中的指针
vector<Person*> people; 声明存储指针的矢量
whild(true)
{
people.push_back(new Person(firstname,secondename)); 在矢量中添加指针
}
vector<Person*>::iterator iter=people.begin(); 通过迭代器访问矢量中指针的对象。
whild(iter!=people.end())
(*(iter++))->showPerson():
iter=people.begin();
whild(iter!=people.end()) 最后释放矢量中的堆上的内存
delete *(iter++);
people.clear(); 最后清空矢量中的内容。
二、双向队列
1、双向队列声明
deque<Person> people;
push_front(); :向容器的前端添加一个元素。
pop_front(); :删除第一个元素。
三、使用列表容器
列表容器最大优点是可以在固定时间从序列的任意位置插入或删除元素。
1、列表容器的声明
list<string> names;
list<string> names(20); 用指定数目的默认元素创建一个列表。
list<double> values(50,2.71828); 创建包含给定数目的相同元素的列表。
list<double> samples(++values.begin(),--values.end());
这个语句用values列表中的内容创建一个列表,省略了values中的第一个和最后一个元素。
2、向列表中添加元素
push_front(): 向列表的头添加元素。
push_back(): 向列表的尾添加元素。
list<int> data(20,1);
data.insert(++data.begin(),77); 第一个参数是插入位置指定的迭代器,第二个参数是要插入的元素。
list<int>::iterator iter=data.begin();
data.insert(iter,3,88); 第一个是指定位置的迭代器,第二个参数是插入的元素数目,
第三个实参是重复插入的元素。
data.insert(--(--data.end()),numbers.begin(),numbers.end());
3、列表的访问
list<string> text;
list<string>::iterator iter;
for(iter=text.begin(); iter!=text.end(); iter++)
cout<<*iter<<endl;
4、列表上的其他操作
clear(): 删除列表中所有元素。
erase(): 函数允许删除有一个迭代器指定的单个元素,或着由一对迭代器以惯用的方式指定的一个元素序列。
remove(): 函数从列表中删除匹配特定值的元素。
assign(): 函数删除列表中的所有元素并将一个对象复制到列表中给定次数,或者复制品由两个迭代器指定的一个对象序列。
unique(): 函数将消除列表中相邻的重复元素,因此如果我们先排序内容,应用该函数可以确保所有元素都是唯一的。
splice(): 函数允许我们删除一个列表的全部或一部分,并将它插到另一个列表中。两个列表必须存储相同类型的元素。
merge(): 函数删除我们作为一个实参提供的列表中的元素,并将它们插入调用该函数的列表中。
四、使用其他序列容器
1、队列容器
queue<string> names;
队列可以基于列表或者矢量容器。
queue<string,list<string>> names; 适配器模板的第二个类型形参指定要使用的底层序列容器。
队列适配器类扮演底层容器类的包装的角色。我们可以执行的操作范围基本上限制于一下:
back(): 返回对队列后代的元素的引用。
front(): 返回对队列前端的元素的引用。
push(): 将实参指定的元素添加到队列后端。
pop(): 删除队列前端的元素。
size(): 返回队列中元素的数目。
empty(): 如果队列为空则返回true,否则返回false。
2、优先级队列容器
priority_queue<T> nambers;
top(): 返回对优先级队列前端元素的const引用,它僵尸容器中最大或者最高优先级的元素。
push(): 将实参指定的元素添加到队列后端。
pop(): 删除队列前端的元素。
size(): 返回队列中元素的数目。
empty(): 如果队列为空则返回true,否则返回false。
注意:优先级队列于队列容器的可用函数之间有一个明显的区别。使用优先级队列时不能访问队列后端的元素,只能访问前端的元素。
priority_queue<int,vector<int>,greater<int>> numbers; 指定默认基础容器vector<int>和一个用来决定元素顺序的新谓词greater<int>.
priority_queue<Person,vector<Person>,greater<Person>> person;
people.push(Person(first,second));
3、堆栈容器
stack<Person> people;
stack<string,list<string>> names;
top(): 返回对优先级队列前端元素的const引用,它僵尸容器中最大或者最高优先级的元素。
push(): 将实参指定的元素添加到队列后端。
pop(): 删除队列前端的元素。
size(): 返回队列中元素的数目。
empty(): 如果队列为空则返回true,否则返回false。
五、关联容器
关联容器map<K,T> 最重要的特性是无需搜索就可用检索特定对象。关联容器内T类型对象的位置有与对象一起提供的类型K的键确定,因此只要提供
适当的键就可用快速的检索任何对象。该键实际上是一个确定映射中的条目顺序的排序键。
1、使用映射容器
map<Person,string> phonebook;
pair<Person,string> entry=pair<Person,string>(Person("Mel","Gibson"),"213");
pair<Person,string> entry=make_pair(Person("Mel","Gibson"),"213");
map<Person,string> phonebook;
typedef pair<Person,string> Entry;
Entry entry1=Entry(Person("Jack","jones"),"213");
phonebook.insert(entry1);
可用像下面这样检查有没有存储对象:
pair<map<Person,string>::iterator,bool> checkpair;
checkpair=phonebook.insert(entry1);
if(checkpair.second)
cout<<"Insertion succeeded."<<endl;
else
cout<<"Insertion failed."<<endl;
phonebook[Person("Jack","jones")]="213";
string number=phonebook[Person("Jack","jones")]; 访问映射中的对象。
find():函数返回一个指向对应于该键的对象的迭代器,或者指向映射中最后一个条目的下一个位置,它对应于end()函数返回的迭代器。
Person key=Person("Jack","Jones");
map<Person,string>::size_type count=phonebook.erase(key); 当向erase()函数提供一个键时,它返回已经删除的条目个数。
Person key=Person("Jack","Jones");
map<Person,string>::iterator iter=phonebook.find(key);
iter=phonebook,erase(iter); 这情况下,erase函数返回一个迭代器,指向被删除的下一个条目。
六、使用多重映射容器
multimap<Person,string>;
七,迭代器的更多内容
1、流迭代器
istream_iterator<int> numbersInput(cin);
fill():
fill(v.gegin(),v.begin()+9,"invalid"); 它会将v中的前10个元素设置为fill()的最后一个实参指定的值。
replace():
replace(v.begin(),v.end(),"yes","no"); 用no替换v中的yes内容。
char str[]=" A nod is as good as wink to a blind horse.";
replace(str,str+strlen(str),'o','*'); 用*替换以空字符结尾的字符串中出现的"o"
find():
vector<int>::iterator iter=find(v.begin(),v.end(),21);

浙公网安备 33010602011771号