STL学习网址:
- C语言中文网:http://c.biancheng.net/stl/
vector
是将元素放到动态数组中加以管理的容器。vector
容器可以随机存取元素,也就是说支持[]
运算符和at
方式存取。
vector
在尾部添加或者移除元素非常快,在中间操作非常耗时,因为它需要移动元素
vector的基本用法
既然vector是容器,那么就可以向这个容器添加删除元素。
基本用法:
front()
返回头部元素的引用,可以当左值back()
返回尾部元素的引用,可以当左值push_back()
添加元素,只能尾部添加pop_back()
移除元素,只能在尾部移除
初始化
第一种:用数组来初始化
int a[10] = {0};
vector<int> my_list1(a, a+10);
第二种:直接初始化
vector<int> my_list1(10);
//定义一个vector容器
vector<int> v1;
//插入元素(尾部插入)
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
//迭代器遍历打印
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
//修改头部元素的值(front()返回是引用,可以当左值)
v1.front() = 44;
//输出头部元素
cout<<"头部元素:"<< v1.front() << endl;
//修改尾部的值(back()返回是引用,可以当左值)
v1.back() = 99;
//输出尾部元素
cout << "尾部元素" << v1.back() <<endl;
//删除元素(从尾部删除)
v1.pop_back();
//迭代器遍历打印
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
vector的遍历
vector的遍历有多种方式,可以根据[]
或者迭代器遍历。
需要主要的是:
[]
方式,如果越界或出现其他错误,不会抛出异常,可能会崩溃,可能数据随机出现at
方式,如果越界或出现其他错误,会抛出异常,需要捕获异常并处理- 迭代器提供了逆向遍历,可以通过迭代器来实现逆向遍历,当然上面两种方式也可以
int main(int argc, const char * argv[]) {
//创建vector
vector<int> v1;
//插入元素
for (int i = 0; i < 10; i++) {
v1.push_back(i);
}
//遍历-[]取值
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
//遍历-at取值
for (int i = 0; i < v1.size(); i++) {
cout << v1.at(i) << " ";
}
cout << endl;
//遍历-迭代器遍历
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
//遍历-迭代器逆向遍历
for (vector<int>::reverse_iterator it = v1.rbegin(); it != v1.rend(); it++) {
cout << *it << " ";
}
cout << endl;
//测试越界
cout << "[]越界:" << v1[20] << endl; //不会抛出异常,可能会崩溃,可能会乱码
cout << "at越界:" << v1.at(20) << endl; //会抛出异常,需要捕获异常
return 0;
}
vector的push_back强化
push_back是在当前vector的内存末尾拷贝元素进入容器。注意这个地方可能产生浅拷贝,所以容器中的对象要支持拷贝操作。另外,如果vector初始化了个数,而不初始化具体的值,push_back也只会在最后面追加。
//初始化10个元素的容器
vector<int> v(10);
//打印容器大小
cout << v.size() << endl;
//push_back添加元素
v.push_back(100);
//打印容器大小
cout << v.size() << endl;
//遍历后的结果是 0 0 0 0 0 0 0 0 0 0 100
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
vector的元素删除
vector的删除,是根据位置进行删除,如果想要删除某个元素,需要找到当前元素的迭代器位置,再进行删除。
iterator erase(iterator it); //删除向量中某一个元素
iterator erase(iterator first, iterator last) //删除向量中[first,last)中元素
void pop_back(); //删除向量中最后一个元素
void clear(); //删除向量中所有元素
erase(iterator)
函数,删除后会返回当前迭代器的下一个位置。
//1 创建容器并初始化
vector<int> v1(10);
for (int i = 0; i < v1.size(); i++) {
v1[i] = i;
}
//2 区间删除
//--2.1 删除前3个元素
v1.erase(v1.begin(), v1.begin() + 3);
//--2.2 删除指定位置的元素
v1.erase(v1.begin() +3);
//3 根据元素的值进行删除,删除值为2的元素
v1.push_back(2);
v1.push_back(2);
vector<int>::iterator it = v1.begin();
while (it != v1.end()) {
if (*it == 2) {
it = v1.erase(it); //删除后,迭代器指针会执行下一个位置并返回。
}else{
it++;
}
}
//4 遍历打印
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
vector的插入元素
vector提供了insert
函数,结合迭代器位置插入指定的元素。
如果迭代器位置越界,会抛出异常。
//初始化vector对象
vector<int> v1(10);
//在指定的位置插入元素10的拷贝
v1.insert(v1.begin() + 3, 10);
//在指定的位置插入3个元素11的拷贝
v1.insert(v1.begin(), 3, 11);
//遍历
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
总之,增加新元素时,如果超过当前的容量,则容量会自动扩充2倍,如果两倍容量仍不足,就扩大至足够大的容量。本图是直接在原空间基础上画的新增空间,其实要复杂得多,包括重新配置、元素移动、释放原始空间的过程。因此对vector容器而言当增加新的元素时,有可能很快完成(直接存在预留空间中),有可能稍慢(扩容后再放新元素);对修改元素值而言是较快的;对删除元素来说,若删除尾部元素较快,非尾部元素则稍慢,因为牵涉到删除后的元素移动。
综合操作示例
利用vector编一个学生信息[学号(它是关键字)、姓名、性别、出生日期]管理类,有添加函数、查询函数(依据学好号查询),显示函数(对查询结果完成显示)。并编制测试函数测试。
(1)基本思想是要有一个基本信息类及该基本信息的集合类。对本题而言,基本信息类是学生类Student,集合类是StudCollect。 (2)Student类中定义了4个基本的成员变量及屏幕显示函数Display()。StudCollect定义了一个成员变量vector<Student> v,可看出本类是对学生集合对象的一个管理类,是实现集合管理类的根本所在。该类主要定义了Add(Student& s)函数及Student *Find(string strNO)函数。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Student //学生类
{
public:
string m_strNO; //学号
string m_strName; //姓名
string m_strSex; //性别
string m_strDate; //出生日期
public:
Student(string strNO, string strName,string strSex,string strDate):
m_strNO(strNO),m_strName(strName),m_strSex(strSex),m_strDate(strDate){}
void Display(){
cout <<m_strNO<<"\t"<<m_strName<<"\t"<<m_strSex<<"\t"<<m_strDate<<endl;
}
};
class StudCollect
{
vector<Student> m_vStud;
public:
void Add(Student& s){
m_vStud.push_back(s);
}
Student* Find(string strNO){
bool bFind = false;
for(int i=0; i<m_vStud.size(); i++)
{
Student& s = m_vStud.at(i);
if(s.m_strNO == strNO)
{
bFind = true;
break;
}
}
Student *s = NULL;
if(bFind)
s = &m_vStud.at(i);
return s;
}
};
void main() //仿真测试程序
{
Student s1("1001","zhangsan","boy","1985-10-10");
Student s2("1002","lisi","boy","1984-6-10");
Student s3("1003","wangwu","boy","1985-11-15");
StudCollect s;
s.Add(s1),s.Add(s2),s.Add(s3);
Student *ps = s.Find("1002");
if(ps)
ps->Display();
}