一、vector类的介绍和使用
1,了解vector
vector类的官方介绍https://cplusplus.com/reference/vector/vector/
使用STL的三个境界:能用,明理,能扩展
1). vector是表示可变大小数组的序列容器。
2). 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3.) 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
4. )vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5. )因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6. )与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。
2,vector的使用
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;namespace std
{void test1(){//初始化vector<int> v1;vector<int> v2(10, 1);vector<int> v3(v2);//尾插v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);// 下标+[]遍历for (size_t i = 0; i < v1.size(); ++i){v1[i]++;}for (size_t i = 0; i < v1.size(); ++i){cout << v1[i] << " ";}cout << endl;//迭代器遍历vector<int>::iterator it = v1.begin();while (it != v1.end()){//可以修改数据(*it)--;cout << *it << " ";++it;}cout << endl;//范围for遍历for (auto e : v1){cout << e << " ";}cout << endl;}void test2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);cout << v1.max_size() << endl;}void test3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);//find算法,引用头文件 <algorithm>vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);if (pos != v1.end()){//插入v1.insert(pos, 88);}for (auto e : v1){cout << e << " ";}cout << endl;pos = find(v1.begin(), v1.end(), 1);if (pos != v1.end()){//删除v1.erase(pos);}for (auto e : v1){cout << e << " ";}cout << endl;}void test4() {vector<int> v1;v1.push_back(8);v1.push_back(7);v1.push_back(2);v1.push_back(5);v1.push_back(9);v1.push_back(3);v1.push_back(4);v1.push_back(1);v1.push_back(6);for (auto e : v1){cout << e << " ";}cout << endl;//快排sort(v1.begin(), v1.end());for (auto e : v1){cout << e << " ";}cout << endl;//less<int> ls;//greater<int> gt;逆置函数//sort(v1.begin(), v1.end(), gt);//直接传名命对象,可以少写两行sort(v1.begin(), v1.end(), greater<int> ());for (auto e : v1){cout << e << " ";}cout << endl;string s("hello26138912634");sort(s.begin(), s.end(), greater<char>());cout << s << endl;//136 }}int main()
{//std::test1();//std::test2();//std::test3();std::test4();return 0;
}
二、vector类的模拟实现
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace std;//csy名命空间
namespace csy
{//vector模板类,类型为T,可替换template<class T>class vector{public://iterator重定义成T*,可以简化一下,//在reserve里的tmp使用//在Func里的const_iterator使用typedef T* iterator;iterator begin(){return _start;}iterator end(){return _finish;}const iterator begin() const{return _start;}const iterator end() const{return _finish;}vector():_start(nullptr), _finish(nullptr), _end_of_storag(nullptr){}//拷贝构造传统写法//vector(const vector<T>& v)// :_start(nullptr)// , _finish(nullptr)// , _end_of_storag(nullptr)//{// //开空间// reserve(v.size());// //拷贝数据// for (auto e : v)// {// push_back(e);// }//}//同值构造vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < i; ++i){push_back(val);}}//拷贝构造的现代写法,区间构造,swap写入template <class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storag(nullptr){while (first != last){push_back(*first);++first;}}void swap(vector<T>& v){std::swap(_start,v._start);std::swap(_finish,v._finish);std::swap(_end_of_storag,v._end_of_storag);}vector(const vector<T>& v){//开空间vector<T> tmp(v.begin(),v.end());//拷贝数据swap(tmp);}~vector(){delete[] _start;_start = _finish = _end_of_storag = nullptr;}//提供capacity和size和reserve和v[i]size_t capacity() const{return _end_of_storag - _start;}size_t size() const{return _finish - _start;}void reserve(size_t n){if (n > capacity()){//开辟n大小的空间T* tmp = new T[n];//拷贝if (_start){memcpy(tmp, _start, sizeof(T)*size());delete[] _start;}//替换size(),避免_start改变导致size()改变size_t sz = size();//类成员变量赋值更新_start = tmp;_finish = _start + sz;_end_of_storag = _start + n;}}T& operator [](size_t pos){assert(pos < size());return _start[pos];}const T& operator [](size_t pos) const{assert(pos < size());return _start[pos];}//假设原始size为8个元素,12345678,size要重置成长度n//1,如果n > 15 需要扩容 + 初始化//2,如果n > 8 && n <= 15 初始化//3,如果n < 8 删除数据void resize(size_t n, const T& val = T()){if (n > capacity()){reserve(n);}if (n > size()){//初始化填值while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}//加const避免引用临时变量void push_back(const T& x){if (_finish == _end_of_storag){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}void pop_back(){assert(_finish > _start);--_finish;}//v.insert(v.begin(), 1);//pos不要传引用,不能修改引用值iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);//扩容if (_finish == _end_of_storag){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}//挪动后半段数据//扩容后,pos还指向旧空间,pos变成野指针,也叫做迭代器的失效//所以扩容后要重置positerator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}//插入*pos = x;++_finish;return pos;}//结论:insert/erase pos位置,不要直接访问pos//一定要更新,直接访问,可能各种出乎意料的结果//认为pos失效,不要访问iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);//挪动后面的往前一个位置覆盖iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;}T& front(){assert(size() > 0);return *_start;}T& back(){assert(size() > 0);return *(_finish - 1);}private:iterator _start;iterator _finish;iterator _end_of_storag;};void Func(const vector<int>& v){//注意使用const迭代器vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;}void test_vector1(){double d = 2.2;//int& i = d;const int& i = d;vector<string> v;v.push_back("xxxxx");for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl << endl;;}void test_vector2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl << endl;}void test_vector3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;v.pop_back();v.pop_back();for (auto e : v){cout << e << " ";}cout << endl;Func(v);}void test_vector4(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl << endl;auto p = find(v.begin(), v.end(), 3);if (p != v.end()){//p不要再次使用,可能失效了v.insert(p, 30);//cout << *p << endl;//v.insert(p, 40);}for (auto e : v){cout << e << " ";}cout << endl;}void test_vector5(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(4);v.push_back(3);v.push_back(4);v.push_back(5);//删除所有的偶数auto it = v.begin();while (it != v.end()){ //错误用法//if (*it % 2 == 0)//{// v.erase(it);//}//++it;//正确用法if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}void test_vector6(){std::vector<int> v;v.reserve(10);v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//在所有的偶数前面插入偶数的2倍auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.insert(it, *it * 2);++it;++it;}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}//浅拷贝,析构两次,指向同一空间,一个对象修改影响两个对象//深拷贝,开辟新空间,指向新空间void test_vector7() {//普通构造vector<int> v1;v1.push_back(1);for (auto e : v1){cout << e << " ";}//拷贝构造vector<int> v2(v1);for (auto e : v2){cout << e << " ";}cout << endl;//内置类型也有构造int i = 6;int j = int();int k = int(22);cout << i << " " << j << " " << k << endl;}void test_vector8(){vector<int> v1;v1.resize(10, 0);for (auto e : v1){cout << e << " ";}cout << endl << endl;vector<int> v2;v2.reserve(10);v2.push_back(1);v2.push_back(2);v2.push_back(3);v2.push_back(4);v2.push_back(5);v2.resize(8, 8);for (auto e : v2){cout << e << " ";}cout << endl << endl;v2.resize(20, 20);for (auto e : v2){cout << e << " ";}cout << endl << endl;}
}