STL之Vector
1.简介
STL 是一套标准模板库。
从广义上来说,容器算法迭代器、仿函数、适配器、空间适配器
容器和算法之间通过迭代器进行无缝连接
STL几乎所有的代码都采用了模板类或者模板函数。
Vector使用上几乎等价于Java中list集合,但是二者在内部实现是完全不一样的。后面会分析。
2.Vector存放内置数据
迭代器:vector::iterator ;从某种意义上来说,迭代器就是指针
- push_back( ) 成员函数在向量的末尾插入值,如果有必要会扩展向量的大小。
- size( ) 函数显示向量的大小。
- begin( ) 函数返回一个指向向量开头的迭代器。
- end( ) 函数返回一个指向向量末尾的迭代器。
1.三种遍历方式
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
cout << val;
}
void test()
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
//第一种取数据
vector<int>::iterator isBegin = vec.begin(); //迭代器第一个
vector<int>::iterator isEnd = vec.end(); //指向容器中下一个位置
while (isBegin != isEnd)
{
cout << *isBegin;
isBegin++;
}
cout << endl;
//第二种方式
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
//第三种方式
for_each(vec.begin(), vec.end(), myPrint);
cout << endl;
}
int main(int argc, char const *argv[])
{
test();
system("pause");
return 0;
}
2.存放自定义数据类型
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name, int age);
~Person();
};
Person::Person(string name, int age)
{
cout << "Person创建了"<< endl;
this->name = name;
this->age = age;
}
Person::~Person()
{
cout << "Person析构了" << endl;
}
// void test()
// {
// vector<Person> vec;
// vec.push_back(Person("a", 10)); //Person("a", 10)为匿名对象,存入到vector中
// vec.push_back(Person("B", 20));
// vec.push_back(Person("C", 30));
// vec.push_back(Person("D", 40));
// for (vector<Person>::iterator it = vec.begin(); it != vec.end(); it++)
// {
// cout << it->name << it->age << endl;
// }
// }
int main(int argc, char const *argv[])
{
// test();
vector<Person> vec;
vec.push_back(Person("a", 10)); //Person("a", 10)为匿名对象,存入到vector中,匿名对象会发生析构
vec.push_back(Person("B", 20));
vec.push_back(Person("C", 30));
vec.push_back(Person("D", 40));
// Person p1("a", 10);
// Person p2("b", 20);
// Person p3("c", 30);
// Person p4("d", 40);
// vec.push_back(p1); //
// vec.push_back(p2);
// vec.push_back(p3);
// vec.push_back(p4);
for (vector<Person>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << it->name << it->age << endl;
}
// cout << p1.name << endl;
system("pause");
return 0;
}
Person创建了
Person析构了
Person创建了
Person析构了
Person析构了
Person创建了
Person析构了
Person析构了
Person析构了
Person创建了
Person析构了
a10
B20
C30
D40
请按任意键继续. . .
第二种:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name, int age);
~Person();
};
Person::Person(string name, int age)
{
cout << "Person创建了"<< endl;
this->name = name;
this->age = age;
}
Person::~Person()
{
cout << "Person析构了" << endl;
}
// void test()
// {
// vector<Person> vec;
// vec.push_back(Person("a", 10)); //Person("a", 10)为匿名对象,存入到vector中
// vec.push_back(Person("B", 20));
// vec.push_back(Person("C", 30));
// vec.push_back(Person("D", 40));
// for (vector<Person>::iterator it = vec.begin(); it != vec.end(); it++)
// {
// cout << it->name << it->age << endl;
// }
// }
int main(int argc, char const *argv[])
{
// test();
vector<Person> vec;
// vec.push_back(Person("a", 10)); //Person("a", 10)为匿名对象,存入到vector中,匿名对象会发生析构
// vec.push_back(Person("B", 20));
// vec.push_back(Person("C", 30));
// vec.push_back(Person("D", 40));
Person p1("a", 10);
Person p2("b", 20);
Person p3("c", 30);
Person p4("d", 40);
vec.push_back(p1); //
vec.push_back(p2);
vec.push_back(p3);
vec.push_back(p4);
for (vector<Person>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << it->name << it->age << endl;
}
vec.clear();
// cout << p1.name << endl;
system("pause");
return 0;
}
Person创建了
Person创建了
Person创建了
Person创建了
Person析构了
Person析构了
Person析构了
a10
b20
c30
d40
Person析构了
Person析构了
Person析构了
Person析构了
请按任意键继续. . .
vector存1放数据:会动态调整内存空间,所得到的存储空间总是大于等于所需存储空间。
3.vector 的初始化
(1) vector<int> a(10); //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
(2)vector<int> a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
(3)vector<int> a(b); //用b向量来创建a向量,整体复制性赋值
(4)vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
(5)int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+7); //从数组中获得初值
(6) vector<int>(vec); //匿名对象,匿名对象会被直接回收掉
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> a(10); //10个0
printVec(a);
vector<int> b(10, 1);
printVec(b);
vector<int> c(b);
printVec(c);
vector<int> d(b.begin(), b.end());
printVec(d);
int e[7] = {1, 2, 3, 4, 5, 9, 8};
vector<int> f(e, e + 7);
printVec(f);
vector<int> vec; //具有自动扩容的功能
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
system("pause");
return 0;
}
4.vector赋值操作
vector& operator=(const vector &vec);
//重载等号操作符assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。assign(n, elem);
//将n个elem拷贝赋值给本身。
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> v1; //无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVec(v1);
vector<int> v2;
v2 = v1;//赋值操作,将v1的所有元素全拷贝给v2
printVec(v2);
vector<int>v3;
v3.assign(v1.begin(), v1.end());//将[beg, end)区间中的数据拷贝赋值给本身。
printVec(v3);
vector<int>v4;
v4.assign(10, 100); //10个100
printVec(v4);
system("pause");
return 0;
}
6.vector基本操作符
1.判空 vec.empty();
vector<int> vec;
if (vec.empty())
{
cout << "vec为空" << endl;
}
else
{
cout << "vec不为空" << endl;
}
2.大小 vec.size()
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
cout << vec.size() << endl;
3.插入数据 insert
-
1.a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5
-
2.a.insert(a.begin()+1,3,5);//在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
vec.insert(vec.begin() + 1, 2);//第二位插入2
printVec(vec);
vec.insert(vec.begin() + 1, 3, 5); //从第二位插入3个555
printVec(vec);
system("pause");
return 0;
}
4.删除元素 vec.erase
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);//0 1 2 3 4
}
vec.erase(vec.begin() + 1, vec.begin() + 3);//删除a中第2个,到第三个,不包含第三个
printVec(vec);
system("pause");
return 0;
}
5.调整空间resize
- 1.a.resize(10)将a的现有元素个数调至10个,多则删,少则补0
- 2.a.resize(10,2);将a的现有元素个数调至10个,多则删,少则补2
注意:resize并不能缩减a.capacity();vector实际占用的内存大小。
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i); //0 1 2 3 4
}
vec.resize(2); //少则删除
printVec(vec);
vec.resize(10); //多则补0
printVec(vec);
vector<int> vec2;
for (int i = 0; i < 5; i++)
{
vec2.push_back(i); //0 1 2 3 4
}
vec2.resize(20, 2);//多则补2
printVec(vec2);
system("pause");
return 0;
}
6.容量的实际大小capacity
- size:表示地是vector元素的个数
- capacity:vector实际内存可以容纳元素的个数,capacity>=size;
为什么capacity很多时候会比实际的size大,这样做优点?
答:与java中list集合一样,避免多次扩容,影响到性能,扩容是很耗性能的。
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 10000; i++)
{
vec.push_back(i);
}
cout << "size" << vec.size() << "capacity:" << vec.capacity() << endl;
system("pause");
return 0;
}
size10000capacity:16384
请按任意键继续. . .
7.清空元素clear
vec.clear();
8.swap操作
- a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
1.交换数据
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i); //0 1 2 3 4
}
vector<int> vec2;
vec2.push_back(9);
vec2.swap(vec);
printVec(vec);
printVec(vec2);
system("pause");
return 0;
}
vec指针指向vec2,vec2指针指向vec。 进行了交换,但是还有功能,可以进行vector实际内存大小缩水操作。
2.实际大小capicity缩水
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 10000; i++)
{
vec.push_back(i);
}
vec.resize(10);
cout << vec.capacity() << endl; //16348,实际vec的内存容纳个数
vector<int>(vec).swap(vec);
cout << vec.capacity() << endl; //10,收缩空间
system("pause");
return 0;
}
——————vector(vec).swap(vec);怎么做到的, 首先:vector(vec)会产生匿名对象,开辟内存空间(只有实际个数大小的空间),vec原来的指向这个空间,匿名的指向原来大的内存空间,这样现在vec就只会有实际个数大小的内存空间。至于匿名的,会被编译器自动回收掉
9.相等比较
a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
vector<int> vec2(vec);
if (vec == vec2)
{
cout << "相等" << endl;
}
system("pause");
return 0;
}
10.其他操作
- 1.a.back();返回最后一个元素
- 2.a.front();返回第一个元素
- 3.a[i]/a.at(i); //返回a的第i个元素
- 4.pop_back;///删除a向量的最后一个元素
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for(int i =0; i< vec.size();i++)
{
cout << vec.at(i) << endl;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
vector<int> vec2(vec);
if (vec == vec2)
{
cout << "相等" << endl;
}
printVec(vec2);
system("pause");
return 0;
}
7.重要的算法algorithm
1.排序
sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
vec.push_back(2);
vec.push_back(3);
vec.push_back(1);
vec.push_back(4);
vec.push_back(5);
sort(vec.begin(), vec.end());
printVec(vec);
system("pause");
return 0;
}
2.元素反转排序
reverse(a.begin(),a.end()); //反转排序
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
reverse(vec.begin(), vec.end());
printVec(vec);
system("pause");
return 0;
}
3.copy复制
copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
vector<int> vec2;
vec2.push_back(6);
vec2.push_back(7);
vec2.push_back(8);
copy(vec.begin(), vec.end(), vec2.begin()+1);//vec2没有扩容,这个个人觉得尽量少使用
printVec(vec2);
system("pause");
return 0;
}
结果:612 ,vec2没有扩容,这个个人觉得尽量少使用, vec没有完全复制
4.查找
find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 5; i++)
{
vec.push_back(i);
}
if (find(vec.begin(), vec.end(), 4) != vec.end())
{
int position = find(vec.begin(), vec.end(), 4) - vec.begin();
cout << position << endl;
}
system("pause");
return 0;
}
8.vector手动释放内存探讨
- 1.直接声明的vector容器是一个普通变量,相当于一个未知大小的动态数组,不需要手动释放,超出作用于范围时会自动回收
- 2.如果是*vec = new vector<>( )这种方法动态创建的vector,则需要delete vector;
第一种,普通变量,数据量超大时,我们执行clear
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> &vec)
{
for (auto it = vec.begin(); it != vec.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 10000; i++)
{
vec.push_back(i);
}
cout << "size" << vec.size() << "capacity:" << vec.capacity() << endl;
vec.clear();
cout << vec.capacity() << endl;//实际内存空间大小并没有归0
system("pause");
return 0;
}
size10000capacity:16384
16384
请按任意键继续. . .
可以发现: vec.clear();执行clear之后,并没有立即就释放内存空间,这么大的一块内存空间,还是被占用了,极其不好,所以还是需要回收的。
1.方式1
vec.shrink_to_fit();//释放内存,缩水到实际数量大小
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 10000; i++)
{
vec.push_back(i);
}
cout << "size" << vec.size() << "capacity:" << vec.capacity() << endl;
vec.clear();//仅仅clear还不够
vec.shrink_to_fit();//释放内存
cout << vec.capacity() << endl;//实际内存空间大小并没有归0
system("pause");
return 0;
}
size10000capacity:16384
0
请按任意键继续. . .
2.方式2 swap
匿名的vector
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
vector<int> vec;
for (int i = 0; i < 10000; i++)
{
vec.push_back(i);
}
vector<int>().swap(vec);
cout << vec.capacity() << endl;
system("pause");
return 0;
}
9.vector存储指针
vector存放指针,则需要手动去释放内存,因为,vector释放内存时,vector内部元素指针指向的对象并不会销毁,堆中数据需要手动释放内存。
#include <iostream>
#include <vector>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name, int age);
~Person();
};
Person::Person(string name, int age)
{
cout << "Person创建了" << endl;
this->name = name;
this->age = age;
}
Person::~Person()
{
cout << "Person析构了" << endl;
}
void printerVec(vector<Person *> &vec)
{
for (vector<Person *>::iterator it = vec.begin(); it < vec.end(); it++)
{
cout << (*it)->name << (*it)->age << endl;
}
}
void releasePointer(vector<Person *> &vec)
{
for (vector<Person *>::iterator it = vec.begin(); it < vec.end(); it++)
{
if ((*it) != nullptr)
{
delete (*it);
(*it) = nullptr;
}
}
}
int main(int argc, char const *argv[])
{
vector<Person *> vec;
Person *p1 = new Person("zhangsan", 10);
Person *p2 = new Person("lisi", 20);
Person *p3 = new Person("wangwu", 30);
vec.push_back(p1);
vec.push_back(p2);
vec.push_back(p3);
printerVec(vec);
//清空并释放空间
releasePointer(vec);
vec.clear();
vec.shrink_to_fit();
cout << vec.capacity() << endl;
system("pause");
return 0;
}
10.手写一个Vector
#include <iostream>
#include <cmath>
using namespace std;
class OutOfException : public exception
{
};
class Array
{
public:
int size;
int maxsize; //capicity,动态扩容
public:
int *arr;
public:
Array(int maxSize);
~Array();
int &operator[](int i) const; //取数据
void push_back(int value);
void remove(int location);
};
Array::Array(int maxSize)
{
this->size = 0;
this->maxsize = maxSize;
arr = new int[maxSize];
}
Array::~Array()
{
if (this->arr != nullptr)
{
delete[] arr;
arr = nullptr;
}
}
int &Array::operator[](int i) const
{
if (i > size - 1)
{
return this->arr[0]; // 抛出异常
}
else
{
return this->arr[i];
}
}
void Array::push_back(int value)
{
if (size >= maxsize)
{
//扩容
int newMaxSize = ceil(maxsize + maxsize / 2);
int *newArr = new int[newMaxSize];
for (size_t i = 0; i < size; i++)
{
newArr[i] = arr[i]; //拷贝数据
}
delete[] arr;
arr = nullptr;
arr = newArr; //地址重新指向newArr
maxsize = newMaxSize;
}
arr[size++] = value;
}
void Array::remove(int location)
{
if (location > size - 1)
{
//抛出异常
}
else
{
for (size_t i = location; i < size - 1; i++)
{
arr[i] = arr[i + 1];
// arr[i] = arr[i++];
// *(arr + i) = *(arr +(++i));
}
size--;
}
}
void printArray(Array &arr, int size)
{
for (size_t i = 0; i < size; i++)
{
cout << arr[i] << endl;
}
}
int main(int argc, char const *argv[])
{
Array arr(2);
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
arr.push_back(6);
printArray(arr, arr.size);
arr.remove(2);
printArray(arr, arr.size);
cout << "获取值" << arr[0] << endl;
system("pause");
return 0;
}
{
newArr[i] = arr[i]; //拷贝数据
}
delete[] arr;
arr = nullptr;
arr = newArr; //地址重新指向newArr
maxsize = newMaxSize;
}
arr[size++] = value;
}
void Array::remove(int location)
{
if (location > size - 1)
{
//抛出异常
}
else
{
for (size_t i = location; i < size - 1; i++)
{
arr[i] = arr[i + 1];
// arr[i] = arr[i++];
// *(arr + i) = *(arr +(++i));
}
size–;
}
}
void printArray(Array &arr, int size)
{
for (size_t i = 0; i < size; i++)
{
cout << arr[i] << endl;
}
}
int main(int argc, char const *argv[])
{
Array arr(2);
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
arr.push_back(6);
printArray(arr, arr.size);
arr.remove(2);
printArray(arr, arr.size);
cout << "获取值" << arr[0] << endl;
system("pause");
return 0;
}