1、vector VS array
-
vector被称为单端动态数组。
-
vector的数据安排及操作方式与array非常相似,唯一差别在于空间运用的灵活性。
-
array是静态空间,一旦配置就不能改变,要更换空间必须手动配置一块新的空间,再将旧的数据搬到新空间,再释放原空间。
-
vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间来容纳新元素。
-
vector的实现技术,关键在于对大小的控制及重新配置时数据移动效率。“配置新空间-移动数据-释放旧空间”时间成本很高,因此容器每次扩充并不是一个一个的扩充。
2、vector迭代器
- vector维护一个线性空间,不论元素类型如何,普通指针都可以作为vector的迭代器,因为迭代器所需要的行为如operator->,operator++,operator–,operator+,operator-,operator+=,operator-=普通指针天生具有。
- vector支持随机存取,而普通指针正有这样的能力。
- vector提供的是随机访问迭代器(Random Access Iterator)。
随机访问迭代器:迭代器+n可以通过编译就是随机访问迭代器。
3、vector空间容量
vector容量capacity和大小size的区别(capacity≥size):
capacity:空间能容纳元素最大个数。
size:空间中实际存放元素个数。
void test2()
{
vector<int> v;
for (int i = 0; i < 100; i++)
v.push_back(i);
cout << "capacity=" << v.capacity() << endl;
cout << "size=" << v.size() << endl;
}
4、vector空间扩充
vector采用的数据结构非常简单,线性连续空间,它以两个迭代器Myfirst和Mylast指向配置得来的连续空间中已被使用的范围,以迭代器Myend指向整块连续内存空间的尾端。
为了降低空间配置时的速度成本,vector实际配置的大小可能比客户需求大一些,已备将来可能的扩充。即一个vector的容量永远大于或等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就会另寻空间。
所谓动态增加大小,并不是在原空间之后连续接新空间(因为无法保证原空间之后尚有可配置的空间,而判断当前开辟空间的后面空间是否已被占用是很耗时间的),因此每次都开辟一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。
因此对于vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。
void test3()
{
vector<int> v;
int* p = NULL;
int count = 0;
for (int i = 0; i < 20; i++)
{
v.push_back(i);
if (p != &v[0])//当p与v的首地址不同时,就表明新开辟了一次空间
{
count++;
p = &v[0];//原地址失效,这里获取新的起始地址
}
cout << "count=" << count <<" capacity="<<v.capacity()<<" size="<<v.size()<< endl;
}
cout << "新开辟了" << count << "次空间" << endl;
}
5、vector函数接口
/************************构造函数*******************************/
vector<T> v;//采用模板类实现,默认构造函数
vector(v.begin(),v.end());//将v[begin(),end())区间中的元素拷贝给本身
vector(n,elem);//将n个elem拷贝给本身
vector(const vector& vec);//拷贝构造函数
/************************赋值操作*******************************/
assign(beg,end);//将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);//将n个elem拷贝赋值给本身
vector& operator=(const vector& vec);//重载等号操作符
swap(vec);//将vec与本身元素交换
/************************大小操作*******************************/
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器长度为num,若变长则新位置填默认值,若变短,则末尾
//超出容器长度的元素被删除
//resize作用于容器的大小size,不会更改容器的容量capacity。
capacity();//容器的容量
reserve(int len);//容器预留len个元素的长度,预留位置若不初始化,元素不可访问
/************************数据存取*******************************/
at(int idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
operator[];//返回idx所指的数据,越界时,运行直接报错
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素
/***********************插入和删除操作****************************/
insert(const_iterator pos,int count,elem);//在迭代器指向位置pos插入count个元素elem
push_back(elem);//尾部插入元素elem
pop_back();//删除最后一个元素
erase(const_iterator start,const_iterator end);//删除迭代器从start到end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素
构造函数:
#include<iostream>
#include<vector>
using namespace std;
void printIntVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test()
{
//vector(n, elem);//将n个elem拷贝给本身
vector<int> v1(10, 5);
printIntVector(v1);
//vector(v.begin(),v.end());//将v[begin(),end())区间中的元素拷贝给本身
vector<int> v2(v1.begin() + 2, v1.end() - 2);
printIntVector(v2);
//vector(const vector& vec);//拷贝构造函数
vector<int> v3(v2);
printIntVector(v3);
//将区间中的元素拷贝给本身
int arr[] = { 1,2,3,4 };
vector<int> v4(arr, arr + sizeof(arr) / sizeof(int));
printIntVector(v4);
}
void main()
{
test();
}
resize和swap联合修改容器容量:
首先用resize()将容器v的大小size变为10,接着在用容器v给匿名容器vector()初始化时调用复制构造函数,匿名容器的容量capacity会等于容器v的size为10,最后通过swap()函数将容器v与匿名容器交换,此时容器v的size为10,capacity为10 ,匿名容器的size为10,capacity为1024.交换完成后匿名容器会立即自动析构,内存空间得到释放。
void test2()
{
vector<int> v;
for (int i = 0; i < 100; i++)
{
v.push_back(i);
}
cout << "size=" << v.size() << endl;
cout << "capacity=" << v.capacity() << endl;
v.resize(10);//只能修改size,不能修改capacity
cout << "size=" << v.size() << endl;
cout << "capacity=" << v.capacity() << endl;
//收缩容器容量
vector<int>().swap(v);//使用匿名对象
cout << "size=" << v.size() << endl;
cout << "capacity=" << v.capacity() << endl;
}
reserve:
预留空间用于提前已知需要向容器中存入多少数据的情况。如下例所示,没有reserve(),输出count为11,有reserve(),输出count为1。(另寻空间,将原空间值复制到新空间,释放原空间,三个步骤都会消耗时间)
void test3()
{
vector<int> v;
int* p = NULL;
int count = 0;
v.reserve(1000);
for (int i = 0; i < 1000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
count++;
}
}
cout << "count=" << count << endl;
}
erase与clear删除元素:
void test4()
{
vector<int>v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
printIntVector(v);
v.insert(v.begin() + 2, 3, 100);//从第三个位置往后插入3个100
printIntVector(v);
v.pop_back();//删除尾部元素
printIntVector(v);
v.erase(v.begin() + 2, v.end() - 1);//删除容器中第三个及以后的元素
printIntVector(v);
v.erase(v.begin() + 1);//删除容器中第二个元素
printIntVector(v);
cout << "size=" << v.size() << " capacity=" << v.capacity() << endl;
v.clear();//删除容器中所有元素
printIntVector(v);
cout << "size=" << v.size() << " capacity=" << v.capacity() << endl;
}
6、vector容器存放自定义对象
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class Person {
private:
int age;
string name;
public:
Person() { age = 0; name = ""; cout << "Person无参构造函数!" << endl; }
Person(int a, string n)
{
age = a;
name = n;
cout << "Person有参构造函数!" << endl;
}
Person(const Person& p) { age = p.age; name = p.name; cout << "拷贝构造!" << endl; }
void showPerson() { cout << "age=" << age << " name=" << name << endl; }
~Person()
{
cout << "析构函数!" << endl;
}
};
void myPrint(Person& ob)
{
ob.showPerson();
}
void test()
{
Person ob1(18, "小明");
Person ob2(20, "小芳");
Person ob3(19, "小李");
Person ob4(21, "小张");
cout << "-------------------------------------------" << endl;
vector<Person> v;
//v.push_back(18, "小明");//error
v.push_back(ob1);
cout << "-------------------------------------------" << endl;
v.push_back(ob2);
cout << "-------------------------------------------" << endl;
v.push_back(ob3);
cout << "-------------------------------------------" << endl;
v.push_back(ob4);
cout << "-------------------------------------------" << endl;
for_each(v.begin(), v.end(), myPrint);
cout << "-------------------------------------------" << endl;
}
void main()
{
test();
}