vector基本概念
功能:
vector数据结构和数组非常相似,也称为单端数组。
vector和普通数组的区别:
不同之处在于数组是静态空间,而vector可以动态扩展。
动态扩展:
并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。
vector容器的迭代器是支持随机访问的迭代器。
容量和大小:
capacity(); //容器的容量
size(); //返回容器中元素的个数
vector构造函数
功能描述:创建vector容器
函数原型:
vector<T> v; // 采用模板列来实现,默认的构造函数
vector<T> v(v1.begin(), v1.end());// 将v1[begin(), end())区间中所有的元素拷贝给当前的vector
vector<T> v(n, elem); // 将n个elem元素拷贝给vector容器
vector<T> v(const vector &vec); // 拷贝构造函数,用一个容器对象初始化另外一个容器对象
#include <iostream>
#include <vector> // 使用vector容器时,要引入<vector>。
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
// 创建一个vector容器
vector<int> v1; // 无参构造,构建一个vector容器
for (int i = 0; i < 10; i++)
{
v1.push_back(i + 1);
}
printVector(v1);
将v1[begin(),end())区间的所有元素拷贝给当前的容器
//vector<int> v3(v1.begin(), v1.end());
//printVector(v3);
拷贝构造
//vector<int> v2(v1);
//printVector(v2);
用5个100对vector容器进行初始化
//vector<int> v4(5, 100);
//printVector(v4);
}
vector的赋值操作
功能描述:给vector容器进行赋值
函数原型:
vector &operator=(const vector &vec); //重载赋值操作符
assign函数:
assign(beg,end); // 将参数vector[beg, end)区间中的数据拷贝给当前vector,beg和end是两个位置的指针
assign(n,ele); // 将n个ele拷贝给容器本身
void test02()
{
vector<int> v1; // 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i + 1);
}
printVector(v1);
// 通过赋值运算符来进行容器赋值操作
vector<int> v2;
v2 = v1;
printVector(v2);
// assign函数实现
vector<int> v3;
// begin()是最开始元素的位置,end是最后一个元素的后一个位置,所以begin()+2是指向了第三个元素,end()-2是指向了倒数第二个元素
v3.assign(v1.begin() + 2, v1.end() - 2);
printVector(v3);
// 将5个200拷贝给容器
vector<int> v4;
v4.assign(5, 200);
printVector(v4);
}
vector的容量和大小
功能描述:对vector容器的容量和大小操作
函数原型:
empty(); //判断容器是否为空
capacity(); // 容器的容量,容量相当于装苹果的筐子大小
size(); // 返回容器中的元素个数,size大小相当于苹果筐中的苹果个数
resize(int num); // 重新指定容器长度为num,如果容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除
void test03()
{
vector<int> v1; // 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i + 1);
}
printVector(v1);
if (v1.empty())
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量:" << v1.capacity() << endl;
cout << "v1的大小:" << v1.size() << endl;
}
// resize来重新指定容器大小
v1.resize(5);
printVector(v1);
v1.resize(10);
printVector(v1);
v1.resize(15, 100);
printVector(v1);
}
总结:
判断是否为空 --- empty
返回元素个数 --- size
返回容器容量 --- capacity
重新指定大小 --- resize
vector插入和删除
功能描述:对vector容器进行插入、删除操作
函数原型:
尾部操作:
push_back(ele); // 尾部插入元素ele
pop_back(); // 删除最后一个元素
插入insert:
insert(const_iterator pos, ele); // 迭代器指向位置pos插入元素ele,并返回表示新插入元素位置的迭代器
insert(const_iterator pos, int count,ele); // 迭代器指向位置pos插入n个元素ele,并返回表示插新插入的第一个元素位置的迭代器
删除erase:
erase(const_iterator pos); // 删除迭代器所指向的元素,返回被删除元素的下一个元素的迭代器位置
erase(const_iterator start, const_iterator end); // 删除start到end之间的元素,不包括end
clear(); // 删除容器中的所有元素
void test04()
{
// 尾部插入
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
printVector(v1);
// 尾部删除
v1.pop_back();
printVector(v1);
v1.pop_back();
printVector(v1);
// 从任意位置来插入
v1.insert(v1.begin(), 100);
printVector(v1);
v1.insert(v1.begin(), 2, 300);
printVector(v1);
// 删除
v1.erase(v1.begin());
printVector(v1);
v1.erase(v1.begin(), v1.begin() + 2);
printVector(v1);
// 清空元素
//v1.erase(v1.begin(), v1.end());
//v1.clear();
//printVector(v1);
// 插入insert函数会返回插入新元素的位置,用迭代器来进行接收
vector<int>::iterator it = v1.insert(v1.begin() + 1, 500);
printVector(v1);
cout << *it << endl;
}
总结:
尾插 --- push_back
尾删 --- pop_back
插入 --- insert (位置迭代器)
删除 --- erase (位置迭代器)
清空 --- clear
关于迭代器失效
概念:
vector属于序列式容器,底层是数组,是连续的物理内存空间存储结构,如果发生了插入或者删除的时候,会出现迭代器失效的问题,当失效的情况发生,如果继续操作迭代器,需要先将迭代器进行更新之后才能使用,否则会报错。
出现失效的情况:
insert:
当容量还足够的时候,插入的元素能放下, 不需要重新申请更大的内存空间,插入操作会导致插入位置之后的所有元素位置发生变化,从而导致迭代器失效;
当容量不够的时候,插入元素放不下,需要申请更大的空间来存储元素,会导致整个vector的迭代器失效。
push_back():
当push_back一个元素的时候,end迭代器失效,如果发生了空间扩展,那么全部迭代器失效。
erase:
删除操作不会导致容量不够的问题,但是会导致被删除的当前位置迭代器失效,以及后面所有的迭代器失效,因为删除当前元素之后,后面的元素要前移。
pop_back():
pop_back只会导致end迭代器失效,但是不会影响前面的迭代器,因为其他元素在前面,不需要移动。
// 迭代器失效
void test05()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(30);
v.push_back(40);
v.push_back(50);
printVector(v);
删除等于30的元素
//for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
//{
// if (*it == 30)
// {
// v.erase(it); // 这里的删除会导致迭代器发生改变,如果不做调整,会导致出现报错,显示信息无效
// }
//}
//printVector(v);
改进方式:erase方法本身就会返回下一个迭代器的位置,所以it = v.earse(it);
//for (vector<int>::iterator it = v.begin(); it != v.end();)
//{
// if (*it == 30)
// {
// it = v.erase(it); // erase会返回下一个元素的迭代器,就相当于it++操作,如果下一个元素也是30下次循环仍然会删除掉
// }
// else // 不是30的时候才会手动进行it++的操作
// {
// it++;
// }
//}
//printVector(v);
通过while循环来做
//vector<int>::iterator it = v.begin();
//while (it != v.end())
//{
// while (*it == 30)
// {
// it = v.erase(it);
// }
// it++;
//}
//printVector(v);
insert出现迭代器失效的问题
//for (vector<int>::iterator it = v.begin(); it !=v. end(); it++)
//{
// if (*it == 30)
// {
// it = v.insert(it, 100);//这里的输入操作会导致迭代器失效,需要更新it
// it++; // 这里需要迭代器加1操作,因为上面的insert返回插入的值的迭代器,相当于it-1,指向了100,如果不加1,下次循环体会自动加一次,又指向了30,就变成了一个死循环
// }
//}
//printVector(v);
for (vector<int>::iterator it = v.begin(); it != v.end();)
{
if (*it == 30)
{
it = v.insert(it, 100);//这里的输入操作会导致迭代器失效,需要更新it
it++; // 这里需要迭代器加1操作,因为上面的insert返回插入的值的迭代器,相当于it-1,指向了100,如果不加1,下次循环体会自动加一次,又指向了30,就变成了一个死循环
it++;
}
else
{
it++;
}
}
printVector(v);
}
vector数据存取
功能描述:对vector中的数据的存取操作;
函数原型:
at(int idx); // 返回索引idx所指向的数据
operator[]; // 重载[] , 返回下标所指向的数据
front(); // 返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
cout << "第一个元素的值是:" << v1.front() << endl;
cout << "最后一个元素的值是:" << v1.back() << endl;
}
总结:
除了用迭代器获取vector容器中元素,[ ]和at也可以
front返回容器第一个元素
back返回容器最后一个元素
vector互换容器
功能描述:实现两个容器内元素进行互换
函数原型:
swap(vec); // 将vec与本身的元素互换
利用swap可以实现容器的缩容操作
void test02()
{
vector<int> v1;
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
cout << "v1:";
printVector(v1);
vector<int> v2;
for (int i = 11; i <= 20; i++)
{
v2.push_back(i);
}
cout << "v2:";
printVector(v2);
//互换swap()
v1.swap(v2);
cout << "互换后:" << endl;
cout << "v1:";
printVector(v1);
cout << "v2:";
printVector(v2);
}
void test03()
{
vector<int> v;
for (int i = 0; i < 10000; i++)
{
v.push_back(i);
}
cout << "v的容量是:" << v.capacity() << endl;
cout << "v的大小是:" << v.size() << endl;
v.resize(5);
cout << "v被重新定义了大小之后结果是:" << v.size() << endl;
cout << "v的容量不会被影响:" << v.capacity() << endl;
// 使用swap来实现缩容的操作
vector<int> v1(v);
//v.swap(v1); // 让v和v1进行交换,可以实现缩容
//cout << v.size() << " " << v.capacity() << endl;
//C++11 提供了一个专门的缩容函数
v.shrink_to_fit();
cout << v.size() << " " << v.capacity() << endl;
}
总结:
swap可以使两个容器互换,可以达到实用的收缩内存效果
vector预留空间
功能描述:减少vector在动态扩展容量时的扩展次数,因为数据量如果比较大,那么在运行时时候vector会多次进行内存的开辟,比较消耗资源和时间,所以最好的办法就是开始的时候就直接给vector容器来预留足够的内存,直接给capacity来进行赋值。
函数原型:
reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。
// vector预留空间
void test04()
{
vector<int> v;
// 预留9个位置,如果添加元素到第十个的时候就需要进行扩容了
v.reserve(9);
for (int i = 1; i < 11; i++)
{
v.push_back(i);
cout << &v[0] << endl; // 每次都打印同一个值的地址,到第十个的时候地址发生了变化
}
}
总结:
如果数据量较大,可以一开始利用reserve预留空间
常用算法函数
使用算法的时候需要引入头文件<algorithm>
注意点:算法是引入类库之后可以直接使用,不是vector的成员函数
排序(sort)
sort(iterator beg, iterator end); // 对beg和end区间内的所有的元素进行排序,默认是从小到大
sort(iterator beg, iterator end, func); // 按照func函数对beg和end区间内的所有的元素进行排序
反转(reverse)
reverse(iterator beg, iterator end); // 对beg和end区间内的所有的元素进行反转。
复制(copy)
copy(源起始位置,源的结束位置(不包括这个位置), 目标的起始位置) // 代表选取一段内容赋值到目标的起始位置
查找(find)
find(iterator beg, iterator end,ele); // 在beg和end区间内查找ele元素,如果能找到直接返回对应的迭代器的位置,如果没有找到,返回end迭代器;
注意end指的是区间中指定的end位置,不一定是整个容器的最后的end()
遍历(for each)
for_each(beg, end, func) // 遍历容器,beg和end是容器的迭代器,func是函数或者仿函数,指明跌倒时对元素的操作。
// 排序函数
bool cap(int a, int b)
{
return a > b;
}
// 用于for_each遍历算法的操作函数
void myPrint(int val)
{
val++;
cout << val << " ";
}
// vector算法的使用
void test05()
{
int arr[] = { 39,40,55,11,23,14,51,20,99,5 };
vector<int> v;
v.assign(arr, arr + 10);
printVector(v);
// 从小到大来进行排序
sort(v.begin(), v.end());
cout << "升序排序后:";
printVector(v);
// 从大到小
// 需要手写一个函数来进行排序操作,这个函数就叫做排序函数
sort(v.begin(), v.end(), cap);
cout << "降序排序后:";
printVector(v);
cout << "利用for_each来实现遍历值,并且给每一个值进行+1" << endl;
for_each(v.begin(), v.end(), myPrint);
// 复制
vector<int> v2;
v2.assign(10, 100);
copy(v.begin(), v.begin() + 5, v2.begin());
cout << "将v的前5个值赋复制到v2的前5个位置" << endl;
printVector(v2);
// 反转
//reverse(v2.begin(), v2.end());
reverse(v2.begin(), v2.begin()+5);
cout << "将v2进行反转之后的结果是:" << endl;
printVector(v2);
// 查找
vector<int>::iterator it = find(v2.begin(), v2.begin() + 5, 55);
if (it == (v2.begin()+5))
{
cout << "没找到" << endl;
}
else
{
cout << "找到了,它的下标是:" << it-v2.begin() << endl;
}
}
总结:
vector是单口容器,所以在尾部进行插入和删除元素的时候效率比较高,访问元素的效率也比较高效,但是在指定位置插入的时候,一定会引起其他元素的移动,所以效率低。
vector的练习
// vector的遍历方法
void test06()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
// 使用for循环加迭代器的方式
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
}
// 在vector中存放自定义数据类型
class Person
{
public:
string m_Name;
int m_Age;
Person(string name, int age) :m_Name(name), m_Age(age) {}
};
void test07()
{
vector<Person> v;
Person p1("lucy", 10);
Person p2("Tom", 20);
Person p3("lihua", 30);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "Name:" << (*it).m_Name << "\t" << "Age:" << it->m_Age << endl;
}
}
// 容器中嵌套容器
void test08()
{
//创建一个外层容器
vector<vector<int>> v;
// 内部容器
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
// 给内部容器进行赋值
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
}
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
// 遍历双层容器
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
}
// 练习
// 1、给定一个整数类型的vector数组nums,返回每一个数字的平方组成的新动态数组,并且进行升序排列,定义函数来实现
// 例
// nums = [3,6,1,10,9];
// 结果为newNums = [1,9,36,81,100]
vector<int> numPower(vector<int>& v)
{
vector<int> res;
for (int i = 0; i < v.size(); i++)
{
res.push_back(v[i] * v[i]);
}
sort(res.begin(), res.end());
return res;
}
// 2、给定一个动态数组nums,编写一个函数将所有的0移动到数组的末尾,其他的元素保持原来的相对顺序,直接在原数组上进行操作即可
// nums = [0, 1, 0 ,3 ,12]
// 输出:[1, 3, 12, 0, 0]
void moveZero(vector<int>& v)
{
// 定义计数器,计算删除了几个0
int num = 0;
for (vector<int>::iterator it = v.begin(); it != v.end();)
{
// 删除0的时候需要处理迭代失效的问题
if (*it == 0)
{
it = v.erase(it);
// 每次删除一次0,需要对计数器进行自加操作
num++;
}
else
{
it++;
}
}
// 所有的0删除完毕后,在容器的最后进行补0操作
for (int i = 0; i < num; i++)
{
v.push_back(0);
}
printVector(v);
}
int main()
{
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(0);
v.push_back(3);
v.push_back(12);
moveZero(v);
/* vector<int> v;
v.push_back(3);
v.push_back(6);
v.push_back(1);
v.push_back(10);
v.push_back(9);
vector<int> newNumber = numPower(v);
for (int i = 0; i < newNumber.size(); i++)
{
cout << newNumber[i] << " ";
}*/
return 0;
}