List双向链表容器

来源:互联网 发布:c2c商城系统源码 编辑:程序博客网 时间:2024/04/29 18:04

List双向链表容器

一、原理

list是双向链表的一个泛化容器。作为一种序列容器,它的数据元素可通过链表指针串接成逻辑意义上的线性表。不同于采用线性表顺序存储结构的vectordeque容器,list双向链表中任一位置的元素查找、插入和删除,都具有高效的常数阶算法时间复杂度O1)。

为了支持前向和反向访问 list 容器的元素,如图所示,list 采用双向循环的链表结构组织数据元素。

53、List双向链表容器 - EdwardLewis - 墨涵天地

      53、List双向链表容器 - EdwardLewis - 墨涵天地

下面是几个内置函数的实现示意:

1void transfer(iterator position, iterator first, iterator last),将在当前链表的position位置前,插入另一个链表的迭代器区间[first, last]的元素,而这部分元素又从该链表中抹去。如图所示,上层为当前链表,position指向第4个元素,下层为插入归并的链表,[first,last]是指中间的3个元素。

53、List双向链表容器 - EdwardLewis - 墨涵天地53、List双向链表容器 - EdwardLewis - 墨涵天地

2、另一个list的归并函数为splice函数。它调用transfer函数将一个链表的所有元素全部归并到当前链表,并将归并的链表清空,或将迭代器所指的一个元素归并到当前链表,而该元素从原来所在的链表中抹去。 

3merge 函数对两个链表进行归并,要求两个链表预先排序,否则 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); 

} 

4list容器的sort成员函数是针对 list容器的元素排序的(与STL中的sort算法函数不同,sort算法只对随机迭代器有效,不能用于链表容器的元素排序)。listsort函数代码,可算是一种多路归并算法的一个实现。它不断从list链表中读取一个元素数据,然后排序归并到counter[i]链表中。最后,调用 merge 和 swap 函数,归并回list链表中,完成对list所有元素的排序。如下所示:

//listsort()函数

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(< 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 (== fill) ++fill; 

    }  

    //对已排序的counter[i]进行归并

    for (int i = 1; i < fill; ++i) 

      counter[i].merge(counter[i-1]); 

      swap(counter[fill-1]); //交换到list

    } 

} 

二、应用

1、创建

1list() 

创建一个没有任何元素的list对象。此构造函数是list(const A& a = A())的一个默认调用方式,其中A为内存分配器。

list<int> l;//创建了空的list对象l

2list(size_type n) 

创建一个链接有 个元素的 list 对象,每个元素采用它的类型下的默认值 

list<int> l(10);//创建了具有10个元素的list对象l,每个元素初始值为0

3list(size_type n, const T& value) 

创建一个链入了n个元素的list对象,这些元素的初始值均为value

list<double> l(10, 9.3);//创建了一个具有10个元素的list对象l,每个元素的初始值为9.3

4list(const list&) 

list拷贝构造函数,通过拷贝一个list对象的元素,创建一个新的list对象。此时,新旧list容器的元素对应相等。

list<char> l1(5, k); 

list<char> l2(l1);//使用list对象l1,创建另一个list对象l2l2对象的5个元素也具有字符值’k

5list(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);//将数组iArray3个整数插入到链表中,创建list对象l

2、插入

1push_back函数,可将元素数据依次链入链表中(插入尾部)。push_back函数常用于list容器的初始化。 

void push_back(const T&)

2push_front函数,可将元素数据插入链表首部中

void push_front(const T&)

3)在任意迭代器位置插入的insert()函数

iterator insert(iterator pos, const T& x) 

3、访问

1iterator begin() 

2iterator end() 

3reverse_iterator rbegin()

4reverse_iterator rend()

4、删除

1void pop_front() 

删除list的第一个链表元素。 

2void pop_back() 

删除list的最后一个链表元素。 

3iterator erase(iterator pos) 

删除pos所指向的链表元素。 

4iterator erase(iterator first, iterator last) 

删除迭代器区间[first,last)所指向的所有链表元素。 

5void clear() 

删除所有的list链表元素。 

6void remove(const T& value) 

删除list链表中所有元素值为value的元素。

5、交换

    swap通过简单地交换两个list的头指针,来实现list元素的交换。交换后的list将具有另一个list的链表元素。 

void swap(list&)

6、归并

   list链表元素的排序,是将list链表分割成若干部分进行子排序,然后通过归并处理,实现list的所有元素的排序。list容器提供了splicemerge归并函数。 

1void splice(iterator position, list& x) 

x的链表归并到当前list链表的position位置之前,list对象x将被清空。 

2void splice(iterator position, list&, iterator i)   

将一个list的迭代器i值所指的元素,归并到当前list链表中,并将被归并的元素从原链表中删除。 

3void 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函数是比较大小的,如果元素没有可比较的意义,那么这两个函数也就没有意义了。