首页 > 代码库 > C++学习之路: STL探索 vector 和 list

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(); //1219     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 就好像链表。

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