欢迎前往我的个人博客阅读原文。
今天来学习 list 双向链表容器。list 容器实现了双向链表的数据结构,数据元素通过链表指针连成线性表(逻辑意义上的),从而,对链表任意位置上的元素进行插入、删除和查找操作都是极快速的。
list 每个节点有三个域:前驱元素指针域、数据域和后继元素指针域。前驱元素指针域保存的是前驱元素的首地址;数据域保存本节点的数据;后继元素指针域则保存后继元素的首地址。值得注意的是,list 的头节点的前驱元素指针域保存的是链表中尾元素的首地址,而 list 尾节点的后继元素指针域保存了头节点的指针域,从而构成了一个双向循环链。
另外,与 vector 不同的是,在使用迭代器的过程中,由于 list 对象的节点并不要求在一段连续的内存中,所以只能使用 ++
或者 --
操作将迭代器移动到后继或者前驱节点元素的位置,而不能使用 +n
或者 -n
的操作。
使用 list 需要声明头文件:
#include<list>
创建 list 对象
创建 list 对象有两种形式,一种直接创建一个空链表,另一种指出链表的元素个数。
- 创建空链表:
list<int> l;
- 创建具有 n 个元素的链表:
list<int> l(10);
元素插入和遍历
向链表中插入元素的方法和其他容器类似,有以下三种方法:
- 采用
push_back()
方法往尾部插入新元素,链表自动扩张; - 采用
push_front()
方法往首部插入新元素,链表自动扩张; - 采用
insert()
方法往迭代器位置插入新元素,链表自动扩张。
注意:迭代器只能进行
++
或--
操作,不能进行+n
或-n
的操作,因为元素的位置不是物理相连的。
#include<list>
#include<iostream>
using namespace std;
int main(int argc, char* argc[])
{
// 定义元素为整型的 list 对象,当前没有元素
list<int> l;
// 在链表尾部插入新元素,链表自动扩张
l.push_back(2);
l.push_back(1);
l.push_back(5);
// 在链表头部插入新元素,链表自动扩张
l.push_front(8);
// 在任意位置插入新元素,链表自动扩张
list<int>::iterator it;
it = l.begin();
it++; // 注意,链表的迭代器只能进行自加自减操作,而不能进行+n操作
l.insert(it, 20);
// 使用前向迭代器遍历链表
for (it = l.begin(); it != l.end(); it++)
cout << *it << ' ';
cout << endl;
return 0;
}
运行结果:
反向遍历
使用反向迭代器 reverse_iterator
对链表进行反向遍历。
#include<iostream>
#include<list>
using namespace std;
int main(int argc, char* argv[])
{
list<int> l;
l.push_back(2);
l.push_back(1);
l.push_back(5);
// 反向遍历链表
list<int>::reverse_iterator rit;
for (rit = l.rbegin; rit != l.rend(); rit++)
cout << *rit