STL容器之vector

【1】模板类vector

模板类vector可理解为广义数组。广义数组,即与类型无关的数组,具有与数组相同的所有操作。

那么,你或许要问:既然C++语言本身已提供了一个序列式容器array,为什么还要vector呢?

我们一直强调,事物总是朝向更先进的方向螺旋式发展与进化。这个问题其中的道理也不例外。

vector的数据安排及操作方式与array非常相似。两者唯一区别在于空间运用的灵活性。

array是静态空间,一旦配置不能改变。要想换个大(或小)点的房子,一切琐细得由客户端自己料理(步骤如下):

首先,配置一块新空间,然后从旧地址将元素逐一搬往新地址,最后把原来的空间释放还给系统。

vector是动态空间,不仅可以在运行期再确定容器容量大小,而且随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。

所以,相比较array,运用vector对内存的合理灵活性利用有很大的帮助。

【2】vector应用实例

(1)有构造函数才会有容器。模板类vector的构造函数及构建实例。代码如下:

1 #include <iostream>
 2 #include <vector>
 3 #include <memory>
 4 using namespace std;
 5 
 6 void main()
 7 {
 8 /* C++11 
 9     default (1)    
10     explicit vector (const allocator_type& alloc = allocator_type());
11     // 构建一个空容器(默认构造函数)。
12 
13     fill (2)    
14     explicit vector (size_type n);
15     vector (size_type n, const value_type& val,
16             const allocator_type& alloc = allocator_type());
17     // 构建一个容器。容器存储n个元素,每个元素的初始值为val(如果提供)。
18 
19     range (3)     
20     template <class InputIterator>
21     vector (InputIterator first, InputIterator last,
22             const allocator_type& alloc = allocator_type());
23     // 构建一个容器。容器存储元素与源容器中[first,last)区间的元素内容一样。
24     // 内容指存放元素的值及位置和[first,last)区间中完全一样,方向也要一致。
25 
26     copy (4)     
27     vector (const vector& x);
28     vector (const vector& x, const allocator_type& alloc);
29     // 拷贝构造函数。构建一个容器,逐个复制源容器x中的每一个元素,存放到本容器中,方向也保持一致。
30 
31     move (5)     
32     vector (vector&& x);
33     vector (vector&& x, const allocator_type& alloc);
34     // 移动构造函数。如果新的分配器alloc和x的分配器alloc不一样,那么将移动源容器x里面的元素到新的vector。
35     // 如果分配器是一样的,那么将直接转换其所有权。
36     // 将右值引用中容器x所有元素的所有权移动到新的vector中,避免付出昂贵的复制代价。
37 
38     initializer list (6)    
39     vector (initializer_list<value_type> il,
40             const allocator_type& alloc = allocator_type());
41     // 初始化列表构造函数。从初始化列表il中复制每一个元素,放到新的vector中,方向与列表保持一致。
42 */
43     // default (1)
44     vector<int> vInt1;
45 
46     // fill (2)
47     int n;
48     cin >> n;
49     vector<int> vInt2(n);
50 
51     vector<int> vInt3(10);
52 
53     vector<int> vInt4(10, 100);
54 
55     // range(3)
56     vector<int> vInt5(vInt4.begin(), vInt4.end());
57 
58     int myInt[] = {1, 2, 3, 4, 5};
59     vector<int> vInt6(myInt, myInt + sizeof(myInt) / sizeof(int));
60 
61     // copy(4)
62     vector<int> vInt7(vInt4);
63 
64     // move(5)
65     vector<unique_ptr<string> > vUS = vector<unique_ptr<string> >({
66         unique_ptr<string> (new string("Qin")), 
67         unique_ptr<string> (new string("Liu")),
68         unique_ptr<string> (new string("Wang")),
69         unique_ptr<string> (new string("Zhang"))});
70 
71     // initializer_list(6)
72     vector<int> vInt8({10, 20, 30, 40, 50});
73 }

对于任何一个类而言,构造函数是相当重要的,其所有对象呈现的操作方法都与构造函数息息相关。

类的构造函数为对象先天性的行为铺垫(比如:类的构造函数若多一个参数,那么类将会有很多成员方法为这个参数服务)。

下面的实例演示使用vector模板方便创建动态分配数组的优势(内置数组无法完成)

1 #include <iostream>
 2 #include <vector>
 3 #include <string>
 4 using namespace std;
 5 
 6 void main()
 7 {
 8     cout << "请输入预处理学生数目:n";
 9     int nStudents;
10     cin >> nStudents;
11     vector<string> names(nStudents);
12     vector<int> scores(nStudents);
13     cout << "请输入" << nStudents << " 个学生的姓名和英语成绩 (0 ~ 100)。n";
14     int i;
15     for (i = 0; i < nStudents; ++i)
16     {
17         cout << "姓名 No" << i + 1 << ": ";
18         cin >> names[i];
19         cout << "成绩 (0 ~ 100):";
20         cin >> scores[i];
21         cin.get();
22     }
23     cout << "输入所有学生信息结束。n";
24     cout << "打印输入姓名及成绩如下:n";
25     for (i = 0; i < nStudents; ++i)
26     {
27         cout << names[i] << "t" << scores[i] << endl;
28     }
29 
30     cin.get();
31 }
32 // Run out:
33 /*
34 请输入预处理学生数目:
35 5
36 请输入5 个学生的姓名和英语成绩 (0 ~ 100)。
37 姓名 No1: sun
38 成绩 (0 ~ 100):89
39 姓名 No2: li
40 成绩 (0 ~ 100):87
41 姓名 No3: wang
42 成绩 (0 ~ 100):90
43 姓名 No4: qin
44 成绩 (0 ~ 100):98
45 姓名 No5: zhang
46 成绩 (0 ~ 100):69
47 输入所有学生信息结束。
48 打印输入姓名及成绩如下:
49 sun     89
50 li      87
51 wang    90
52 qin     98
53 zhang   69
54 */

vector模板更多的方法请看下节。

(2)常用成员方法应用示例如下代码:

1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4 
  5 void printVectorValue(vector<int> & vInt)
  6 {
  7     for (vector<int>::iterator pt = vInt.begin(); pt != vInt.end(); ++pt)
  8     {
  9         cout << *pt << "t";
 10     }
 11     cout << endl;
 12 }
 13 
 14 void main()
 15 {
 16 //  vector对象的常用方法以及应用示例如下:
 17     cout << "动态构建一个整型容器(请输入整数值,0时退出):n"; 
 18     vector<int> vMyInts;
 19     int nTemp;
 20     while (cin >> nTemp && nTemp != 0)
 21     {
 22         vMyInts.push_back(nTemp);
 23     }
 24     cout << "您输入 " << vMyInts.size() << "个元素,分别如下: " << endl;
 25     printVectorValue(vMyInts);
 26     cout << "构建整型容器vMyInts完成" << endl << endl;
 27 
 28 //(1)a.assign(b.begin(), b.begin() + 3); // b为向量,将b的0~2个元素构成的向量赋给a
 29     cout << "(1) assign方法 :" << endl;
 30     vector<int> vA1;
 31     vA1.assign(vMyInts.begin(), vMyInts.begin() + 3);
 32     cout << "容器vA1元素如下:" << endl;
 33     printVectorValue(vA1);
 34     cout << "(1) assign方法应用示例完成。" << endl << endl;
 35 
 36 //(2)a.assign(4, 2); // 容器a只含4个元素,且每个元素值为2
 37     cout << "(2) assign(4, 2)方法 :" << endl;
 38     vector<int> vA2;
 39     vA2.assign(4, 12);
 40     cout << "容器vA2元素如下:" << endl;
 41     printVectorValue(vA2);
 42     cout << "(2) assign(4, 2)方法应用示例完成。" << endl << endl;
 43 
 44 //(3)a.back(); // 返回容器a的最后一个元素
 45     cout << "(3) back方法 :" << endl;
 46     cout << "vMyInts容器的最后一个元素是:" << vMyInts.back() << endl;
 47     cout << "(3) back方法应用示例完成。" << endl << endl;
 48 
 49 // (4)a.front(); // 返回容器a的第一个元素
 50     cout << "(4) front方法 :" << endl;
 51     cout << "vMyInts容器的最前一个元素是:" << vMyInts.front() << endl;
 52     cout << "(4) front方法应用示例完成。" << endl << endl;
 53 
 54 // (5)a[i]; // 返回a的第i个元素,当且仅当a[i]存在
 55     cout << "(5) a[i] 方法 :" << endl;
 56     cout << "vMyInts容器的第2个元素是:" << vMyInts[2 - 1] << endl;
 57     cout << "(5) a[i]方法应用示例完成。" << endl << endl;
 58 
 59 // (6)a.clear(); // 清空容器a中的元素
 60     cout << "(6) clear() 方法 :" << endl;
 61     cout << "清空前,vA2容器中的元素为: " << endl;
 62     printVectorValue(vA2);
 63     vA2.clear();
 64     cout << "清空后,vA2容器中的元素为: " << endl;
 65     printVectorValue(vA2);
 66     cout << "(6) clear()方法应用示例完成。" << endl << endl;
 67 
 68 // (7)a.empty(); // 判断容器a是否为空,空则返回ture,不空则返回false
 69     cout << "(7) empty() 方法 :" << endl;
 70     cout << "vA2容器是否为空:" << vA2.empty() << endl;
 71     cout << "(7) empty()方法应用示例完成。" << endl << endl;
 72 
 73 // (8)a.pop_back(); // 删除容器a的最后一个元素
 74     cout << "(8) pop_back() 方法 :" << endl;    vA2.clear();
 75     cout << "删除前,vMyInts容器中的元素为: " << endl;
 76     printVectorValue(vMyInts);
 77     vMyInts.pop_back();
 78     cout << "删除最后一个元素后,vMyInts容器中的元素为: " << endl;
 79     printVectorValue(vMyInts);
 80     cout << "(8) pop_back()方法应用示例完成。" << endl << endl;
 81 
 82 // (9)a.erase(a.begin() + 1, a.begin() + 3); 
 83 //  删除容器a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从[a.begin() + 1, a.begin() + 3)(前闭后开区间)
 84     cout << "(9) erase() 方法 :" << endl;    vA2.clear();
 85     cout << "删除前,vMyInts容器中的元素为: " << endl;
 86     printVectorValue(vMyInts);
 87     vMyInts.erase(vMyInts.begin() + 1, vMyInts.begin() + 3);
 88     cout << "删除后,vMyInts容器中的元素为: " << endl;
 89     printVectorValue(vMyInts);
 90     cout << "(9) erase()方法应用示例完成。" << endl << endl;
 91 
 92 // (10)a.push_back(5); // 在容器a的最后一个向量后插入一个元素,其值为5
 93     cout << "(10) push_back() 方法 :" << endl;    vA2.clear();
 94     cout << "添加前,vMyInts容器中的元素为: " << endl;
 95     printVectorValue(vMyInts);
 96     vMyInts.push_back(99);
 97     cout << "添加后,vMyInts容器中的元素为: " << endl;
 98     printVectorValue(vMyInts);
 99     cout << "(10) push_back()方法应用示例完成。" << endl << endl;
100 
101 // (11)a.insert(a.begin() + 1, 5); 
102 //  在容器a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4 插入元素后为1,5,2,3,4
103     cout << "(11) insert() 方法 :" << endl;
104     cout << "插入前,vMyInts容器中的元素为: " << endl;
105     printVectorValue(vMyInts);
106     vMyInts.insert(vMyInts.begin() + 1, 11);
107     cout << "插入后,vMyInts容器中的元素为: " << endl;
108     printVectorValue(vMyInts);
109     cout << "(11) insert()方法应用示例完成。" << endl << endl;
110 
111 // (12)a.insert(a.begin() + 1, 3, 5); // 在容器a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
112     cout << "(12) insert() 方法 :" << endl;
113     cout << "插入前,vMyInts容器中的元素为: " << endl;
114     printVectorValue(vMyInts);
115     vMyInts.insert(vMyInts.begin() + 1, 2, 12);
116     cout << "插入后,vMyInts容器中的元素为: " << endl;
117     printVectorValue(vMyInts);
118     cout << "(12) insert()方法应用示例完成。" << endl << endl;
119 
120 // (13)a.insert(a.begin() + 1, b + 3, b + 6); 
121 //  b为数组。在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b + 6)
122 //  b为1,2,3,4,5,9,8  插入元素后为1,4,5,9,2,3,4,5,9,8
123     cout << "(13) insert() 方法 (容器示例):" << endl;
124     cout << "插入前,vMyInts容器中的元素为: " << endl;
125     printVectorValue(vMyInts);
126     cout << "插入前,vA1容器中的元素为: " << endl;
127     printVectorValue(vA1);
128     vA1.insert(vA1.begin() + 1, vMyInts.begin() + 3, vMyInts.begin() + 6);
129     cout << "插入后,vMyInts容器中的元素为: " << endl;
130     printVectorValue(vMyInts);
131     cout << "插入后,vA1容器中的元素为: " << endl;
132     printVectorValue(vA1);
133     cout << "(13) insert()方法应用示例完成。" << endl << endl;
134 
135     cout << "(13) insert() 方法 (数组示例):" << endl;
136     cout << "插入前,vA1容器中的元素为: " << endl;
137     printVectorValue(vA1);
138     cout << "数组中的元素为: {1, 2, 3, 4, 5, 6}" << endl;
139     int nArrB[] = {1, 2, 3, 4, 5, 6};
140     vA1.insert(vA1.begin() + 1, nArrB + 1, nArrB + 4);
141     cout << "插入后,vA1容器中的元素为: " << endl;
142     printVectorValue(vA1);
143     cout << "(13) insert()方法应用示例完成。" << endl << endl;
144 
145 // (14)a.size(); // 返回容器a中元素的个数;
146     cout << "(14) size() 方法: " << endl;
147     cout << "vA1容器中的元素为: " << endl;
148     printVectorValue(vA1);
149     cout << "vA1容器中元素个数为:" << vA1.size() << endl;
150     cout << "(14) size()方法应用示例完成。" << endl << endl;
151 
152 // (15)a.capacity(); // 返回容器a的容量
153     cout << "(15) capacity() 方法: " << endl;
154     cout << "vA1容器的容量为:" << vA1.capacity() << endl;
155     cout << "(15) capacity()方法应用示例完成。" << endl << endl;
156 
157 // (16)a.rezize(10); // 将a的现有元素个数调至10个,多则删,少则补,其值随机
158     cout << "(16) resize() 方法: " << endl;
159     cout << "重新分配大小前,vA1容器中元素为: " << endl;
160     printVectorValue(vA1);
161     vA1.resize(6);
162     cout << "vA1.resize(6) 重新分配大小后,vA1容器中元素为:" << endl;
163     printVectorValue(vA1);
164     cout << "(16) resize()方法应用示例完成。" << endl << endl;
165 
166 // (17)a.rezize(10, 2); // 将容器a的现有元素个数调至10个,多则删,少则补其值为2
167     cout << "(17) resize() 方法: " << endl;
168     cout << "重新分配大小前,vA1容器中元素为: " << endl;
169     printVectorValue(vA1);
170     vA1.resize(10, 100);
171     cout << "vA1.resize(10, 110) 重新分配大小后,vA1容器中元素为:" << endl;
172     printVectorValue(vA1);
173     cout << "(17) resize()方法应用示例完成。" << endl << endl;
174 
175 // (18)a.reserve(100);
176 //  将容器a的容量(capacity)扩充至100,也就是说现在测试 a.capacity();的时候返回值是100。
177 //  这种操作只有在需要给a添加大量数据的时候才有意义,
178 //  因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能。) 
179     cout << "(18) reserve() 方法: " << endl;
180     cout << "扩容前,vA1容器的容量为:" << vA1.capacity() << endl;
181     vA1.reserve(30);
182     cout << "扩容后,vA1容器的容量为:" << vA1.capacity() << endl;
183     cout << "(18) reserve()方法应用示例完成。" << endl << endl;
184 
185 // (19)a.swap(b); // b为容器,将a中的元素和b中的元素进行整体性交换
186     cout << "(19) swap() 方法: " << endl;
187     cout << "vA1容器中的元素为: " << endl;
188     printVectorValue(vA1);
189     cout << "vMyInts容器中的元素为: " << endl;
190     printVectorValue(vMyInts);
191     vA1.resize(5);
192     vMyInts.resize(5);
193     vA1.swap(vMyInts);
194     cout << "vA1容器中的元素为: " << endl;
195     printVectorValue(vA1);
196     cout << "vMyInts容器中的元素为: " << endl;
197     printVectorValue(vMyInts);
198     cout << "(19) swap() 方法应用示例完成。 " << endl << endl;
199 
200 // (20)a = b; // b为容器,将一个对象赋给另一个对象
201     cout << "(20) 赋值方法: " << endl;
202     cout << "vA1容器中的元素为: " << endl;
203     printVectorValue(vA1);
204     vector<int> vTemp = vA1;
205     cout << " vTemp = vA1 后,vTemp 容器中的元素为: " << endl;
206     printVectorValue(vTemp);
207     cout << "(20) 赋值方法应用示例完成。 " << endl << endl;
208 
209 // (20)a == b; // b为容器,向量的比较操作还有!=,>=,<=,>,<
210     cout << "(21) 比较操作: " << endl;
211     cout << "vA1容器中的元素为: " << endl;
212     printVectorValue(vA1);
213     cout << " vTemp 容器中的元素为: " << endl;
214     printVectorValue(vTemp);
215     cout << "vA1 == vTemp 比较:" << (vA1 == vTemp) << endl; 
216     cout << "(21) 比较操作应用示例完成。 " << endl << endl; 
217     cin >> nTemp;
218 }
219 // Run out
220 /*
221 动态构建一个整型容器(请输入整数值,0时退出):
222 12
223 23
224 34
225 45
226 56
227 67
228 78
229 89
230 90
231 0
232 您输入 9个元素,分别如下:
233 12      23      34      45      56      67      78      89      90
234 构建整型容器vMyInts完成
235 
236 (1) assign方法 :
237 容器vA1元素如下:
238 12      23      34
239 (1) assign方法应用示例完成。
240 
241 (2) assign(4, 2)方法 :
242 容器vA2元素如下:
243 12      12      12      12
244 (2) assign(4, 2)方法应用示例完成。
245 
246 (3) back方法 :
247 vMyInts容器的最后一个元素是:90
248 (3) back方法应用示例完成。
249 
250 (4) front方法 :
251 vMyInts容器的最前一个元素是:12
252 (4) front方法应用示例完成。
253 
254 (5) a[i] 方法 :
255 vMyInts容器的第2个元素是:23
256 (5) a[i]方法应用示例完成。
257 
258 (6) clear() 方法 :
259 清空前,vA2容器中的元素为:
260 12      12      12      12
261 清空后,vA2容器中的元素为:
262 
263 (6) clear()方法应用示例完成。
264 
265 (7) empty() 方法 :
266 vA2容器是否为空:1
267 (7) empty()方法应用示例完成。
268 
269 (8) pop_back() 方法 :
270 删除前,vMyInts容器中的元素为:
271 12      23      34      45      56      67      78      89      90
272 删除最后一个元素后,vMyInts容器中的元素为:
273 12      23      34      45      56      67      78      89
274 (8) pop_back()方法应用示例完成。
275 
276 (9) erase() 方法 :
277 删除前,vMyInts容器中的元素为:
278 12      23      34      45      56      67      78      89
279 删除后,vMyInts容器中的元素为:
280 12      45      56      67      78      89
281 (9) erase()方法应用示例完成。
282 
283 (10) push_back() 方法 :
284 添加前,vMyInts容器中的元素为:
285 12      45      56      67      78      89
286 添加后,vMyInts容器中的元素为:
287 12      45      56      67      78      89      99
288 (10) push_back()方法应用示例完成。
289 
290 (11) insert() 方法 :
291 插入前,vMyInts容器中的元素为:
292 12      45      56      67      78      89      99
293 插入后,vMyInts容器中的元素为:
294 12      11      45      56      67      78      89      99
295 (11) insert()方法应用示例完成。
296 
297 (12) insert() 方法 :
298 插入前,vMyInts容器中的元素为:
299 12      11      45      56      67      78      89      99
300 插入后,vMyInts容器中的元素为:
301 12      12      12      11      45      56      67      78      89      99
302 
303 (12) insert()方法应用示例完成。
304 
305 (13) insert() 方法 (容器示例):
306 插入前,vMyInts容器中的元素为:
307 12      12      12      11      45      56      67      78      89      99
308 
309 插入前,vA1容器中的元素为:
310 12      23      34
311 插入后,vMyInts容器中的元素为:
312 12      12      12      11      45      56      67      78      89      99
313 
314 插入后,vA1容器中的元素为:
315 12      11      45      56      23      34
316 (13) insert()方法应用示例完成。
317 
318 (13) insert() 方法 (数组示例):
319 插入前,vA1容器中的元素为:
320 12      11      45      56      23      34
321 数组中的元素为: {1, 2, 3, 4, 5, 6}
322 插入后,vA1容器中的元素为:
323 12      2       3       4       11      45      56      23      34
324 (13) insert()方法应用示例完成。
325 
326 (14) size() 方法:
327 vA1容器中的元素为:
328 12      2       3       4       11      45      56      23      34
329 vA1容器中元素个数为:9
330 (14) size()方法应用示例完成。
331 
332 (15) capacity() 方法:
333 vA1容器的容量为:9
334 (15) capacity()方法应用示例完成。
335 
336 (16) resize() 方法:
337 重新分配大小前,vA1容器中元素为:
338 12      2       3       4       11      45      56      23      34
339 vA1.resize(6) 重新分配大小后,vA1容器中元素为:
340 12      2       3       4       11      45
341 (16) resize()方法应用示例完成。
342 
343 (17) resize() 方法:
344 重新分配大小前,vA1容器中元素为:
345 12      2       3       4       11      45
346 vA1.resize(10, 110) 重新分配大小后,vA1容器中元素为:
347 12      2       3       4       11      45      100     100     100     100
348 
349 (17) resize()方法应用示例完成。
350 
351 (18) reserve() 方法:
352 扩容前,vA1容器的容量为:13
353 扩容后,vA1容器的容量为:30
354 (18) reserve()方法应用示例完成。
355 
356 (19) swap() 方法:
357 vA1容器中的元素为:
358 12      2       3       4       11      45      100     100     100     100
359 
360 vMyInts容器中的元素为:
361 12      12      12      11      45      56      67      78      89      99
362 
363 vA1容器中的元素为:
364 12      12      12      11      45
365 vMyInts容器中的元素为:
366 12      2       3       4       11
367 (19) swap() 方法应用示例完成。
368 
369 (20) 赋值方法:
370 vA1容器中的元素为:
371 12      12      12      11      45
372  vTemp = vA1 后,vTemp 容器中的元素为:
373 12      12      12      11      45
374 (20) 赋值方法应用示例完成。
375 
376 (21) 比较操作:
377 vA1容器中的元素为:
378 12      12      12      11      45
379  vTemp 容器中的元素为:
380 12      12      12      11      45
381 vA1 == vTemp 比较:1
382 (21) 比较操作应用示例完成。
383 */

类的成员方法应用示例运行结果如下:

STL容器之vector

这么多成员方法,为什么没有sort排序方法呢?

(3)通用成员函数。上面常用方法那么多,怎么没有排序方法呢?这点得追溯于STL的设计理念(尽可能一劳永逸)。

STL从更广泛的角度定义了非成员函数来执行这些操作,即不是为每个类都定义sort()成员函数,而是定义一个适用于所有容器类的非成员函数sort()。

试想一个问题,假设有10个类,每个类都支持10种操作,若每个类都有自己的成员函数,则需要定义100(10*10)个成员函数。而采用STL方式,只需要定义10个非成员函数即可。

另外需要注意,已有执行相同任务的非成员函数,STL有时还会为类定义一个成员函数,因为对于有些操作来说,类特定算法的效率比通用算法高。

下面学习几个所谓的公用函数:for_each()、random_shuffle()、sort()。

3.1 for_each函数接受3个参数,前两个是定义容器中区间的迭代器,最后一个是指向函数的指针。可以用for_each函数来代替for循环。例如:

1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>   // for_each
 4 using namespace std;
 5 
 6 void printVectorValue(int & rInt)
 7 {
 8     cout << rInt << "t";
 9 }
10 
11 void main()
12 {
13     cout << "动态构建一个整型容器(请输入整数值,0时退出):n"; 
14     vector<int> vMyInts;
15     int nTemp;
16     while (cin >> nTemp && nTemp != 0)
17     {
18         vMyInts.push_back(nTemp);
19     }
20     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
21     cout << "使用for循环打印容器元素如下:" << endl;
22     for (vector<int>::iterator pIt = vMyInts.begin(); pIt != vMyInts.end(); ++pIt)
23     {
24         cout << *pIt << "t";
25     }
26     cout << endl << "使用for_each打印容器元素如下:" << endl;
27     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue);
28     cout << endl << "构建整型容器vMyInts完成" << endl << endl;
29     cin >> nTemp;
30 }
31 // Run out
32 /*
33 动态构建一个整型容器(请输入整数值,0时退出):
34 12
35 23
36 34
37 45
38 56
39 67
40 78
41 89
42 90
43 0
44 您输入 9 个元素,分别如下:
45 使用for循环打印容器元素如下:
46 12      23      34      45      56      67      78      89      90
47 使用for_each打印容器元素如下:
48 12      23      34      45      56      67      78      89      90
49 构建整型容器vMyInts完成
50 */

这样可以避免显式使用迭代器变量。

3.2 random_shffle函数接受两个指定区间的迭代器参数,并随机排列该区间中的元素。应用示例代码如下:

1 #include <iostream>
 2 #include <vector>
 3 #include <string>
 4 #include <algorithm>   // for_each
 5 using namespace std;
 6 
 7 template<class T>
 8 void printVectorValue(T & rInt)
 9 {
10     cout << rInt << "t";
11 }
12 
13 void main()
14 {
15     cout << "动态构建一个整型容器(请输入整数值,0时退出):n"; 
16     vector<int> vMyInts;
17     int nTemp;
18     while (cin >> nTemp && nTemp != 0)
19     {
20         vMyInts.push_back(nTemp);
21     }
22     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
23     cout << "使用for_each打印排序前容器元素如下:" << endl;
24     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
25     random_shuffle(vMyInts.begin(), vMyInts.end());
26     cout << endl << "使用for_each打印排序后容器元素如下:" << endl;
27     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
28 
29     cout << endl;
30     vector<string> vStr;
31     vStr.push_back("sun");
32     vStr.push_back("zhang");
33     vStr.push_back("huang");
34     vStr.push_back("liu");
35     vStr.push_back("qin");
36     cout << endl << "打印排序前容器元素如下:" << endl;
37     for (int j = 0; j < vStr.size(); ++j)
38     {
39         cout << vStr[j].c_str() << "t";
40     }
41     std::random_shuffle(vStr.begin(), vStr.end()); // 迭代器
42     cout << endl << "打印排序后容器元素如下:" << endl;
43     for (int j = 0; j < vStr.size(); ++j)
44     {
45         cout << vStr[j].c_str() << "t";
46     }
47     cout << endl;
48     system("pause");
49 }

程序运行结果如下:

STL容器之vector

3.3 sort函数也要求容器支持随机访问,该函数有两个版本:

第一个版本接受两个定义区间的迭代器参数,并使用为存储在容器中的类型元素定义的<运算符。

备注:如果元素为用户自定义类型,必须定义能够处理该类型对象的operator<()函数),对区间中的元素进行操作。

第二个版本接受3个参数,前两个参数也是指定区间的迭代器,最后一个参数是指向要使用的函数的指针(而不是比较的operator<()运算符)。

sort函数的应用示例代码如下:

1 #include <iostream>
 2 #include <vector>
 3 #include <string>
 4 #include <algorithm>   // for_each
 5 using namespace std;
 6 
 7 template<class T>
 8 void printVectorValue(T & rInt)
 9 {
10     cout << rInt << "t";
11 }
12 
13 struct student
14 {
15     string strName;
16     int nAge;
17 
18     student(string sName = "liu", int nAge = 22) : strName(sName), nAge(nAge)
19     {}
20 };
21 
22 bool worseThan(const student & stuObject1, const student & stuObject2)
23 {
24     if (stuObject1.nAge > stuObject2.nAge)
25     {
26         return true;
27     }
28     else if (stuObject1.nAge == stuObject2.nAge 
29         && stuObject1.strName > stuObject2.strName)
30     {
31         return true;
32     }
33     else
34     {
35         return false;
36     }
37 }
38 
39 void printValue(const student & rStuObject)
40 {
41     cout << rStuObject.strName << "  " << rStuObject.nAge << "n";
42 }
43 
44 void main()
45 {
46     cout << "sort函数版本1测试程序:" << endl;
47     cout << "动态构建一个整型容器(请输入整数值,0时退出):n"; 
48     vector<int> vMyInts;
49     int nTemp;
50     while (cin >> nTemp && nTemp != 0)
51     {
52         vMyInts.push_back(nTemp);
53     }
54     cout << "您输入 " << vMyInts.size() << " 个元素,分别如下: " << endl;
55     cout << "使用for_each打印排序前容器元素如下:" << endl;
56     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
57     sort(vMyInts.begin(), vMyInts.end());  // 版本1
58     cout << endl << "使用for_each打印排序后容器元素如下:" << endl;
59     for_each(vMyInts.begin(), vMyInts.end(), printVectorValue<int>);
60 
61     cout << endl << endl << "sort函数版本2测试程序:" << endl;
62     vector<student> vStudents;
63     vStudents.push_back(student("sun", 23));
64     vStudents.push_back(student("zhang", 24));
65     vStudents.push_back(student("huang", 22));
66     vStudents.push_back(student("liu", 21));
67     vStudents.push_back(student("qin", 22));
68     cout << "使用for_each打印排序前容器元素如下:" << endl;
69     for_each(vStudents.begin(), vStudents.end(), printValue);
70     sort(vStudents.begin(), vStudents.end(), worseThan);  // 版本2
71     cout << "使用for_each打印排序后容器元素如下:" << endl;
72     for_each(vStudents.begin(), vStudents.end(), printValue);
73     cout << endl;
74     system("pause");
75 }

程序运行结果如下:

STL容器之vector

通用非成员函数结束。

【3】学习《STL源码剖析》中vector

(1)vector容器可以自动扩充内存空间,具体的扩充规则测试代码如下:

1 #include <vector>
 2 #include <iostream>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 template<class T>
 7 void printVectorValue(T & rInt)
 8 {
 9     cout << rInt << "  ";
10 }
11 
12 template<class T>
13 void printSizeAndCapacity(vector<T> & oVec)
14 {
15     for_each(oVec.begin(), oVec.end(), printVectorValue<T>);
16     cout << endl << "size = " << oVec.size() << endl;
17     cout << "capacity = " << oVec.capacity() << endl << endl;
18 }
19 
20 int main()
21 {
22     vector<int> iv(2, 9);
23     printSizeAndCapacity(iv);
24     for (int i = 0; i < 8; ++i)
25     {
26         iv.push_back(i + 1);
27         printSizeAndCapacity<int>(iv);
28     }
29 
30     system("pause");
31 }

vector容器示意图如下:

STL容器之vector

运行结果如下:

STL容器之vector

有一个遗留问题:如size不为零时,扩充后容量应该是之前的2倍,根据上例实际情况,不应该有奇数值的容量!求再探索,作此备录。

(2)vector迭代器和数据结构,如下图所示:

STL容器之vector

(3)vector部分源码如下:

1 #include<iostream>
  2 #include<memory.h>
  3 using namespace std;
  4 
  5 // alloc是SGI STL的空间配置器
  6 template <class T, class Alloc = alloc>
  7 class vector
  8 {
  9 public:
 10     // vector的嵌套类型定义,typedefs用于提供iterator_traits<I>支持
 11     typedef T value_type;
 12     typedef value_type* pointer;
 13     typedef value_type* iterator;
 14     typedef value_type& reference;
 15     typedef size_t size_type;
 16     typedef ptrdiff_t difference_type;
 17 protected:
 18     // 这个提供STL标准的allocator接口
 19     typedef simple_alloc <value_type, Alloc> data_allocator;
 20 
 21     iterator start;               // 表示目前使用空间的头
 22     iterator finish;              // 表示目前使用空间的尾
 23     iterator end_of_storage;      // 表示实际分配内存空间的尾
 24 
 25     void insert_aux(iterator position, const T& x); // 在position位置插入值为x的元素
 26 
 27     // 释放分配的内存空间
 28     void deallocate()
 29     {
 30         // 由于使用data_allocator进行内存空间的分配,
 31         // 所以匹配使用data_allocator::deallocate()进行释放
 32         // 如果直接释放, 对于data_allocator内部使用内存池的版本就会发生错误
 33         if (start)
 34             data_allocator::deallocate(start, end_of_storage - start);
 35     }
 36 
 37     void fill_initialize(size_type n, const T& value)
 38     {
 39         start = allocate_and_fill(n, value);
 40         finish = start + n;  // 设置当前使用内存空间的结束点
 41         // 构造阶段(不多分配内存)
 42         // 所以要设置内存空间结束点(与已经使用的内存空间结束点相同)
 43         end_of_storage = finish;
 44     }
 45 
 46 public:
 47     // 获取几种迭代器
 48     iterator begin() { return start; }
 49     iterator end() { return finish; }
 50 
 51     // 返回当前对象个数
 52     size_type size() const { return size_type(end() - begin()); }
 53     size_type max_size() const { return size_type(-1) / sizeof(T); }
 54     // 返回重新分配内存前最多能存储的对象个数
 55     size_type capacity() const { return size_type(end_of_storage - begin()); }
 56     // 判空
 57     bool empty() const { return begin() == end(); }
 58     // 重载[](下标访问)
 59     reference operator[](size_type n) { return *(begin() + n); }
 60 
 61     // 默认构造函数。默认构造vector不分配内存空间
 62     vector() : start(0), finish(0), end_of_storage(0) {}
 63 
 64     vector(size_type n, const T& value) { fill_initialize(n, value); }
 65     vector(int n, const T& value) { fill_initialize(n, value); }
 66     vector(long n, const T& value) { fill_initialize(n, value); }
 67 
 68     // 需要对象提供默认构造函数
 69     explicit vector(size_type n) { fill_initialize(n, T()); }
 70 
 71     vector(const vector<T, Alloc>& x)
 72     {
 73         start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
 74         finish = start + (x.end() - x.begin());
 75         end_of_storage = finish;
 76     }
 77 
 78     ~vector()
 79     {
 80         // 析构对象
 81         destroy(start, finish);
 82         // 释放内存
 83         deallocate();
 84     }
 85 
 86     vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
 87 
 88     // 提供访问函数
 89     reference front() { return *begin(); }
 90     reference back() { return *(end() - 1); }
 91 
 92     ////////////////////////////////////////////////////////////////////////////////
 93     // 向容器尾追加一个元素, 可能导致内存重新分配(开辟新空间、移动原数据、释放原内存)
 94     ////////////////////////////////////////////////////////////////////////////////
 95     //                          push_back(const T& x)
 96     //                                   |
 97     //                                   |---------------- 容量已满?
 98     //                                   |
 99     //               ----------------------------
100     //           No  |                          |  Yes
101     //               |                          |
102     //               ↓                          ↓
103     //      construct(finish, x);       insert_aux(end(), x);
104     //      ++finish;                           |
105     //                                          |------ 内存不足, 重新分配
106     //                                          |       大小为原来的2倍
107     //      new_finish = data_allocator::allocate(len);       <stl_alloc.h>
108     //      uninitialized_copy(start, position, new_start);   <stl_uninitialized.h>
109     //      construct(new_finish, x);                         <stl_construct.h>
110     //      ++new_finish;
111     //      uninitialized_copy(position, finish, new_finish); <stl_uninitialized.h>
112     ////////////////////////////////////////////////////////////////////////////////
113 
114     void push_back(const T& x)
115     {
116         // 内存满足条件则直接追加元素, 否则需要重新分配内存空间
117         if (finish != end_of_storage)
118         {
119             construct(finish, x);
120             ++finish;
121         }
122         else
123             insert_aux(end(), x);
124     }
125 
126 
127     ////////////////////////////////////////////////////////////////////////////////
128     // 在指定位置插入元素
129     ////////////////////////////////////////////////////////////////////////////////
130     //                   insert(iterator position, const T& x)
131     //                                   |
132     //                                   |------------ 容量是否足够 && 是否是end()?
133     //                                   |
134     //               -------------------------------------------
135     //            No |                                         | Yes
136     //               |                                         |
137     //               ↓                                         ↓
138     //    insert_aux(position, x);                  construct(finish, x);
139     //               |                              ++finish;
140     //               |-------- 容量是否够用?
141     //               |
142     //        --------------------------------------------------
143     //    Yes |                                                | No
144     //        |                                                |
145     //        ↓                                               |
146     // construct(finish, *(finish - 1));                       |
147     // ++finish;                                               |
148     // T x_copy = x;                                           |
149     // copy_backward(position, finish - 2, finish - 1);        |
150     // *position = x_copy;                                     |
151     //                                                         ↓
152     // data_allocator::allocate(len);                       <stl_alloc.h>
153     // uninitialized_copy(start, position, new_start);      <stl_uninitialized.h>
154     // construct(new_finish, x);                            <stl_construct.h>
155     // ++new_finish;
156     // uninitialized_copy(position, finish, new_finish);    <stl_uninitialized.h>
157     // destroy(begin(), end());                             <stl_construct.h>
158     // deallocate();
159     ////////////////////////////////////////////////////////////////////////////////
160 
161     iterator insert(iterator position, const T& x)
162     {
163         size_type n = position - begin();
164         if (finish != end_of_storage && position == end())
165         {
166             construct(finish, x);
167             ++finish;
168         }
169         else
170             insert_aux(position, x);
171         return begin() + n;
172     }
173 
174     iterator insert(iterator position) { return insert(position, T()); }
175 
176     void pop_back()
177     {
178         --finish;
179         destroy(finish);
180     }
181 
182     iterator erase(iterator position)
183     {
184         if (position + 1 != end())
185             copy(position + 1, finish, position);
186         --finish;
187         destroy(finish);
188         return position;
189     }
190 
191 
192     iterator erase(iterator first, iterator last)
193     {
194         iterator i = copy(last, finish, first);
195         // 析构掉需要析构的元素
196         destroy(i, finish);
197         finish = finish - (last - first);
198         return first;
199     }
200 
201     // 调整size, 但是并不会重新分配内存空间
202     void resize(size_type new_size, const T& x)
203     {
204         if (new_size < size())
205             erase(begin() + new_size, end());
206         else
207             insert(end(), new_size - size(), x);
208     }
209     void resize(size_type new_size) { resize(new_size, T()); }
210 
211     void clear() { erase(begin(), end()); }
212 
213 protected:
214     // 分配空间, 并且复制对象到分配的空间处
215     iterator allocate_and_fill(size_type n, const T& x)
216     {
217         iterator result = data_allocator::allocate(n);
218         uninitialized_fill_n(result, n, x);
219         return result;
220     }
221 
222     // 提供插入操作
223     ////////////////////////////////////////////////////////////////////////////////
224     //                 insert_aux(iterator position, const T& x)
225     //                                   |
226     //                                   |---------------- 容量是否足够?
227     //                                   ↓
228     //              -----------------------------------------
229     //        Yes   |                                       | No
230     //              |                                       |
231     //              ↓                                      |
232     // 从opsition开始, 整体向后移动一个位置                 |
233     // construct(finish, *(finish - 1));                    |
234     // ++finish;                                            |
235     // T x_copy = x;                                        |
236     // copy_backward(position, finish - 2, finish - 1);     |
237     // *position = x_copy;                                  |
238     //                                                      ↓
239     //                            data_allocator::allocate(len);
240     //                            uninitialized_copy(start, position, new_start);
241     //                            construct(new_finish, x);
242     //                            ++new_finish;
243     //                            uninitialized_copy(position, finish, new_finish);
244     //                            destroy(begin(), end());
245     //                            deallocate();
246     ////////////////////////////////////////////////////////////////////////////////
247 
248     template <class T, class Alloc>
249     void insert_aux(iterator position, const T& x)
250     {
251         if (finish != end_of_storage)    // 还有备用空间
252         {
253             // 在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值
254             construct(finish, *(finish - 1));
255             ++finish;
256             T x_copy = x;
257             copy_backward(position, finish - 2, finish - 1);
258             *position = x_copy;
259         }
260         else   // 已无备用空间
261         {
262             const size_type old_size = size();
263             const size_type len = old_size != 0 ? 2 * old_size : 1;
264             // 以上配置元素:如果大小为0,则配置1(个元素大小)
265             // 如果大小不为0,则配置原来大小的两倍
266             // 前半段用来放置原数据,后半段准备用来放置新数据
267 
268             iterator new_start = data_allocator::allocate(len);  // 实际配置
269             iterator new_finish = new_start;
270             // 将内存重新配置
271             try
272             {
273                 // 将原vector的安插点以前的内容拷贝到新vector
274                 new_finish = uninitialized_copy(start, position, new_start);
275                 // 为新元素设定初值 x
276                 construct(new_finish, x);
277                 // 调整水位
278                 ++new_finish;
279                 // 将安插点以后的原内容也拷贝过来
280                 new_finish = uninitialized_copy(position, finish, new_finish);
281             }
282             catch(...)
283             {
284                 // 回滚操作
285                 destroy(new_start, new_finish);
286                 data_allocator::deallocate(new_start, len);
287                 throw;
288             }
289             // 析构并释放原vector
290             destroy(begin(), end());
291             deallocate();
292 
293             // 调整迭代器,指向新vector
294             start = new_start;
295             finish = new_finish;
296             end_of_storage = new_start + len;
297         }
298     }
299 
300     ////////////////////////////////////////////////////////////////////////////////
301     // 在指定位置开始连续插入n个值为x的元素
302     ////////////////////////////////////////////////////////////////////////////////
303     //             insert(iterator position, size_type n, const T& x)
304     //                                   |
305     //                                   |---------------- 插入元素个数是否为0?
306     //                                   ↓
307     //              -----------------------------------------
308     //        No    |                                       | Yes
309     //              |                                       |
310     //              |                                       ↓
311     //              |                                    return;
312     //              |----------- 内存是否足够?
313     //              |
314     //      -------------------------------------------------
315     //  Yes |                                               | No
316     //      |                                               |
317     //      |------ (finish - position) > n?                |
318     //      |       分别调整指针                            |
319     //      ↓                                              |
320     //    ----------------------------                      |
321     // No |                          | Yes                  |
322     //    |                          |                      |
323     //    ↓                         ↓                    |
324     // 插入操作, 调整指针           插入操作, 调整指针      |
325     //                                                      ↓
326     //            data_allocator::allocate(len);
327     //            new_finish = uninitialized_copy(start, position, new_start);
328     //            new_finish = uninitialized_fill_n(new_finish, n, x);
329     //            new_finish = uninitialized_copy(position, finish, new_finish);
330     //            destroy(start, finish);
331     //            deallocate();
332     ////////////////////////////////////////////////////////////////////////////////
333 
334     template <class T, class Alloc>
335     void insert(iterator position, size_type n, const T& x)
336     {
337         // 如果n为0,则不进行任何操作
338         if (n != 0)
339         {
340             if (size_type(end_of_storage - finish) >= n)
341             {      // 剩下的备用空间大于等于“新增元素的个数”
342                 T x_copy = x;
343                 // 以下计算插入点之后的现有元素个数
344                 const size_type elems_after = finish - position;
345                 iterator old_finish = finish;
346                 if (elems_after > n)
347                 {
348                     // 插入点之后的现有元素个数 大于 新增元素个数
349                     uninitialized_copy(finish - n, finish, finish);
350                     finish += n;    // 将vector 尾端标记后移
351                     copy_backward(position, old_finish - n, old_finish);
352                     fill(position, position + n, x_copy); // 从插入点开始填入新值
353                 }
354                 else
355                 {
356                     // 插入点之后的现有元素个数 小于等于 新增元素个数
357                     uninitialized_fill_n(finish, n - elems_after, x_copy);
358                     finish += n - elems_after;
359                     uninitialized_copy(position, old_finish, finish);
360                     finish += elems_after;
361                     fill(position, old_finish, x_copy);
362                 }
363             }
364             else
365             {   // 剩下的备用空间小于“新增元素个数”(那就必须配置额外的内存)
366                 // 首先决定新长度:就长度的两倍 , 或旧长度+新增元素个数
367                 const size_type old_size = size();
368                 const size_type len = old_size + max(old_size, n);
369                 // 以下配置新的vector空间
370                 iterator new_start = data_allocator::allocate(len);
371                 iterator new_finish = new_start;
372                 __STL_TRY
373                 {
374                     // 以下首先将旧的vector的插入点之前的元素复制到新空间
375                     new_finish = uninitialized_copy(start, position, new_start);
376                     // 以下再将新增元素(初值皆为n)填入新空间
377                     new_finish = uninitialized_fill_n(new_finish, n, x);
378                     // 以下再将旧vector的插入点之后的元素复制到新空间
379                     new_finish = uninitialized_copy(position, finish, new_finish);
380                 }
381 #         ifdef  __STL_USE_EXCEPTIONS
382                 catch(...)
383                 {
384                     destroy(new_start, new_finish);
385                     data_allocator::deallocate(new_start, len);
386                     throw;
387                 }
388 #         endif /* __STL_USE_EXCEPTIONS */
389                 destroy(start, finish);
390                 deallocate();
391                 start = new_start;
392                 finish = new_finish;
393                 end_of_storage = new_start + len;
394             }
395         }
396     }
397 };

(4)使用主要问题及成员函数详解。

4.1 erase函数。vector::erase()方法有两种重载形式:

(1.1)iterator erase (iterator _Where);

(1.2)iterator erase (iterator _First, iterator _Last);

如果是删除指定位置的元素时:返回值是一个迭代器,指向删除元素下一个元素。

如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素。

请看如下“临床典型性”应用错误示例代码:

1 #include <vector> 
 2 #include <iostream>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 template<class T>
 7 void printVectorValue(T & rInt)
 8 {
 9     cout << rInt << "  ";
10 }
11 
12 void main() 
13 { 
14     vector <int> v1;
15     for (int i = 0; i < 6; ++i)
16     {
17         v1.push_back(i + 10);
18     }
19     cout << "(1) v1 容器元素如下:" << endl;
20     for_each(v1.begin(), v1.end(), printVectorValue<int>);
21     cout << endl;
22 
23     v1.erase(v1.begin( ));
24     cout << "(2) v1 容器元素如下:" << endl;
25     for_each(v1.begin(), v1.end(), printVectorValue<int>);
26     cout << endl;
27 
28     v1.erase(v1.begin( ) + 1, v1.begin( ) + 3);
29     cout << "(3) v1 容器元素如下:" << endl;
30     for_each(v1.begin(), v1.end(), printVectorValue<int>);
31     cout << endl;
32 
33     v1.push_back(14);
34     vector<int>::iterator itPt;
35     for (itPt = v1.begin(); itPt != v1.end(); ++itPt) 
36     { 
37         if (14 == *itPt) 
38         { 
39             v1.erase(itPt);
40         } 
41     }
42 
43     system("pause");
44 }

程序运行结果如下:

STL容器之vector

分析程序:一一遍历容器找到元素值为14,然后一一删除。程序为什么会崩溃呢?

其实,出现这种原因是没搞懂erase的删除原理(套路),当调用erase()后迭代器就失效了,即变成一个野指针。

所以要处理这种问题,关键是要解决调用erase()方法后,迭代器变成野指针的问题。

结合套路,解决这个问题有两种方案:

第一种:正向删除。

第二种:逆向删除。代码如下:

1 #include <vector> 
  2 #include <iostream>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 template<class T>
  7 void printVectorValue(T & rInt)
  8 {
  9     cout << rInt << "  ";
 10 }
 11 
 12 // 正删
 13 template<class T>
 14 void eraseAll(vector<T> & v1, T value)
 15 {
 16     vector<T>::iterator itPt;
 17     for (itPt = v1.begin(); itPt != v1.end();) 
 18     { 
 19         if (value == *itPt) 
 20         { 
 21             itPt = v1.erase(itPt);
 22         }
 23         else
 24         {
 25             ++itPt;
 26         }
 27     }
 28 }
 29 
 30 // 逆删
 31 template<class T>
 32 void eraseAll2(vector<T> & v1, T value)
 33 {
 34     vector<T>::iterator itPt;
 35     for (itPt = --v1.end(); itPt != v1.begin();) 
 36     { 
 37         if (value == *itPt) 
 38         { 
 39             v1.erase(itPt--);
 40         }
 41         else
 42         {
 43             --itPt;
 44         }
 45     }
 46 
 47     if (value == *itPt)
 48     {
 49         v1.erase(itPt);
 50     }
 51 }
 52 
 53 void main() 
 54 { 
 55     vector<int> v1(6, 9);
 56     for (int i = 0; i < 6; ++i)
 57     {
 58         v1.push_back(i + 10);
 59     }
 60     cout << "(1) v1 容器元素如下:" << endl;
 61     for_each(v1.begin(), v1.end(), printVectorValue<int>);
 62     cout << endl;
 63 
 64     v1.erase(v1.begin( ));
 65     cout << "(2) v1 容器元素如下:" << endl;
 66     for_each(v1.begin(), v1.end(), printVectorValue<int>);
 67     cout << endl;
 68 
 69     v1.erase(v1.begin( ) + 1, v1.begin( ) + 3);
 70     cout << "(3) v1 容器元素如下:" << endl;
 71     for_each(v1.begin(), v1.end(), printVectorValue<int>);
 72     cout << endl;
 73 
 74     v1.insert(v1.begin() + 5, 3, 12);
 75     v1.push_back(15);
 76     v1.push_back(15);
 77     cout << "(4) 删除前 v1 容器元素如下:" << endl;
 78     for_each(v1.begin(), v1.end(), printVectorValue<int>);
 79     cout << endl;
 80 
 81 // 第一种正向删除
 82     eraseAll<int>(v1, 9);
 83     eraseAll<int>(v1, 12);
 84     eraseAll<int>(v1, 15);
 85 
 86 /* 第二种逆向删除
 87     eraseAll2<int>(v1, 9);
 88     eraseAll2<int>(v1, 12);
 89     eraseAll2<int>(v1, 15);
 90 */
 91     cout << "(5) 删除9,12,15后 v1 容器元素如下:" << endl;
 92     for_each(v1.begin(), v1.end(), printVectorValue<int>);
 93     cout << endl;
 94     /* 错误删除!!
 95     for (itPt = v1.begin(); itPt != v1.end(); ++itPt) 
 96     { 
 97         if (14 == *itPt) 
 98         { 
 99             v1.erase(itPt);
100         } 
101     }
102     */
103 
104     system("pause");
105 }
106 
107 // Run out
108 /*
109 (1) v1 容器元素如下:
110 9  9  9  9  9  9  10  11  12  13  14  15
111 (2) v1 容器元素如下:
112 9  9  9  9  9  10  11  12  13  14  15
113 (3) v1 容器元素如下:
114 9  9  9  10  11  12  13  14  15
115 (4) 删除前 v1 容器元素如下:
116 9  9  9  10  11  12  12  12  12  13  14  15  15  15
117 (5) 删除9,12,15后 v1 容器元素如下:
118 10  11  13  14
119 请按任意键继续. . .
120 */

规避开失效指针,完全可以正常删除。

为了加深理解,再追加一个正向删除的示例程序:

1 #include <vector>
 2 #include <iostream>
 3 
 4 #define PRINT_INFO (1)
 5 
 6 void eraseTarget(std::vector<int>& vect, int value)
 7 {
 8     auto print = [&]() {
 9         for (auto iter = vect.begin(); iter != vect.end();)
10             std::cout << (*iter++) << ((iter == vect.end()) ? std::string{} : " | ");
11         std::cout << std::endl;
12     };
13 
14 #if PRINT_INFO
15     std::cout << "************ Begin erase target ************" << std::endl;
16     std::cout << "begin element of vector :: ";
17     print();
18     std::cout << std::endl;
19 #endif
20 
21     auto iter = vect.begin();
22     while (iter != vect.end())
23     {
24 #if PRINT_INFO
25         print();
26         std::cout << "before erase current iter value :: " << (*iter) << " || before erase size :: " << vect.size() << std::endl;
27 #endif
28 
29         if ((*iter) == value)
30         {
31            iter = vect.erase(iter);
32 
33 #if PRINT_INFO
34            std::cout << "after erase current iter value :: " << ((iter == vect.end()) ? (-1) : (*iter))
35                << " || after erase size :: " << vect.size() << std::endl << std::endl;
36 #endif
37         }
38         else
39         {
40 #if PRINT_INFO
41             std::cout << std::endl;
42 #endif
43             ++iter;
44         }
45     }
46 
47 #if PRINT_INFO
48     std::cout << "end element of vector :: ";
49     print();
50     std::cout << "************ End erase target ************" << std::endl;
51 #endif
52 }
53 
54 int main()
55 {
56     {
57         std::vector<int> vect = { 3, 3, 4, 5, 6, 3, 3, 7, 8, 9, 3, 3 };
58         eraseTarget(vect, 3);
59     }
60 
61     return 0;
62 }

备注:可通过宏PRINT_INFO控制是否打印过程信息,便于理解。

附本地运行结果:

STL容器之vector

4.2 insert函数

insert函数源码如下:

STL容器之vector

insert函数两种情况分析如下:

STL容器之vector

insert函数重载多,使用比较方便。

【4】vector总结

相比C++内置的array数组类,vector模板类是有生命的、动态的、可塑性的数组,使用更方便,更健壮。

Good Good Study, Day Day Up.

顺序 选择 循环 总结
原文链接: https://www.cnblogs.com/Braveliu/p/6264543.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/247389

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 上午2:13
下一篇 2023年2月14日 上午2:13

相关推荐