list同样是序列式容器,可排序但是未排序。
list和vector相比较,list的优点是每次插入或删除一个元素,就会分配或释放一个元素都空间。因此,list对空间的运用有绝对的精准,一点儿也不浪费。而且,list对于任何位置的元素的插入或移除,时间复杂度永远是常数级。
下面我们从节点、迭代器、list结构、list 的constructor, push_back, insert、list元素的操作这五点进行分析。
1.节点
首先看一下list的节点(node)的定义
template <class T>
struct __list_node {
typedef void* void_pointer;
void_pointer prev; // 类型为 void*。其实可设为 __list_node<T>*
void_pointer next;
T data;
};
可以看到每个node有自己的数据,并且有前指针和后指针。
显然这个是一种双向链表。
值得注意的是,list的节点不保证在空间上是连续存储的。
2.迭代器
list有一个重要的特性,插入动作(insert)和接合动作(splice)都不会造成原有的list的迭代器失效。这在vector是不成立的,因为vector的插入动作造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的删除动作(erase),也只有【指向被删除元素】的那个迭代器失效,其他迭代器不受任何影响。
3.list的结构
正如前面提到的那样,list是个双向链表,但是不仅如此,它还是个环状链表,因此只需要一个指针就可以完成整个list的遍历。
4.list 的constructor, push_back, insert
话不多说,先看一下list的这三种基本操作
int i;
list<int> ilist;
cout << "size=" << ilist.size() << endl; // size=0
ilist.push_back(0);
ilist.push_back(1);
ilist.push_back(2);
ilist.push_back(3);
ilist.push_back(4);
cout << "size=" << ilist.size() << endl; // size=5
list<int>::iterator ite;
for (ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 1 2 3 4
cout << endl;
ite = find(ilist.begin(), ilist.end(), 3);
if (ite !=ilist.end())
ilist.insert(ite, 99);
cout << "size=" << ilist.size() << endl; // size=6
cout << *ite << endl; // 3
for (ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 1 2 99 3 4
cout << endl;
ite = find(ilist.begin(), ilist.end(), 1);
if (ite != ilist.end())
cout << *(ilist.erase(ite)) << endl; // 2
for (ite = ilist.begin(); ite != ilist.end(); ++ite)
cout << *ite << ' '; // 0 2 99 3 4
cout << endl;
输出:
list有许多constructors,其中的一个是default constructor,允许我们不指定任何参数做出一个空的list
当我们以 push_back() 將新元素安插于 list 尾端,此函数內部呼叫 insert() :
void push_back(const T& x) { insert(end(), x); }
而insert有多种重载类型,其中一下如下
// 函式目的:在迭代器 position 所指位置安插一个节点,內容为 x。
iterator insert(iterator position, const T& x)
由于 list 不像 vector 那样有可能在空间不足时做重新配置、资料搬移的动作,所以插入前的所有迭代器在插入动作之后都仍然有效。
5.list 的元素操作:push_front, push_back, erase, pop_front, pop_back,clear, remove, unique, splice, merge, reverse, sort
功能描述
// 安插一个节点,做为头节点
void push_front(const T& x) { insert(begin(), x); }
// 安插一个节点,做为尾节点(上一小节才介紹过)
void push_back(const T& x) { insert(end(), x); }
// 移除迭代器 position 所指节点
iterator erase(iterator position)
// 移除头结点
void pop_front() { erase(begin()); }
// 移除尾节点
void pop_back()
// 清除所有节点(整個链表)
template <class T, class Alloc>
void list<T, Alloc>::clear()
// 將数值为value 的所有元素移除
template <class T, class Alloc>
void list<T, Alloc>::remove(const T& value)
// 移除数值相同的连续元素。注意,只有「连续而相同的元素」,才会被移除剩一个。
template <class T, class Alloc>
void list<T, Alloc>::unique()
下图展示了移除值为1的节点
下面是splice、reverse、sort操作,输出即为注释。
int iv[5] = { 5,6,7,8,9 };
list<int> ilist2(iv, iv + 5);
// 目前,ilist 的內容為 0 2 99 3 4
ite = find(ilist.begin(), ilist.end(), 99);
ilist.splice(ite, ilist2); // 0 2 5 6 7 8 9 99 3 4
ilist.reverse(); // 4 3 99 9 8 7 6 5 2 0
ilist.sort(); // 0 2 3 4 5 6 7 8 9 99
// merge() 將 x 合并到 *this 身上。两个 lists 的內容都必须先经过递增排序。
template <class T, class Alloc>
void list<T, Alloc>::merge(list<T, Alloc>& x)
具体操作
int d1[5] = { 1,3,5,7,9 };
int d2[5] = { 2,4,6,8,10 };
list<int> list1(d1,d1+5);//前闭后开区间
list<int> list2(d2,d2+5);
list1.merge(list2);
list<int>::iterator it;
for (it = list1.begin(); it != list1.end(); ++it)
cout << *it << " ";
cout << endl;
输出: