0


进阶C++__STL__容器vector使用方法【简单易懂】

vector容器

vector构造函数

  • vector<T> v; //采用模板实现类实现,默认构造函数
  • vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。
  • vector(n, elem); //构造函数将n个elem拷贝给本身。
  • vector(const vector &vec); //拷贝构造函数。
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void printVector(vector<int>& v) {
  6. for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
  7. cout << *it << " ";
  8. }
  9. cout << endl;
  10. }
  11. void test01()
  12. {
  13. vector<int> v1; //无参构造 默认构造
  14. for (int i = 0; i < 10; i++)
  15. {
  16. v1.push_back(i);
  17. }
  18. printVector(v1);
  19. //通过区间方式构造
  20. vector<int> v2(v1.begin(), v1.end());
  21. printVector(v2);
  22. // n个元素e方式构造
  23. vector<int> v3(10, 0);
  24. printVector(v3);
  25. //拷贝构造
  26. vector<int> v4(v3);
  27. printVector(v4);
  28. }
  29. int main() {
  30. test01();
  31. system("pause");
  32. return 0;
  33. }

输出:

0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

vector赋值操作

  • vector& operator=(const vector &vec);//重载等号操作符
  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
  • assign(n, elem); //将n个elem拷贝赋值给本身。
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void printVector(vector<int>& v) {
  6. for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
  7. cout << *it << " ";
  8. }
  9. cout << endl;
  10. }
  11. //赋值操作
  12. void test01()
  13. {
  14. vector<int> v1; //无参构造
  15. for (int i = 0; i < 10; i++)
  16. {
  17. v1.push_back(i);
  18. }
  19. printVector(v1);
  20. vector<int>v2;
  21. v2 = v1;
  22. printVector(v2);
  23. vector<int>v3;
  24. v3.assign(v1.begin(), v1.end());
  25. printVector(v3);
  26. vector<int>v4;
  27. v4.assign(10, 100);
  28. printVector(v4);
  29. }
  30. int main() {
  31. test01();
  32. system("pause");
  33. return 0;
  34. }

输出:

0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
100 100 100 100 100 100 100 100 100 100

vector容量和大小

  • empty(); //判断容器是否为空
  • capacity(); //容器的容量
  • size(); //返回容器中元素的个数
  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。​ //如果容器变短,则末尾超出容器长度的元素被删除。
  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。​ //如果容器变短,则末尾超出容器长度的元素被删除
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void printVector(vector<int>& v) {
  6. for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
  7. cout << *it << " ";
  8. }
  9. cout << endl;
  10. }
  11. void test01()
  12. {
  13. vector<int> v1;
  14. for (int i = 0; i < 10; i++)
  15. {
  16. v1.push_back(i);
  17. }
  18. printVector(v1);
  19. if (v1.empty())
  20. {
  21. cout << "v1为空" << endl;
  22. }
  23. else
  24. {
  25. cout << "v1不为空" << endl;
  26. cout << "v1的容量 = " << v1.capacity() << endl;
  27. cout << "v1的大小 = " << v1.size() << endl;
  28. }
  29. //resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充
  30. v1.resize(15,10);
  31. printVector(v1);
  32. //resize 重新指定大小 ,若指定的更小,超出部分元素被删除
  33. v1.resize(5);
  34. printVector(v1);
  35. }
  36. int main() {
  37. test01();
  38. system("pause");
  39. return 0;
  40. }

vector插入和删除

  • push_back(ele); //尾部插入元素ele
  • pop_back(); //删除最后一个元素
  • insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele
  • insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele
  • erase(const_iterator pos); //删除迭代器指向的元素
  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
  • clear(); //删除容器中所有元素
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void printVector(vector<int>& v) {
  6. for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
  7. cout << *it << " ";
  8. }
  9. cout << endl;
  10. }
  11. //插入和删除
  12. void test01()
  13. {
  14. vector<int> v1;
  15. //尾插
  16. v1.push_back(10);
  17. v1.push_back(20);
  18. v1.push_back(30);
  19. v1.push_back(40);
  20. v1.push_back(50);
  21. printVector(v1);
  22. //尾删
  23. v1.pop_back();
  24. printVector(v1);
  25. //插入
  26. v1.insert(v1.begin(), 100);
  27. printVector(v1);
  28. v1.insert(v1.begin(), 2, 1000);
  29. printVector(v1);
  30. //删除
  31. v1.erase(v1.begin());
  32. printVector(v1);
  33. //清空
  34. v1.erase(v1.begin(), v1.end());
  35. v1.clear();
  36. printVector(v1);
  37. }
  38. int main() {
  39. test01();
  40. system("pause");
  41. return 0;
  42. }

输出:

10 20 30 40 50
10 20 30 40
100 10 20 30 40
1000 1000 100 10 20 30 40
1000 100 10 20 30 40

vector数据存取

  • at(int idx); //返回索引idx所指的数据
  • operator[]; //返回索引idx所指的数据
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最后一个数据元素
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void test01()
  6. {
  7. vector<int>v1;
  8. for (int i = 0; i < 10; i++)
  9. {
  10. v1.push_back(i);
  11. }
  12. for (int i = 0; i < v1.size(); i++)
  13. {
  14. cout << v1[i] << " ";
  15. }
  16. cout << endl;
  17. for (int i = 0; i < v1.size(); i++)
  18. {
  19. cout << v1.at(i) << " ";
  20. }
  21. cout << endl;
  22. cout << "v1的第一个元素为: " << v1.front() << endl;
  23. cout << "v1的最后一个元素为: " << v1.back() << endl;
  24. }
  25. int main() {
  26. test01();
  27. system("pause");
  28. return 0;
  29. }

输出:

0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
v1的第一个元素为: 0
v1的最后一个元素为: 9

vector互换容器

  • swap(vec); // 将vec与本身的元素互换
  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void printVector(vector<int>& v) {
  6. for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
  7. cout << *it << " ";
  8. }
  9. cout << endl;
  10. }
  11. void test01()
  12. {
  13. vector<int>v1;
  14. for (int i = 0; i < 10; i++)
  15. {
  16. v1.push_back(i);
  17. }
  18. printVector(v1);
  19. vector<int>v2;
  20. for (int i = 10; i > 0; i--)
  21. {
  22. v2.push_back(i);
  23. }
  24. printVector(v2);
  25. //互换容器
  26. cout << "互换后" << endl;
  27. v1.swap(v2);
  28. printVector(v1);
  29. printVector(v2);
  30. }
  31. void test02()
  32. {
  33. vector<int> v;
  34. for (int i = 0; i < 100000; i++) {
  35. v.push_back(i);
  36. }
  37. cout << "v的容量为:" << v.capacity() << endl;
  38. cout << "v的大小为:" << v.size() << endl;
  39. v.resize(3);
  40. cout << "v的容量为:" << v.capacity() << endl;
  41. cout << "v的大小为:" << v.size() << endl;
  42. //收缩内存
  43. vector<int>(v).swap(v); //匿名对象
  44. cout << "v的容量为:" << v.capacity() << endl;
  45. cout << "v的大小为:" << v.size() << endl;
  46. }
  47. int main() {
  48. test01();
  49. test02();
  50. system("pause");
  51. return 0;
  52. }

输出:

0 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1
互换后
10 9 8 7 6 5 4 3 2 1
0 1 2 3 4 5 6 7 8 9
v的容量为:131072
v的大小为:100000
v的容量为:131072
v的大小为:3
v的容量为:3
v的大小为:3

总结:swap可以使两个容器互换,可以达到实用的收缩内存效果

vector预留空间

  1. reserve(int len);

//容器预留len个元素长度,预留位置不初始化,元素不可访问。

vector开辟空间原理:

当空间不够时,会重新开辟一块更大的空间,将原来空间内容拷贝到这个更大的空间,并指向这块空间;

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. #include <vector>
  5. void test01()
  6. {
  7. vector<int> v;
  8. //预留空间
  9. //v.reserve(100000);
  10. int num = 0;
  11. int* p = NULL;
  12. for (int i = 0; i < 100000; i++) {
  13. v.push_back(i);
  14. if (p != &v[0]) {
  15. p = &v[0];
  16. num++;
  17. }
  18. }
  19. cout << "num:" << num << endl;
  20. }
  21. int main() {
  22. test01();
  23. system("pause");
  24. return 0;
  25. }

输出:(不同编译器结果不同)

num:18

利用开辟空间原理判断指向的地址是否改变,我们发现vector存100000个元素时要改变18次,即重新开辟并拷贝18次;这样非常耗费时间;

当我们使用reserve直接预留100000空间时,则只需要一次,非常节约时间

reserve()的实现

  1. /* reserve */
  2. void reserve(size_t new_capacity) {
  3. if (new_capacity > capacity()) { // 检查是否真的需要扩容
  4. if (_finish == _eos) {
  5. size_t sz = size(); // 提前把size算好
  6. T* tmp = new T[new_capacity];
  7. if (_start) {
  8. // memcpy(tmp, _start, sizeof(T) * size()); 有问题!
  9. //自己把原空间的数据拷贝到新空间
  10. for (size_t i = 0; i < sz; i++) {
  11. // 如果T是int,一个一个拷贝没问题
  12. // 如果T是string等自定义问题,一个一个拷贝调用的是T的深拷贝,也不会出问题。
  13. tmp[i] = _start[i];
  14. }
  15. delete[] _start; // 并释放原有的旧空间
  16. }
  17. _start = tmp; // 指向新空间
  18. _finish = tmp + sz; // 现场算size() 会有问题,因为start已经被更新成tmp了
  19. _eos = _start + new_capacity;
  20. }
  21. }
  22. }

vector的增删查改的模拟实现

函数接口:

  1. namespace bit
  2. {
  3. template<class T>
  4. class vector
  5. {
  6. public:
  7. // Vector的迭代器是一个原生指针
  8. typedef T* iterator
  9. typedef const T* const_iterator
  10. iterator begin();
  11. iterator end();
  12. const_iterator cbegin();
  13. const_iterator cend() const
  14. // construct and destroy
  15. vector();
  16. vector(int n, const T& value = T());
  17. template<class InputIterator>
  18. vector(InputIterator first, InputIterator last);
  19. vector(const vector<T>& v);
  20. vector<T>& operator= (vector<T> v);
  21. ~vector();
  22. // capacity
  23. size_t size() const
  24. size_t capacity() const
  25. void reserve(size_t n);
  26. void resize(size_t n, const T& value = T());
  27. ///access///
  28. T& operator[](size_t pos);
  29. const T& operator[](size_t pos)const
  30. ///modify/
  31. void push_back(const T& x);
  32. void pop_back();
  33. void swap(vector<T>& v);
  34. iterator insert(iterator pos, const T& x);
  35. iterator erase(Iterator pos);
  36. private:
  37. iterator _start; // 指向数据块的开始
  38. iterator _finish; // 指向有效数据的尾
  39. iterator _endOfStorage; // 指向存储容量的尾
  40. };
  41. }

模拟实现

  1. namespace bit
  2. {
  3. template<class T>
  4. class vector
  5. {
  6. public:
  7. // Vector的迭代器是一个原生指针
  8. typedef T* iterator
  9. typedef const T* const_iterator
  10. iterator begin()
  11. {
  12. return _start;
  13. }
  14. iterator end()
  15. {
  16. return _finish;
  17. }
  18. const_iterator cbegin()const
  19. {
  20. return _start;
  21. }
  22. const_iterator cend() const
  23. {
  24. return _finish;
  25. }
  26. // construct and destroy
  27. vector(): _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
  28. {}
  29. vector(int n, const T& value = T())
  30. : _start(nullptr), _finish(nullptr),_endOfStorage(nullptr)
  31. {
  32. reserve(n);
  33. while (n--)
  34. {
  35. push_back(value);
  36. }
  37. }
  38. template<class InputIterator>
  39. vector(InputIterator first, InputIterator last)
  40. {
  41. reserve(last - first);
  42. while (first != last)
  43. {
  44. push_back(*first);
  45. ++first;
  46. }
  47. }
  48. vector(const vector<T>& v)
  49. : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
  50. {
  51. reserve(v.capacity());
  52. iterator it = begin();
  53. const_iterator vit = v.cbegin();
  54. while (vit != v.cend())
  55. {
  56. *it++ = *vit++;
  57. }
  58. _finish = _start + v.size();
  59. _endOfStorage = _start + v.capacity();
  60. }
  61. vector<T>& operator= (vector<T> v)
  62. {
  63. swap(v);
  64. return *this;
  65. }
  66. ~vector()
  67. {
  68. delete[] _start;
  69. _start = _finish = _endOfStorage = nullptr;
  70. }
  71. // capacity
  72. size_t size() const
  73. {
  74. return _finish - _start;
  75. }
  76. size_t capacity() const
  77. {
  78. return _endOfStorage - _start;
  79. }
  80. void reserve(size_t n)
  81. {
  82. if (n > capacity())
  83. {
  84. size_t oldSize = size();
  85. T* tmp = new T[n];
  86. if (_start)
  87. {
  88. for (size_t i = 0; i < oldSize; ++i)
  89. tmp[i] = _start[i];
  90. }
  91. _start = tmp;
  92. _finish = _start + size;
  93. _endOfStorage = _start + n;
  94. }
  95. }
  96. void resize(size_t n, const T& value = T())
  97. {
  98. // 1.如果n小于当前的size,则数据个数缩小到n
  99. if (n <= size())
  100. {
  101. _finish = _start + n;
  102. return;
  103. }
  104. // 2.空间不够则增容
  105. if (n > capacity())
  106. reserve(n);
  107. // 3.将size扩大到n
  108. iterator it = _finish;
  109. iterator _finish = _start + n;
  110. while (it != _finish)
  111. {
  112. *it = value;
  113. ++it;
  114. }
  115. }
  116. ///access///
  117. T& operator[](size_t pos)
  118. {
  119. return _start[pos];
  120. }
  121. const T& operator[](size_t pos)const
  122. {
  123. return _start[pos];
  124. }
  125. ///modify/
  126. void push_back(const T& x)
  127. {
  128. insert(end(), x);
  129. }
  130. void pop_back()
  131. {
  132. erase(--end());
  133. }
  134. void swap(vector<T>& v)
  135. {
  136. swap(_start, v._start);
  137. swap(_finish, v._finish);
  138. swap(_endOfStorage, v._endOfStorage);
  139. }
  140. iterator insert(iterator pos, const T& x)
  141. {
  142. assert(pos <= _finish);
  143. // 空间不够先进行增容
  144. if (_finish == _endOfStorage)
  145. {
  146. size_t size = size();
  147. size_t newCapacity = (0 == capacity())? 1 : capacity() * 2;
  148. reserve(newCapacity);
  149. // 如果发生了增容,需要重置pos
  150. pos = _start + size;
  151. }
  152. iterator end = _finish - 1;
  153. while (end >= pos)
  154. {
  155. *(end + 1) = *end;
  156. --end;
  157. }
  158. *pos = x;
  159. ++_finish;
  160. return pos;
  161. }
  162. // 返回删除数据的下一个数据
  163. // 方便解决:一边遍历一边删除的迭代器失效问题
  164. iterator erase(Iterator pos)
  165. {
  166. // 挪动数据进行删除
  167. iterator begin = pos + 1;
  168. while (begin != _finish)
  169. {
  170. *(begin - 1) = *begin;
  171. ++begin;
  172. }
  173. --_finish;
  174. return pos;
  175. }
  176. private:
  177. iterator _start; // 指向数据块的开始
  178. iterator _finish; // 指向有效数据的尾
  179. iterator _endOfStorage; // 指向存储容量的尾
  180. };
  181. }

经典题目练习

1.杨辉三角OJ

模拟;练一练二维vector

  1. class Solution {
  2. public:
  3. vector<vector<int>> generate(int numRows) {
  4. vector<vector<int>> vv;
  5. vv.resize(numRows);
  6. for(size_t i=1;i<=numRows;i++)
  7. {
  8. vv[i-1].resize(i,0);
  9. vv[i-1][0]=1;
  10. vv[i-1][i-1]=1;
  11. }
  12. for(int i=0;i<vv.size();i++)
  13. {
  14. for(int j=0;j<vv[i].size();j++){
  15. if(vv[i][j]==0)
  16. {
  17. vv[i][j]=vv[i-1][j]+vv[i-1][j-1];
  18. }
  19. }
  20. }
  21. return vv;
  22. }
  23. };

2.删除排序数组中的重复项 OJ

快慢指针:

所谓快:不加条件判断的数组下标累计
所谓慢:加上条件判断的数组下标累计

  1. class Solution {
  2. public:
  3. int removeDuplicates(vector<int>& nums) {
  4. int n=nums.size();
  5. if(n==0){
  6. return 0;
  7. }
  8. int fast=1,slow=1;
  9. while(fast<n)
  10. {
  11. if(nums[fast]!=nums[fast-1]){
  12. nums[slow]=nums[fast];
  13. slow++;
  14. }
  15. fast++;
  16. }
  17. return slow;
  18. }
  19. };

3. 数组中出现次数超过一半的数字

**最优解:候选法 **

思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数(因为超过数组一半)。

  1. 假设cond为候选人,cnt为票数(要找到票最多的当选);
  2. 如果cnt为0,说明没有候选人或者该候选人票不够选不了;
  3. 否则,如果cnt > 0, 表示有候选人,如果当前数=cond,则++cnt,否则--cnt
  1. class Solution {
  2. public:
  3. int MoreThanHalfNum_Solution(vector<int> numbers) {
  4. int cond = 0;
  5. int cnt = 0;
  6. for (int i=0; i<numbers.size(); ++i)
  7. {
  8. if (cnt == 0)
  9. {
  10. cond = numbers[i];
  11. ++cnt;
  12. }
  13. else
  14. {
  15. if (cond == numbers[i]) ++cnt;
  16. else --cnt;
  17. }
  18. }
  19. return cond;
  20. }
  21. };

4.只出现一次的数字

不需要额外空间的方法,就往位运算上想

  1. 交换律:a ^ b ^ c <=> a ^ c ^ b
  2. 任何数于0异或为任何数 0 ^ n => n
  3. 相同的数异或为0: n ^ n => 0
  1. class Solution {
  2. public:
  3. int singleNumber(vector<int>& nums) {
  4. int ret=0;
  5. for(auto e:nums)
  6. ret^=e;
  7. return ret;
  8. }
  9. };

5.电话号码字母组合

思路:

由题意知就是把字母一一组合;

  1. 首先使用哈希表存储每个数字对应的所有可能的字母,然后进行回溯操作
  2. 假设输入“234”,进入递归,首先获得str第一个字符‘2’然后转成数字,取数字映射的字符串
  3. 开始遍历字符“abc”,刚取到‘a’时再进入递归取第二个字符‘3’,取数字映射的字符串“def”后开始遍历,以此类推我们的combineStr为“adg”
  4. 取到“adg”时就到顶了,利用di==digits.size()判断,将取到的组合数保存到retV并开始回溯;
  5. 由auto ch : str 我们会遍历“ghi”,按照上述同理方法得到“adh”,“adi”,然后回溯到第二次取‘e’,同理得“aeg”,“aeh”,“aei”
  6. 最终取到333种排列

回溯算法用于寻找所有的可行解,如果发现一个解不可行,则会舍弃不可行的解。在这道题中,由于每个数字对应的每个字母都可能进入字母组合,因此不存在不可行的解,直接穷举所有的解即可。

  1. class Solution {
  2. string nums[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
  3. public:
  4. void Combine(string digits,int di,string combineStr,vector<string>& retV)
  5. {
  6. if(di==digits.size())
  7. {
  8. retV.push_back(combineStr);
  9. return;
  10. }
  11. int num=digits[di]-'0';
  12. string str=nums[num];
  13. for(auto ch:str)
  14. {
  15. Combine(digits,di+1,combineStr+ch,retV);
  16. }
  17. }
  18. vector<string> letterCombinations(string digits) {
  19. vector<string> retV;
  20. if(digits.empty())
  21. return retV;
  22. int i=0;
  23. string str;
  24. Combine(digits,i,str,retV);
  25. return retV;
  26. }
  27. };

6. 连续子数组的最大和

经典动态规划

  • step 1:可以用dp数组表示以下标iii为终点的最大连续子数组和。
  • step 2:遍历数组,每次遇到一个新的数组元素,连续的子数组要么加上变得更大,要么这个元素本身就更大,要么会更小,更小我们就舍弃,因此状态转移为dp[i]=max(dp[i−1]+array[i],array[i])dp[i] = max(dp[i - 1] + array[i], array[i])dp[i]=max(dp[i−1]+array[i],array[i])。
  • step 3:因为连续数组可能会断掉,每一段只能得到该段最大值,因此我们需要维护一个最大值。
  1. class Solution {
  2. public:
  3. int FindGreatestSumOfSubArray(vector<int> array) {
  4. vector<int> dp(array.size(),0);
  5. dp[0]=array[0];
  6. int maxv=dp[0];
  7. for(int i=1;i<array.size();i++)
  8. {
  9. dp[i]=max(dp[i-1]+array[i],array[i]);
  10. maxv=max(maxv,dp[i]);
  11. }
  12. return maxv;
  13. }
  14. };
标签: c++ 算法 开发语言

本文转载自: https://blog.csdn.net/qq_61386381/article/details/125869840
版权归原作者 NO.-LL 所有, 如有侵权,请联系我们删除。

“进阶C++__STL__容器vector使用方法【简单易懂】”的评论:

还没有评论