list类模板
list列表实现为一个双向链表,因为同为序列式容器,所以它的对外接口大部分与vector和deque都相同,因此我们学习起来也比较容易。
1、创建对象
list类模板中也实现的了不同的的重载构造函数,因此也可以以不同的方式创建对象,创建对象的几种方式如下所示:
list<T> lt; //创建一个空的列表对象
list<T> lt(n); //创建一个列表对象,大小为n
list<T> lt(n, elem); //创建一个列表对象,包含n个elem元素
list<T> lt(begin, end); //创建一个列表对象,用[begin, end)区间的值为元素赋值
list<T> lt(lt1); //创建一个列表对象,用另一个对象初始化
创建list列表对象有这五种方式,接下来我们分别用这五种方式来创建list列表对象,代码如下所示:
list<char> lt1;
list<int> lt2(10);
list<float>lt3(10, 1.2);
list<string> lt4(begin, end);
list<float> lt5(lt3);
上述代码分别用五种不同方式创建了五个list列表对象,除了第一种形式,其他四种形式都指定了容器大小;第五种形式其实是一个拷贝构造函数,用一个对象初始化另一个对象。
2、赋值
和vector与deque一样,list列表也提供了assign()函数为列表容器赋值,函数调用如下所示:
lt.assign(n, elem); //将n个elem元素的值赋值给lt
lt.assign(begin, end); //用[begin, end)区间的值给lt中的元素赋值
在list列表中,assign()函数的用法和在vector与deque容器中一样,这里就不再举例说明。
3、元素访问
因为list列表是由链表实现的,内存区域并不是连续的,所以无法用[]运算符来访问元素,也没有可随机访问元素的at()方法,但它提供了下列函数可以访问容器中的元素:
lt.front(); //返回第一个元素
lt.back(); //返回最后一个元素
lt.begin(); //返回第一个元素的迭代器
lt.end(); //返回指向最后一个元素的下一个迭代器
这几个函数的用法和vector与deque的用法一样,front()与back()函数返回的元素的引用,而begin()与end()函数返回的是相应的迭代器。
4、添加元素
list提供了多个函数向容器中添加元素,函数调用如下所示:
lt.push_back(); //在尾部插入元素
lt.push_front(); //在头部插入元素
lt.insert(pos, elem); //在pos位置上插入元素elem
lt.insert(pos, n, elem); //在pos位置上插入n个元素elem
lt.insert(pos, begin, end); //在pos位置上插入[begin, end)区间的值作为元素
这些函数的用法与deque容器中的用法一样,即list列表容器可以头尾部添加元素也可以从中间添加元素。
5、删除元素
list列表也提供了多个函数从容器中删除元素,可以从头尾部删除元素,也可以删除中间某一个元素,函数调用形式如下所示:
lt.pop_back(); //从尾部删除元素
lt.pop_front(); //从头部删除元素
lt.erase(pos); //从中间删除元素
lt.erase(begin, end); //删除[begin, end)区间的元素
lt.remove(elem); //从容器中删除所有与elem匹配的元素
前四个函数在deque容器中都已经学习过,相信读者已经能熟练的使用。最后一个remove()函数,它是删除容器中所有与参数elem匹配的元素,接下来我们可以用一个案例来演示这些函数的使用,具体如例1所示。
例1
1 #include <iostream>
2 #include <list>
3 using namespace std;
4
5 template<typename T>
6 void print(list<T> mylist) //定义print()函数,输出list容器元素
7 {
8 list<T>::iterator it; //创建list列表的迭代器
9 for (it = mylist.begin(); it != mylist.end(); it++)
10 cout << *it << " ";
11 cout << endl;
12 }
13
14 int main()
15 {
16 list<int> lt;
17 for (int i = 0; i < 10; i++)
18 lt.push_back(i + 1); //向容器中添加元素
19 cout << "输出list容器中的元素:" << endl;
20 print(lt);
21 lt.pop_back(); //删除最后一个元素
22 lt.push_front(5); //在头部添加元素5
23
24 cout << "再次输出list容器中的元素:" << endl;
25 print(lt);
26 lt.remove(5);
27 cout << "删除5之后,输出list容器中的元素:" << endl;
28 print(lt);
29 system("pause");
30 return 0;
31 }
运行结果如图1所示。
图1 例1运行结果
在例1中,定义了一个list列表容器,并且定义了一个输出列表元素的函数print()函数,代码17-20行,向lt容器中添加元素并输出,由图1可知,元素添加成功。代码21行删除末尾元素,22行代码在头部添加元素5,然后输出元素,由图1可知,再次输出的list容器元素时末尾的10被删除,头部又新增元素5。代码26行调用remove()函数删除容器中所有的5,由图1可知,5被成功删除。
6、merge()函数与sort()函数
函数merge()可以将两个列表容器合并,函数的功能是把一个list对象作为参数插入到目标list容器中,其调用形式如下所示:
lt.merge(list& lt1);
两个容器合并后,容器中的元素按从小到大排列,而且合并之后,lt1容器会变为一个空的容器。list容器还提供了具有排序功能的成员函数sort(),其函数调用如下所示:
lt.sort();
sort()函数使容器中的元素按从小到大的顺序排列。接下来我们通过一个案例来演示这两个函数的用法,具体如例2所示。
例2
1 #include <iostream>
2 #include <list>
3 using namespace std;
4
5 template<typename T>
6 void print(list<T> mylist) //定义print()函数,输出list容器元素
7 {
8 list<T>::iterator it; //创建list列表的迭代器
9 for (it = mylist.begin(); it != mylist.end(); it++)
10 cout << *it << " ";
11 cout << endl;
12 }
13
14 int main()
15 {
16 list<int> lt1, lt2;
17 lt1.push_back(12);
18 lt1.push_back(6);
19 lt1.push_back(32);
20 lt2.push_front(45);
21 lt2.push_front(9);
22 cout << "lt1:";
23 print(lt1);
24 cout << "lt2:";
25 print(lt2);
26 //对lt1容器排序
27 lt1.sort();
28 cout << "lt1排序之后:";
29 print(lt1);
30 //合并两个容器
31 lt1.merge(lt2);
32 cout << "合并两个容器后:";
33 print(lt1);
34 system("pause");
35 return 0;
36 }
运行结果如图2所示。
图2 例2运行结果
在例2中,定义了两个list容器lt1与lt2,分别向两个容器中随机添加元素,然后输出两个容器中的元素,第27-29行代码调用sort()函数对lt1容器排序,由图8-10的输出结果可知,lt1中的元素实现了从小到大的排序;代码31行又调用merge()函数将两个list容器合并,由图8-10的输出结果可知,两个容器合并成功,并且合并后的元素是按从小到大的顺序排列的。
7、splic()函数
上面讲解的merge()函数可以合并两个list容器,但它有局限性,合并的元素从打乱顺序重新排列,有时合并两个容器的元素只想直到“插队”,而不想重新“排队”。为此,list提供了另外一个函数splice(),该函数用于连接两个list对象,其调用形式如下所示:
lt.splice(iterator it, list& lt1);
lt.splice(iterator it, list& lt1, iterator first);
lt.splice(iterator it, list& lt1, iterator first, iterator last);
● 第一种形式是将容器lt1插入到迭代器it指示的位置前;
● 第二种形式是将lt1中的元素first(first迭代器指示的元素)插入到迭代器it指示的位置前;
● 第三种形式是将lt1容器中[first, last)区间的元素插入到迭代器it指示的位置前面。
与merge()函数一样,一旦合并完成,则lt1中的元素就是被“移走”,即lt1中不再有这些元素,如第一种形式splic()合并,合并之后,lt1容器就变成一个空的容器。
接下来我们通过修改例2来演示splice()函数的用法,具体如例3所示。
例3
1 #include <iostream>
2 #include <list>
3 using namespace std;
4
5 template<typename T>
6 void print(list<T> mylist) //定义print()函数,输出list容器元素
7 {
8 list<T>::iterator it; //创建list列表的迭代器
9 for (it = mylist.begin(); it != mylist.end(); it++)
10 cout << *it << " ";
11 cout << endl;
12 }
13
14 int main()
15 {
16 list<int> lt1, lt2, lt3;
17 lt1.push_back(12);
18 lt1.push_back(6);
19 lt1.push_back(32);
20 lt2.push_front(45);
21 lt2.push_front(9);
22 lt3.push_back(100);
23 lt3.push_back(2);
24 lt3.push_back(11);
25 cout << "lt1:";
26 print(lt1);
27 cout << "lt2:";
28 print(lt2);
29 cout << "lt3:";
30 print(lt3);
31 //调用splice()函数将lt2中的第一个元素插入到lt1末尾
32 lt1.splice(lt1.end(), lt2, lt2.begin());
33 cout << "lt1与lt2合并后,lt1: ";
34 print(lt1);
35 cout << "lt1与lt2合并后,lt2: ";
36 print(lt2);
37 //将lt3容器插入到lt1容器前面
38 lt1.splice(lt1.begin(), lt3);
39 cout << "lt1与lt3合并后,lt1: ";
40 print(lt1);
41 cout << "lt1与lt3合并后,lt3: ";
42 print(lt3);
43 system("pause");
44 return 0;
45 }
运行结果如图3所示。
图3 例3运行结果
在例3中,定义了三个list列表容器,然后向其中添加元素,各个容器中元素如图8-11所示。代码32行将lt2容器中的第一个元素9插入到了lt1容器末尾,由图8-11可知,插入成功。代码38行将lt3容器中的所有元素插入到lt1头部,由图3可知,元素插入成功。