- vector是表示可变大小数组的序列容器。
- 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自 动处理。
- 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小 为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
- vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
- 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增 长。
- 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和 forward_lists统一的迭代器和引用更好。
注意:string与vector类似,但也有不同之处。string是存放字符的动态数组,vector是存放一个T类型的动态数组,本质都是一个顺序表。并且我们使用vector时需要加头文件#include
- void test_vector1()
- {
- vector<int> v1;
- vector<int> v2(10, 8);//开十个空间都赋值8
- vector<int> v3(++v2.begin(), --v2.end());//用自身的迭代器区间构造
- vector<int> v4(v3);//拷贝构造
-
- string s("hello world");
- vector<char> v5(s.begin(), s.end());//用string的迭代器区间构造
- }
- vector<int> v;
- v.push_back(1);
- v.push_back(2);
- v.push_back(3);
- v.push_back(4);
-
- v.pop_back();
- v.pop_back();
- v.pop_back();
- v.pop_back();
由于头删和头插效率太低了,vector并没有提供相应的接口。
vector可支持[]下标访问,并且可以改变vector中的值,至于遍历,我们可以用下标遍历,也可以使用范围for来遍历。
- //遍历
- for (size_t i = 0; i < v.size(); i++)
- {
- v[i] += 1;//可修改
- cout << v[i] << " ";
- }
- cout << endl;
-
- //
- vector<int>::iterator it = v.begin();
- //迭代器 it指向vector的第一个数据
- while (it != v.end())
- {
- *it -= 1;
- cout << *it << " ";
- it++;
- }
- cout << endl;
- //范围for 本质也是迭代器
- for (auto e : v)
- //把v中的每个数据遍历的时候给给e
- {
- cout << e << " ";
- }
- cout << endl;
-
- //int a[] = { 1,2,3 };
- 原生指针就是天然的迭代器,数组支持范围for,会被替换指针
- //for (int* p = a; p < a + sizeof(a) / sizeof(int); p++)
- //{}
- v.reserve(100); //扩容并只改变capacity空间
- v.resize(100); //扩容不仅改变capacity空间并且改变size
- v.resize(100, 5); //扩容+初始化 或 删除数据(类比string)
- v.resize(2); //截取数据但不改变capacity
- vector<int>::iterator ret = find(v.begin(), v.end(), 3);
- //auto ret = find(v.begin(), v.end(), 3);
- //如果没找到find返回第二个参数
- //如果找到了返回该数下标
- vector<int> v;
- v.push_back(1);
- v.push_back(2);
- v.push_back(3);
- v.push_back(4);
-
- v.assign(10, 5);//给v的前十个值上全部赋值为5,并且会覆盖原来的值
-
- cout <<"max_size:"<< v.max_size() << endl;//数据所能存放的最大容量
- cout <<"capacity:"<< v.capacity() << endl;//当前容量
- cout <<"size:"<< v.size() << endl;//当前数据个数
-
- v.clear();//只清理size的值不改变capacity
- cout << "-------------------";
- cout << "max_size:" << v.max_size() << endl;
- cout << "capacity:" << v.capacity() << endl;
- cout << "size:" << v.size() << endl;
- vector<int> v;
- v.push_back(1);
- v.push_back(2);
- v.push_back(3);
- v.push_back(4);
-
- //v.assign(10, 5);
- //覆盖之前已有的值
-
- vector<int>::iterator ret = find(v.begin(), v.end(), 3);
- //auto ret = find(v.begin(), v.end(), 3);
- //如果没找到find返回第二个参数
- if (ret != v.end())
- {
- cout << "找到了" << endl;
- v.insert(ret, 30);
- //v.erase(ret);
- //不能在这删,因为ret失效了
- //这个迭代器失效问题,我们后面会细讲
- }
- v.insert(v.begin(), 30);//在v.begin()的前面插入30也就是头插
- vector<int>::iterator pos = find(v.begin(), v.end(), 300);
- if (pos != v.end())
- //找不到的时候就会返回v.end
- //因此找不到的时候不会进入
- {
- v.erase(pos);//删除pos下标的值
-
- }
- int main()
- {
- size_t sz;
- std::vector<int> foo;
- sz = foo.capacity();
- std::cout << "making foo trow;\n";
- for (int i = 0; i < 100; i++)
- {
- foo.push_back(i);
- if (sz != foo.capacity())
- {
- sz = foo.capacity();
- std::cout << "capacity changed:" << sz << '\n';
- }
- }
- }
由上图可知vs下vector是以大约1.5增容的。而Linux下g++是以2倍增容的。
- class Solution {
- public:
- int singleNumber(vector<int>& nums)
- {
- int value=0;
- for(auto e : nums)
- {
- value^=e;//将nums中的值全部互相异或,这样的话相同的数据刚好抵消
- }
- return value;//返回剩下的那个与其他值不相等的数据
-
- }
- };
- 杨辉三角形
- class Solution {
- public:
- vector
int>> generate(int numRows) - {
- vector
int>> vv; - vv.resize(numRows);//先给外层vector开内存
- for (size_t i = 0; i < numRows; i++)
- {
- vv[i].resize(i + 1);//给每一个小vector开内存
- vv[i][0] = vv[i][vv[i].size() - 1] = 1;//小vector中的头尾设为1
- }
- for (size_t i = 0; i < vv.size(); i++)
- {
- for (size_t j = 0; j < vv[i].size(); j++)
- {
- if (vv[i][j] == 0)
- {
- vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
- }
- }
- }
- return vv;
- }
- };
- //回溯力扣题:《电话号码的字母组合》
- class Solution {
- string arr[10] = { "","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz" };
- //将0-9(其中0和1不给值)中的每个数字映射一个字符串
- public:
- //最关键的一个函数体,会反复使用
- void _letterCombinations(const string& digits, size_t i,
- string combinStr, vector
& strV) - //传入digits的引用并且加const为了防止改变digits并且减少拷贝,digits就是我们传入的字符串
- //传入i为了遍历digits中的每个字符串,因为digits字符串的每个字符还代表这一个字符串:例如2->"abc"
- //combinStr是为了去存放每次递归后的字符串组合
- //strV为了存放所有情况遍历完全之后的字符串总和
- {
- if (i == digits.size())
- //由于i是从0开始的,倘若此时i已经与digits的长度相等那么说明i已经越界了也代表digits的字符串已经遍历完全了
- {
- strV.push_back(combinStr);
- //将我们组合好的combinStr尾插到strV中,strV也就是最终我们需要返回的那个字符串
- return;//立即返回,只要执行该语句,该函数将不再执行接下来的语句,因为此时就需要返回
- }
- string str = arr[digits[i] - '0'];
- //定义一个新的字符串str并且让str中存入我们需要遍历的字符串
- //digits[i]是访问到我们输入字符串中的某个字符
- //digits-'0'为了得到arr的下标 使其得到digits字符串中每个字符中的字符串
- //最后让它赋值给str我们就可以遍历str将其进行组合
- for (size_t j = 0; j < str.size(); j++)//遍历str进行组合,并且继续递归调用_letterCombination函数
- {
- _letterCombinations(digits, i + 1, combinStr + str[j], strV);
- //传入digits 为了继续访问它的字符中的字符串
- //传入i+1 为了访问digits中的下一个字符中的字符串 并且这样的话i不会发生改变 以便下次可以直接继续使用i+1
- //传入 combinStr+str[j] 为了将我们得到的str中的字符尾插到combinStr中存放起来,等遍历结束可以尾插到strV中
- //传入 strV 如果遍历结束可直接把combinStr中的值直接传入strV中
- }
- }
- vector
letterCombinations(string digits) - //digits是我们所选择的字符串
- {
- string combinStr;//定义一个combinStr字符串
- vector
strV;//定义一个vector容器里面的值是string值 - if (digits.empty())//为了考虑我们的digits为空的情况下
- return strV;//若为空 直接返回
-
- //开始递归调用此函数
- _letterCombinations(digits, 0, combinStr, strV);
-
- return strV;//递归调用完成后返回
- }
- };
图解:
- private:
- iterator _start; // 指向数据块的开始
- iterator _finish; // 指向有效数据的尾
- iterator _endofStorage; // 指向存储容量的尾
默认构造
- vector()
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {}
迭代器构造
- //一个类模板的成员函数,又可以是一个函数模板
- template<class InputIterator>
- vector(InputIterator first, InputIterator last)
- :_start(nullptr)
- ,_finish(nullptr)
- ,_endofstorage(nullptr)
- {
- while (first != last)
- {
- push_back(*first);
- first++;
- }
- }
拷贝构造
- //v2(v1)
- //现代写法
- vector(const vector
& v) - {
- vector
tmp(v.begin(),v.end()) ; -
- //没有模拟swap之前可用下列写法
- /*swap(_start, tmp._start);
- swap(_finish, tmp._finish);
- swap(_endofstorage, tmp._endofstorage);*/
-
- //this->swap(tmp);
- swap(tmp);
- }
- v2(v1)传统写法
- //vector(const vector
& v) - // //拷贝构造(深拷贝)
- //{
- // _start = new T[v.capacity()];
- // _finish = _start + v.size();
- // _endofstorage = _start + v.capacity();
-
- // memcpy是浅拷贝
- // memcpy(_start, v._start, v.size() * sizeof(T));
- //}
这里传统写法不是很推荐,因为会用到memcpy,因为memcpy会用到浅拷贝。
- ~vector()
- {
- if (_start)
- {
- delete[] _start;
- _start = _finish = _endofstorage = nullptr;
- }
- }
- //v1=v2
- //现代写法
- vector
& operator=(vector v) - {
-
- //未模拟swap时用下列方法
- /*swap(_start, v._start);
- swap(_finish, v._finish);
- swap(_endofstorage, v._endofstorage);*/
-
-
- swap(v);
-
- return *this;
- }
- public:
- typedef T* iterator;
- typedef const T* const_iterator;
-
- const_iterator begin() const
- {
- return _start;
- }
- const_iterator end() const
- {
- return _finish;
- }
- iterator begin()
- {
- return _start;
- }
- iterator end()
- {
- return _finish;
- }
-
- size_t size() const
- {
- return _finish - _start;
- }
- size_t capacity() const
- {
- return _endofstorage - _start;
- }
- void reserve(size_t n)
- {
- if (n > capacity())
- {
- //扩容
- size_t sz = size();
- T* tmp = new T[n];
- if (_start)
- {
- //memcpy是浅拷贝
- //memcpy(tmp, _start, sizeof(T) * size());
- for (size_t i = 0; i < sz; i++)
- {
- //T 是int,一个一个拷贝没问题
- //T 是string,一个一个拷贝调用是T的深拷贝复制,也没问题
- tmp[i] = _start[i];
- }
- delete[] _start;
- }
- _start = tmp;
- _finish = _start + sz;
- /*_finish = tmp + size();
- _start = tmp;*/
- _endofstorage = _start + n;
-
- }
- }
-
- void resize(size_t n, const T& val = T())
- {
- if (n < size())
- {
- _finish = _start + n;
- }
- else
- {
- if (n > capacity())
- {
- reserve(n);
- }
- while (_finish != _start + n)
- {
- *_finish = val;
- _finish++;
- }
- }
- }
- bool empty()const
- {
- return _start == _finish;
- }
- void push_back(const T& x)
- {
- if (_finish == _endofstorage)
- {
- 扩容
- //size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
- size_t sz = size();
- //T* tmp = new T[newCapacity];
- //if (_start)
- //{
- // memcpy(tmp, _start, sizeof(T) * size());
- // delete[] _start;
- //}
- _start = tmp;
- _finish = _start + sz;
- //_finish = tmp + size();
- //_start = tmp;
- //_endofstorage = _start + newCapacity;
-
- reserve(capacity() == 0 ? 4 : capacity() * 2);
- }
- *_finish = x;
- _finish++;
- }
- void pop_back()
- {
- assert(_finish > _start);//检查是否为空
-
- _finish--;
- }
- iterator insert(iterator pos, const T& x)
- {
- assert(pos >= _start);
- assert(pos <= _finish);
- //满了就扩容
- if (_finish == _endofstorage)
- {
- //扩容
- //扩容会导致pos失效,扩容需要更新一下pos
- size_t len = pos - _start;//计算一下扩容前pos与_start直接的距离以便以计算新pos
- reserve(capacity() == 0 ? 4 : capacity() * 2);
- pos = _start + len;//得到新pos的位置
- }
-
- //移动数据
- iterator end = _finish - 1;
- while (end >= pos)
- {
- *(end + 1) = *end;
- end--;
- }
- *pos = x;
- _finish++;
-
- return 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;
- }
- void swap(vector
& v) - {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_endofstorage, v._endofstorage);
- }
- T& operator[](size_t i)
- {
- assert(i < size());
- return _start[i];
- }
- #pragma once
-
- namespace mwb
- {
- template<class T>
- class vector
- {
- public:
- typedef T* iterator;
- typedef const T* const_iterator;
-
- vector()
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {}
-
- // v2(v1)传统写法
- //vector(const vector
& v) - // //拷贝构造(深拷贝)
- //{
- // _start = new T[v.capacity()];
- // _finish = _start + v.size();
- // _endofstorage = _start + v.capacity();
-
- // memcpy是浅拷贝
- // memcpy(_start, v._start, v.size() * sizeof(T));
- //}
-
- //一个类模板的成员函数,又可以是一个函数模板
- template<class InputIterator>
- vector(InputIterator first, InputIterator last)
- :_start(nullptr)
- ,_finish(nullptr)
- ,_endofstorage(nullptr)
- {
- while (first != last)
- {
- push_back(*first);
- first++;
- }
- }
- void swap(vector
& v) - {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_endofstorage, v._endofstorage);
- }
- //v2(v1)
- //现代写法
- vector(const vector
& v) - {
- vector
tmp(v.begin(),v.end()) ; - /*swap(_start, tmp._start);
- swap(_finish, tmp._finish);
- swap(_endofstorage, tmp._endofstorage);*/
- //this->swap(tmp);
- swap(tmp);
- }
- //v1=v2
- //现代写法
- vector
& operator=(vector v) - {
- /*swap(_start, v._start);
- swap(_finish, v._finish);
- swap(_endofstorage, v._endofstorage);*/
- swap(v);
-
- return *this;
- }
- ~vector()
- {
- if (_start)
- {
- delete[] _start;
- _start = _finish = _endofstorage = nullptr;
- }
- }
- const_iterator begin() const
- {
- return _start;
- }
- const_iterator end() const
- {
- return _finish;
- }
- iterator begin()
- {
- return _start;
- }
- iterator end()
- {
- return _finish;
- }
- T& operator[](size_t i)
- {
- assert(i < size());
- return _start[i];
- }
- size_t size() const
- {
- return _finish - _start;
- }
- size_t capacity() const
- {
- return _endofstorage - _start;
- }
-
- void reserve(size_t n)
- {
- if (n > capacity())
- {
- //扩容
- size_t sz = size();
- T* tmp = new T[n];
- if (_start)
- {
- //memcpy是浅拷贝
- //memcpy(tmp, _start, sizeof(T) * size());
- for (size_t i = 0; i < sz; i++)
- {
- //T 是int,一个一个拷贝没问题
- //T 是string,一个一个拷贝调用是T的深拷贝复制,也没问题
- tmp[i] = _start[i];
- }
- delete[] _start;
- }
- _start = tmp;
- _finish = _start + sz;
- /*_finish = tmp + size();
- _start = tmp;*/
- _endofstorage = _start + n;
-
- }
- }
- void resize(size_t n, const T& val = T())
- {
- if (n < size())
- {
- _finish = _start + n;
- }
- else
- {
- if (n > capacity())
- {
- reserve(n);
- }
- while (_finish != _start + n)
- {
- *_finish = val;
- _finish++;
- }
- }
- }
- iterator insert(iterator pos, const T& x)
- {
- assert(pos >= _start);
- assert(pos <= _finish);
- //满了就扩容
- if (_finish == _endofstorage)
- {
- //扩容
- //扩容会导致pos失效,扩容需要更新一下pos
- size_t len = pos - _start;//计算一下扩容前pos与_start直接的距离以便以计算新pos
- reserve(capacity() == 0 ? 4 : capacity() * 2);
- pos = _start + len;//得到新pos的位置
- }
-
- //移动数据
- iterator end = _finish - 1;
- while (end >= pos)
- {
- *(end + 1) = *end;
- end--;
- }
- *pos = x;
- _finish++;
-
- return 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;
- }
- void push_back(const T& x)
- {
- if (_finish == _endofstorage)
- {
- 扩容
- //size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
- size_t sz = size();
- //T* tmp = new T[newCapacity];
- //if (_start)
- //{
- // memcpy(tmp, _start, sizeof(T) * size());
- // delete[] _start;
- //}
- _start = tmp;
- _finish = _start + sz;
- //_finish = tmp + size();
- //_start = tmp;
- //_endofstorage = _start + newCapacity;
-
- reserve(capacity() == 0 ? 4 : capacity() * 2);
- }
- *_finish = x;
- _finish++;
- }
- void pop_back()
- {
- assert(_finish > _start);//检查是否为空
-
- _finish--;
- }
- private:
- iterator _start;
- iterator _finish;
- iterator _endofstorage;
- };
- }