C++学习之路: STL探索 vector 和 list

引言: 这篇文章写在我们窥探庞大的STL 库之前,先熟悉一下基本操作,用于练手, 也用于过段时间的复习。

 

1.可以用一个容器去初始化另外一个容器。

但是两个容器的类型和内置类型都必须一致,否则编译无法通过。

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 using namespace std;
 5 
 6 //用一个容器去初始化另一个容器
 7 int main(int argc, const char *argv[])
 8 {
 9     vector<int> vec;
10     vec.push_back(12);
11     vec.push_back(89);
12     vec.push_back(34);
13     vec.push_back(23);
14     vec.push_back(56);
15 
16     vector<int> vec2(vec);
17     for(int t : vec2)
18     {
19         cout << t << " ";
20     }
21     cout << endl;
22 
23     return 0;
24 }

2.也可以用一段迭代器范围,去初始化另外一个容器:

同样迭代器也必须是该类型 的迭代器,这是基本要求,不要去尝试一些莫名其妙的初始化,例如用vector<string> 去初始化 vector<int> ,这种低级的错误

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 //用一段迭代器范围去初始化另一个容器
 8 int main(int argc, const char *argv[])
 9 {
10     vector<int> vec;
11     vec.push_back(12);
12     vec.push_back(89);
13     vec.push_back(34);
14     vec.push_back(23);
15     vec.push_back(56);
16 
17     vector<int>::iterator it1, it2;
18     it1 = vec.begin(); //12
19     it2 = find(vec.begin(), vec.end(), 23);   
20 
21     vector<int> vec2(it1, it2);  //作为vec2的参数的两个迭代器it1和it2 也必须是vector<int>::iterator 类型,用vector<xxxxx> ::iterator 作为参数是不会通过编译的
22     for(int i : vec2)
23     {
24         cout << i << " ";
25     }
26     cout << endl;
27     return 0;
28 }

综上:我们在用容器,迭代器等方法去初始化另外一个容器,类型匹配是最基本的要求。

 3.下面看一个错误的例子:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 //用一段迭代器范围去初始化另一个容器
 8 int main(int argc, const char *argv[])
 9 {
10     vector<int> vec;
11     vec.push_back(12);
12     vec.push_back(89);
13     vec.push_back(34);
14     vec.push_back(23);
15     vec.push_back(56);
16 
17     vector<double> vec2(vec); //vector<int> 与vector<double>类型不同
18 
19 
20     return 0;
21 }

上述代码,编译出现错误,因为vec2是一个vector<double> 类型,而vec是一个vector<int> 类型,两个容器类型不匹配。

 

4.容器类型不一样,无法使用一个容器初始化另外的方法,

却可以使用迭代器范围的方法,用一个容器的迭代器范围去初始化另外一个。   前提是它们的内置类型必须相近,如 int 和 double 

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 //用一段迭代器范围去初始化另一个容器
 8 int main(int argc, const char *argv[])
 9 {
10     vector<int> vec;
11     vec.push_back(12);
12     vec.push_back(89);
13     vec.push_back(34);
14     vec.push_back(23);
15     vec.push_back(56);
16 
17     vector<double> vec2(vec.begin(), vec.end());
18     for(double d : vec2)
19     {
20         cout << d << " ";
21     }
22     cout << endl;
23 
24     return 0;
25 }

 

上面代码所描述的情况就好比, 如果两个碗里面装的东西不一样的时候,它们是不能相互赋值(或初始化)的, 但是当它们*里面的东西*, 差不多的时候,可以用迭代器赋值。

如果差别太大,则编译不通过 如 迭代器指向的是string类型, 我们却用来初始化 一个vector<int> 容器,显然是不可取的。

 

5.当容器不一样,但是内置类型差不多的时候,也可以用迭代器的方法来初始化, 例如我们用vector<int>的 迭代器 来初始化list<int/double> 则是可以的

因为迭代器指向的内容和vector里面存放的东西差不多,就好像碗和碟子的关系,虽然容器不同,但是里面都是放的同一种食物(好比米饭), 我们就可以把碟子中的米饭,

复制到碟子里。

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <list>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 //用一段迭代器范围去初始化另一个容器
 9 int main(int argc, const char *argv[])
10 {
11     vector<int> vec;
12     vec.push_back(12);
13     vec.push_back(89);
14     vec.push_back(34);
15     vec.push_back(23);
16     vec.push_back(56);
17 
18     list<double> lst(vec.begin(), vec.end());
19     for(double d : lst)
20     {
21         cout << d << " ";
22     }
23     cout << endl;
24 
25     return 0;
26 }

 

6. 下面我们来看一看list,如果vector好比是数组,那么list就像链表一样,这个容器我们用的比较少。 看看它有哪些操作

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <list>
 5 using namespace std;
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     list<string> lst;
10     lst.push_back("beijing");
11     lst.push_back("shanghai");
12 
13     lst.push_front("shenzhen");
14 
15     for(list<string>::const_iterator it = lst.begin();
16         it != lst.end();
17         ++it)
18     {
19         cout << *it << " ";
20     }
21 
22     cout << endl;
23     return 0;
24 }

 list比vector 多出一个push_front成员函数,可以用于头插,把元素至于首POS。

vector为存储的对象分配一块连续的地址空间,因此对vector中的元素随机访问效率很高。在vecotor中插入或者删除某个元素,需要将现有元素进行复制,移动。如果vector中存储的对象很大,或者构造函数复杂,则在对现有元素进行拷贝时开销较大,因为拷贝对象要调用拷贝构造函数。对于简单的小对象,vector的效率优于list。vector在每次扩张容量的时候,将容量扩展2倍,这样对于小对象来说,效率是很高的。

list中的对象是离散存储的,随机访问某个元素需要遍历list。在list中插入元素,尤其是在首尾插入元素,效率很高,只需要改变元素的指针。

综上所述:

vector适用:对象数量变化少,简单对象,随机访问元素频繁

list适用:对象数量变化大,对象复杂,插入和删除频

 

vector 和 list 就好比 数组和链表一般, 一个是连续地址分布,一个是离散地址分布, 

vector 可以高效 随机访问成员, 通过下标即可,但是插入和删除,需要移动其余的所以成员, 访问成员高效, 删除和插入低效

list 是插入删除 成员高效, 但是访问低效 ,因为每次访问都需要遍历 list 就好像链表。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。