C++学习笔记_15 线性容器-vector容器 2021-05-12

简介: C++学习笔记_15 线性容器-vector容器 2021-05-12

向量 vector

支持对元素的下标访问,在尾部添加和删除元素,效率高,  类似数组.

1. 
2. // C++学习笔记_15 线性容器-vector容器
3. 
4. #include<vector>
5. #include<iostream>
6. #include<string>
7. #include<algorithm>  //算法函数的头文件
8. 
9. using namespace std;
10. template <typename T>
11. void PrintVecInfo(const vector<T> &tVec)
12. {
13.     cout << "Empty   :" << tVec.empty() << endl; //判断容器是否为空
14.     cout << "Size    :" << tVec.size() << endl;  //容器中存的元素个数
15.     cout << "Capacity:" << tVec.capacity() << endl;//容器可以存储的元素个数(申请了多少内存)
16.     cout << "Max_size:" << tVec.max_size() << endl;//容器最大可以存储多少个元素
17. }
18. 
19. template<typename T>
20. void PrintVec(vector<T> &tVec)
21. {
22. typename vector<T>::iterator it;
23. for (it = tVec.begin(); it != tVec.end(); it++){cout << *it << " ";}
24.     cout << endl;
25. }
26. 
27. class AAA
28. {
29. private:
30. int x;int y;
31. public:
32. AAA(int a, int b) :x(a), y(b){}
33. 
34. friend ostream& operator << (ostream& os, const AAA &A)
35.     { os << "(" << A.x << ", " << A.y << ")";return os; }
36. };
37. 
38. void TestVector()
39. {
40.     vector<int> iVec1;  //定义vector 里面没数据
41. vector<int> iVec2(10); //定义 10 个长度的 vector, 默认值是 0
42. //vector<AAA> aVec --> 由默认构造函数生成的对象
43. vector<int> iVec3(10, 1); //定义10个长度的 vector 默认值是 1 (string(5,'A') = "AAAAA");
44. vector<int> iVec4(iVec3); //复制构造函数
45. vector<int> iVec5(iVec4.begin(), iVec4.begin() + 5);
46. // 使用迭代器区间进行构造
47. 
48. //迭代器区间 的迭代器类型可以是任何迭代器
49. int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
50. vector<int> iVec6(arr, arr + 9); //--> 这个也是迭代器区间构造
51. 
52. //直接赋值:可以理解为复制构造函数(这里 {} 不可以省略,表示{}内整体是一个变量)
53. //                               (这里 () 可以省略。vector<int> v{1,2,3})
54. vector<int>  iVec7({ 1, 3, 5, 7, 9, 2, 4, 6, 8 });
55. 
56.     cout << "iVec7 info:" << endl;
57. PrintVecInfo(iVec7);
58.     cout << endl;
59. 
60.     cout << "iVec7:";
61. PrintVec(iVec7);
62.     cout << endl;
63. //插入元素:
64. //1: 插入最后面       push_back(xxx)
65. //2:  指定位置插入元素  insert(it, xxx)
66. //3: 插入 N 个一样的元素,   insert(it, N, xxx)
67. //4: 插入一段迭代器区间的元素    insert(it, itBegin, itEnd)   
68.     iVec7.push_back(11);               //在尾部插入  11
69.     iVec7.insert(iVec7.begin()+1, 22); //在第二个位置插入 22
70.     iVec7.insert(iVec7.begin(), 3, 33); //在开始位置插入 3 个 33
71.     iVec7.insert(iVec7.begin(), iVec2.begin(), iVec2.begin() + 3); 
72. //开始位置插入 iVec2.begin 到 iVec2.begin() + 3 这段区间的元素
73.     cout << "iVec7:";
74. PrintVec(iVec7);
75.     cout << endl;
76. 
77. //删除元素:
78. //1: 删除尾部元素  pop_back()
79. //2:  删除指定位置元素 erase(it)
80. //3:  删除指定区间的元素  erase(itBegin, itEnd)
81. //4:  清空整个 vector     clear()
82.     iVec7.pop_back(); //删除尾部
83.     cout << "iVec7:";
84. PrintVec(iVec7);
85. 
86.     iVec7.erase(iVec7.begin() + 1); //删除第二个元素
87.     cout << "iVec7:";
88. PrintVec(iVec7);
89. 
90.     iVec7.erase(iVec7.begin(), iVec7.begin() + 6);//删除前面6个元素
91.     cout << "iVec7:";
92. PrintVec(iVec7);
93. 
94.     iVec7.clear();//删除所有元素
95.     cout << "iVec7 info: "<<endl;
96. PrintVecInfo(iVec7);
97.     cout << endl;
98. 
99. //访问第 i 个元素
100.     cout << "iVec6:";
101. PrintVec(iVec6);
102.     cout << "第三个元素:" << iVec6[2] << endl;
103.     cout << "第四个元素:" << iVec6.at(3) << endl;
104. //可以下标[] 或者 at 方式访问第 i 个元素。
105. //有一点点区别:下标访问不会判断是否越界 --》越界则程序出错
106. //              at()  方式访问,会做越界判断 --》越界抛出异常
107. 
108. //第一个元素和最后一个元素
109.     cout << "第一个元素:" << iVec6.front() << endl;
110.     cout << "第末个元素:" << iVec6.back() << endl;
111. 
112.     cout << endl;
113. //事实上  iVec6.begin() 这个迭代器,就指向了  front() 这个元素
114. //        iVec6.end()-1   这个迭代器,就指向了  back() 这个元素
115.     cout << "第一个元素:" << *(iVec6.begin()) << endl;
116.     cout << "第末个元素:" << *(iVec6.end()-1) << endl;
117. 
118. //反向迭代器  rbegin(), rend()
119. // rbegin() 指向最后一个元素, 直到 rend() 指向第一个元素前面
120. // 从 rbegin 到 rend 也是使用 ++ 操作
121.     cout << endl << "逆向迭代:" << endl;
122.     vector<int>::reverse_iterator rIt;
123. for (rIt = iVec6.rbegin(); rIt != iVec6.rend(); rIt++){cout << *rIt << " ";}
124.     cout << endl;
125.     cout << "第一个元素:" << *(iVec6.rend()-1) << endl;
126.     cout << "第末个元素:" << *(iVec6.rbegin()) << endl;
127. 
128. //其他函数
129.     iVec2.swap(iVec3); //成员函数。交换两个 vector --》交换的是 内存地址值
130. swap(iVec2, iVec3);//外部函数 std 里定义的 swap --》 交换的是元素值
131. //原则:容器内自己实现了的函数,不要调用外部实现(成员函数效率更高,处理的更好)
132. 
133. //重置容器中的数据:assign
134. //使用方式类似于构造函数
135.     cout << endl;
136.     iVec1.assign({1,3,5,7,9}); //指定一系列数据
137. PrintVec(iVec1);
138. 
139.     iVec1.assign(5, 7);       //指定连续 N 个数据 (5 个 7)
140. PrintVec(iVec1);
141. 
142.     iVec1.assign(iVec6.begin(), iVec6.end()); //指定一段区间
143. PrintVec(iVec1);
144.     cout << endl;
145. 
146. //resize(n)  -->把容器中元素扩充(或者减少)到 n 个
147. //      1:如果扩充,则在容器后面增加元素,值是默认构造函数生成的
148. //      2:如果减少,则删除掉末尾若干个元素
149.     iVec1.resize(12);
150. PrintVec(iVec1);
151. 
152.     iVec1.resize(5);
153. PrintVec(iVec1);
154. 
155. //内部存储 AAA 对象 
156.     vector<AAA>  aVec;//不可以使用 vector<AAA>  aVec(5)
157. //因为 AAA 没有默认构造函数,这里 5 个元素的值是默认构造函数生成的
158. //error C2512: “AAA”: 没有合适的默认构造函数可用
159. //没有默认构造函数,不能通过 AAA() 生成元素默认的值;
160. //aVec.resize(5);
161.     aVec.resize(5, AAA(1, 2));//扩充(或者减少)到5个元素,扩充的话,默认值是 AAA(1,2)
162. PrintVec(aVec);
163.     cout << endl;
164. 
165. //reserve(n)  预先给 vector 分配 n 个元素的空间  --》 改变的是 capacity 
166. //vector 的内存管理:vector 申请里一段大小的内存
167. //         在插入元素的过程中,如果,内存空间不够 
168. //            --》 重新申请一片更大的内存,把已有数据拷贝过去后,再插入元素
169. 
170. //     --》如果我们已经知道我们的vector需要存多少元素(比如10000个)
171. //     直接存的话,可能涉及到频繁申请释放空间,和元素拷贝
172. //     如果用 reserve 预先申请内存 --》 避免重复的申请释放内存和元素拷贝
173. 
174. PrintVecInfo(aVec);
175.     cout << endl;
176. 
177. //aVec.push_back(AAA(2,2));
178. //aVec.reserve(100);
179.     aVec.reserve(3); //原来元素个数是5,capacity是5,不能把 capacity变小
180. PrintVecInfo(aVec);
181.     cout << endl;
182. 
183. PrintVec(aVec);
184. 
185. //事实上 aVec 的 capacity 无论任何情况,都只会增加,不会减少,哪怕调用了 clear() 清空容器
186. 
187. }
188. 
189. //判断是否偶数
190. bool IsEven(int x)
191. {
192. return  x % 2 == 0; // 等价于: return !( x % 2);
193. // return !(x & 1);  
194. }
195. 
196. bool IsBigger2(int x)
197. {
198. return x > 2;
199. }
200. 
201. class IsMore
202. {
203. private:
204. int x;
205. public:
206. IsMore(int a) :x(a){}
207. 
208. //重载 括号运算符 (注意这里两对括号)
209. //--》IsMore 对象 XXX 调用  XXX(a) 就 返回了  a > x
210. bool operator () (int a){return a > x;}
211. };
212. 
213. void TestAlg()
214. {
215. //count   :   统计容器中元素的个数
216. //count_if:   统计容器中满足某个条件的元素个数
217.     vector<int>   iVec{ 1, 2, 3, 4, 5, 5, 3, 2, 2, 1 };
218. 
219. int cnt;
220. 
221.     cnt = count(iVec.begin(), iVec.end(), 2);
222.     cout << "统计 2 的个数:" << cnt << endl;
223. 
224. //入参是一个函数
225. //一定注意不带 (), 带括号表示调用这个函数,然后取函数的返回值
226. //不带括号才表示这是一个变量 (变量类型是: 函数指针)
227.     cnt = count_if(iVec.begin(), iVec.end(), IsEven); //入参是一个函数
228. //回调的概念:以函数指针作为函数 count_if 函数的入参
229. //       在 count_if 函数里面,调用函数 IsEven(xxx)
230. // 也就是说,count_if 函数,会对 [iVec.begin(), iVec.end()) 这个区间中的元素 *it
231. //    依次调用 IsEven(*it) 来判断这个值,是否满足条件 (满足则计数器++)
232.     cout << "统计偶数的个数:" << cnt << endl;
233. 
234. //统计iVec 中 大于 2 的元素个数:
235.     cnt = count_if(iVec.begin(), iVec.end(), IsBigger2);
236. 
237. //我们还想iVec中统计大于 3 的元素个数? 再写一个 IsBigger3 {return x>3}
238. //还想统计 大于 4 的元素个数? 大于 5 的元素个数 ?......
239. //不能随便给 IsBigger 加参数,因为 count_if 调用的方式只会传入1个入参
240. //--->  使用仿函数的方式来实现 
241. // --》定义一个类,然后,这个类的对象具有函数的功能(重载括号运算符)
242. //现在我们怎么调用?
243.     cnt = count_if(iVec.begin(), iVec.end(), IsMore(3));
244.     cnt = count_if(iVec.begin(), iVec.end(), IsMore(4));
245.     cnt = count_if(iVec.begin(), iVec.end(), IsMore(5));
246. //---> IsMore(3) 生成了一个你们对象 M
247. //---> count_if 函数中,依次调用  M(*it) 来判断元素是否满足条件
248. // ----》 调用了 () 运算符重载来判断 是否有:*it > 3
249. 
250. //事实上,我们实现的 MySort 函数,只能升序排列
251. //我们想降序?字符串按长度排序呢? 都不可能通过 MySort 实现
252. //--> 改进的方法: 给 MySort 传入一个参数,作为比较条件
253. }
254. 
255. int main()
256. {
257. //TestVector();
258. TestAlg();
259. 
260. system("pause");
261.  return 0;
262. }

 

相关文章
|
30天前
|
存储 C++ 容器
【C++】vector的底层剖析以及模拟实现
【C++】vector的底层剖析以及模拟实现
|
1月前
|
设计模式 程序员 C++
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
259 2
|
3天前
|
C++
C++虚函数学习笔记
C++虚函数学习笔记
8 0
|
4天前
|
存储 缓存 编译器
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
|
4天前
|
编译器 C++
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析
|
16天前
|
存储 算法 编译器
【C++初阶】STL详解(三)vector的介绍与使用
【C++初阶】STL详解(三)vector的介绍与使用
34 0
|
16天前
|
存储 编译器 C++
【C++初阶】STL详解(四)vector的模拟实现
【C++初阶】STL详解(四)vector的模拟实现
45 1
|
20天前
|
存储 编译器 C++
【C++初阶】10. vector的使用及模拟实现
【C++初阶】10. vector的使用及模拟实现
51 1
|
算法 程序员 C语言
【C++ 迭代器】深入探讨 C++ 迭代器:标准与自定义容器中的 begin() 和 cbegin()
【C++ 迭代器】深入探讨 C++ 迭代器:标准与自定义容器中的 begin() 和 cbegin()
50 0
|
1月前
|
存储 安全 编译器
【C++ 17 泛型容器对比】C++ 深度解析:std::any 与 std::variant 的细微差别
【C++ 17 泛型容器对比】C++ 深度解析:std::any 与 std::variant 的细微差别
57 1