1、基本概念
相比vector的连续线性空间,list的内部空间是不连续的。STL的list实现是一个双向链表,因而其每个元素必须包含一个指向前一个节点的指针和一个指向后一个节点的指针。优点是插入和删除的代价比vector低的多,同时占用空间需要多少创建多少,空间利用率高;缺点是维护额外的指针需要消耗一定的空间。
2、迭代器
list提供的迭代器能够向前和向后访问,但无法进行算术运算,只能递增和递减,因而是一个双向迭代器。
3、基本用法
我们可以看下下面的测试代码:
list<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
list<int>::iterator i;
for (i=a.begin();i!=a.end();++i)
{
cout<<*i<<" "; //1 2 3 4 5
}
cout<<endl;
i = find(a.begin(), a.end(), 3);
if (i != a.end())
{
a.insert(i, 99);
}
for (i=a.begin();i!=a.end();++i)
{
cout<<*i<<" "; //1 2 99 3 4 5
}
cout<<endl;
i = find(a.begin(), a.end(), 2);
if (i != a.end())
{
cout<<*(a.erase(i))<<endl; //99
}
通过log,我们可以知道list在插入元素时是插到迭代器所指元素的前面,而删除是返回指定元素的下一个位置。
4、特殊考虑
list不但是一个双向链表,而且是一个循环列表,只需要一个指针,便可以完整表现整个链表。list在创建时,会创建一个空白节点,作为链表的end节点。同时,list头节点的前驱指针会指向该空白节点,空白节点的后驱指针指向头节点,从而形成环状结构。如以下测试代码:
list<int> b;
b.push_back(1);
b.push_back(2);
list<int>:: iterator x;
x = b.begin();
--x; //list iterator not decrementable
cout<<*x<<endl; //-1163005939
--x;
cout<<*x<<endl; //2
--x;
cout<<*x<<endl; //1
这段代码在debug下运行时报错,这是由于list的内部在debug模式下并不允许迭代器在begin位置还能继续向前移动,但在release下是正常的。
由log可以看出,通过某一位置的迭代器,可以遍历整个链表,证明list内部是环形链表,但是要注意end节点是空白节点,获取其值是无意义的。