List双向链表容器
一、原理
list是双向链表的一个泛化容器。作为一种序列容器,它的数据元素可通过链表指针串接成逻辑意义上的线性表。不同于采用线性表顺序存储结构的vector和deque容器,list双向链表中任一位置的元素查找、插入和删除,都具有高效的常数阶算法时间复杂度O(1)。
为了支持前向和反向访问 list 容器的元素,如图所示,list 采用双向循环的链表结构组织数据元素。
下面是几个内置函数的实现示意:
1、void transfer(iterator position, iterator first, iterator last),将在当前链表的position位置前,插入另一个链表的迭代器区间[first, last]的元素,而这部分元素又从该链表中抹去。如图所示,上层为当前链表,position指向第4个元素,下层为插入归并的链表,[first,last]是指中间的3个元素。
2、另一个list的归并函数为splice函数。它调用transfer函数将一个链表的所有元素全部归并到当前链表,并将归并的链表清空,或将迭代器所指的一个元素归并到当前链表,而该元素从原来所在的链表中抹去。
3、merge 函数对两个链表进行归并,要求两个链表预先排序,否则 merge 归并没有太大意义。merge函数归并出一个已排序的新链表。
//merge()函数
template <class T, class Alloc>
void list<T, Alloc>::merge(list<T, Alloc>& x) //归并
{
iterator first1 = begin();
iterator last1 = end();
iterator first2 = x.begin();
iterator last2 = x.end();
while (first1 != last1 && first2 != last2)
if (*first2 < *first1) {
iterator next = first2;
transfer(first1, first2, ++next);
first2 = next;
}
else
++first1;
if (first2 != last2) transfer(last1, first2, last2);
}
4、list容器的sort成员函数是针对 list容器的元素排序的(与STL中的sort算法函数不同,sort算法只对随机迭代器有效,不能用于链表容器的元素排序)。list的sort函数代码,可算是一种多路归并算法的一个实现。它不断从list链表中读取一个元素数据,然后排序归并到counter[i]链表中。最后,调用 merge 和 swap 函数,归并回list链表中,完成对list所有元素的排序。如下所示:
//list的sort()函数
template <class T, class Alloc>
void list<T, Alloc>::sort()
{
//多于个元素
if (M_node->M_next != M_node && M_node->M_next->M_next != M_node) {
list<T, Alloc> carry;
list<T, Alloc> counter[64];
int fill = 0;
while (!empty()) {
carry.splice(carry.begin(), *this, begin()); //不断从list读取个数据
int i = 0;
while(i < fill && !counter[i].empty()) { //i<fill 和counter[i]不为空
counter[i].merge(carry); carry.swap(counter[i++]); //相当于carry.swap(counter[i]); i++;
}
carry.swap(counter[i]);
if (i == fill) ++fill;
}
//对已排序的counter[i]进行归并
for (int i = 1; i < fill; ++i)
counter[i].merge(counter[i-1]);
swap(counter[fill-1]); //交换到list中
}
}
二、应用
1、创建
(1)list()
创建一个没有任何元素的list对象。此构造函数是list(const A& a = A())的一个默认调用方式,其中A为内存分配器。
list<int> l;//创建了空的list对象l
(2)list(size_type n)
创建一个链接有 n 个元素的 list 对象,每个元素采用它的类型下的默认值
list<int> l(10);//创建了具有10个元素的list对象l,每个元素初始值为0
(3)list(size_type n, const T& value)
创建一个链入了n个元素的list对象,这些元素的初始值均为value。
list<double> l(10, 9.3);//创建了一个具有10个元素的list对象l,每个元素的初始值为9.3
(4)list(const list&)
list拷贝构造函数,通过拷贝一个list对象的元素,创建一个新的list对象。此时,新旧list容器的元素对应相等。
list<char> l1(5, ’k’);
list<char> l2(l1);//使用list对象l1,创建另一个list对象l2。l2对象的5个元素也具有字符值’k’
(5)list(InputIterator first, InputIterator last)
将另一个list对象的迭代器区间[first,last)所指的元素,拷贝到新创建的list对象中。它是更完整的list(const InputIterator first, const InputIterator last, const A& a=A())构造函数的一个省略写法。
int iArray[] = {19, 13, 38};
list<int> l(iArray, iArray + 3);//将数组iArray的3个整数插入到链表中,创建list对象l
2、插入
1)push_back函数,可将元素数据依次链入链表中(插入尾部)。push_back函数常用于list容器的初始化。
void push_back(const T&)
2)push_front函数,可将元素数据插入链表首部中
void push_front(const T&)
3)在任意迭代器位置插入的insert()函数
iterator insert(iterator pos, const T& x)
3、访问
(1)iterator begin()
(2)iterator end()
(3)reverse_iterator rbegin()
(4)reverse_iterator rend()
4、删除
(1)void pop_front()
删除list的第一个链表元素。
(2)void pop_back()
删除list的最后一个链表元素。
(3)iterator erase(iterator pos)
删除pos所指向的链表元素。
(4)iterator erase(iterator first, iterator last)
删除迭代器区间[first,last)所指向的所有链表元素。
(5)void clear()
删除所有的list链表元素。
(6)void remove(const T& value)
删除list链表中所有元素值为value的元素。
5、交换
swap通过简单地交换两个list的头指针,来实现list元素的交换。交换后的list将具有另一个list的链表元素。
void swap(list&)
6、归并
list链表元素的排序,是将list链表分割成若干部分进行子排序,然后通过归并处理,实现list的所有元素的排序。list容器提供了splice和merge归并函数。
(1)void splice(iterator position, list& x)
将x的链表归并到当前list链表的position位置之前,list对象x将被清空。
(2)void splice(iterator position, list&, iterator i)
将一个list的迭代器i值所指的元素,归并到当前list链表中,并将被归并的元素从原链表中删除。
(3)void merge(list& x)
将list对象x的链表归并到当前list链表中,并清空x的链表。只有当前list链表和被归并的x链表的元素,均预先按元素值的“<”关系排好序,merge函数才具有意义,归并后的链表元素也是按“<”关系排序的。
7、排序
void sort函数,按“<”关系进行list链表元素排序,较小的元素排在前面。
8、连续重复元素的剔除
void unique函数,可将连续重复的元素删除,仅保留一个
三、例子
#include "iostream"
#include "list"
using namespace std;
struct student{
char* name;
int age;
};
int main()
{
student s[]={
{"me",14},
{"you",12},
{"he",12},
{"she",12}
};
list<student> L;
L.push_back(s[0]);
L.push_back(s[1]);
L.push_back(s[2]);
//L.push_back(s[3]);
list<student>::iterator i,iend;
iend=L.end();
cout<<"Name "<<"年龄"<<endl;
for(i=L.begin();i!=iend;i++)
cout<<(*i).name<<" "
<<(*i).age<<" "<<endl;
cout<<endl;
cout<<"Another stage:"<<endl;
i=L.begin();
L.insert(i,s[3]);
for(i=L.begin();i!=iend;i++)
cout<<(*i).name<<" "
<<(*i).age<<" "<<endl;
cout<<endl;
cout<<"Another stage:"<<endl;
i=L.begin();
L.erase(i);
for(i=L.begin();i!=iend;i++)
cout<<(*i).name<<" "
<<(*i).age<<" "<<endl;
cout<<endl;
cout<<"Another stage:"<<endl;
list<student> L2;
L2.splice(L2.begin(),L);
for(i=L2.begin();i!=L2.end();i++)
cout<<(*i).name<<" "
<<(*i).age<<" "<<endl;
cout<<endl;
return 1;
}
说明:最后再说明一次,merge函数和sort函数是比较大小的,如果元素没有可比较的意义,那么这两个函数也就没有意义了。