STL容器:list

1. 概述
STL::list是STL最常用的容器之一,其本质上是一个双向环状链表,链表每一个结点内容如下:
template
struct __list_node {
typedef void* void_pointer;
void_pointer next; // 指向下一个节点的指针
void_pointer prev; // 指向前一个节点的指针
T data; //list 数据
};
由于其双链表的结构,因此list适合需要频繁插入和删除数据的场合,这个和vector刚好相反。

2. API

Member functions
(constructor)    Construct list (public member function)
(destructor)    List destructor (public member function)
operator=    Copy container content (public member function)

Iterators:
begin    Return iterator to beginning (public member function)
end    Return iterator to end (public member function)
rbegin    Return reverse iterator to reverse beginning (public member function)
rend    Return reverse iterator to reverse end (public member function)

Capacity:
empty    Test whether container is empty (public member function)
size    Return size (public member function)
max_size    Return maximum size (public member function)
resize    Change size (public member function)

Element access:
front    Access first element (public member function)
back    Access last element (public member function)

Modifiers:
assign    Assign new content to container (public member function)
push_front    Insert element at beginning (public member function)
pop_front    Delete first element (public member function)
push_back    Add element at the end (public member function)
pop_back    Delete last element (public member function)
insert    Insert elements (public member function)
erase    Erase elements (public member function)
swap    Swap content (public member function)
clear    Clear content (public member function)

Operations:
splice    Move elements from list to list (public member function)
remove    Remove elements with specific value (public member function)
remove_if    Remove elements fulfilling condition (public member function template)
unique    Remove duplicate values (member function)
merge    Merge sorted lists (public member function)
sort    Sort elements in container (public member function)
reverse    Reverse the order of elements (public member function)

Allocator:
get_allocator    Get allocator (public member function)

Member types
of template > class list;
member type    definition
reference    Allocator::reference
const_reference    Allocator::const_reference
iterator    Bidirectional iterator
const_iterator    Constant bidirectional iterator
size_type    Unsigned integral type (usually same as size_t)
difference_type    Signed integral type (usually same as ptrdiff_t)
value_type    T
allocator_type    Allocator
pointer    Allocator::pointer
const_pointer    Allocator::const_pointer
reverse_iterator    reverse_iterator
const_reverse_iterator    reverse_iterator

3. 内存分配
相比于vector,list内存分配策略简单,每插入一个新元素,则new一个新结点,删除一个元素,则delete这个结点。需要注意的是,由于list的每一个结点除了包含对应的数据,还包含指向上一个和下一个元素的指针,因此,在资源紧张的环境下,这块占用的内存需要考虑。
list和vector占用内存对比:
如下程序:

list mylist;
cout << sizeof(int) <<<="" sizeof(int*)="" endl;<="" p="">
for(int i = 0; i < 1000000; i++)
{
       mylist.push_back(i);
}
cout << "push ok" << endl;
sleep(1000);


vector myvector;
cout << sizeof(int) <<<="" sizeof(int*)="" endl;<="" p="">
for(int i = 0; i < 1000000; i++)
{
       myvector.push_back(i);
}
cout << "push ok" << endl;
sleep(1000);

对比程序消耗的内存,会发现在数据对象本身比较小的情况下,list额外消耗还是比较恐怖的。

4. list使用范例
list插入、删除、遍历操作

#include
#include
using namespace std;
int main ()
{
  list mylist (20,100);  // two ints with a value of 100  mylist.push_front (200);  //表头插入
  mylist.push_back (300);  //表尾插入 
 
  //删除元素
  list::iterator it = mylist.begin();
  mylist.erase(it);
 
  //遍历输出  
  for (list::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << " " << *it;
  cout << endl;
  return 0;
}

5. list有趣的API
1)splice
void splice ( iterator position, list& x );
void splice ( iterator position, list& x, iterator i );
void splice ( iterator position, list& x, iterator first, iterator last );
splice可以将一个list的元素搬到另一个list,避免了先删后插的做法,在数据元素比较大的情况下,还是相当高效的。
splice提供多个接口,可以搬移单个元素,部分元素or整个list

示例:

list mylist1, mylist2;
list::iterator it;
for(int i = 0; i < 5; i++)
{
    mylist1.push_back(i);
}
//mylist1的数据插入mylist2
it = mylist2.begin();
mylist2.splice(it,mylist1);
cout << "list1: " << endl;
for (list::iterator it=mylist1.begin(); it!=mylist1.end(); ++it)
    cout << *it << endl;
cout << "list2: " << endl;
for (list::iterator it=mylist2.begin(); it!=mylist2.end(); ++it)
    cout << *it << endl;

2)remove & remove_if
void remove ( const T& value );

template
void remove_if ( Predicate pred );

remove删除list中所有值为value的数据;
remove_if删除Predicate pred返回为真的元素,pred可以为函数或者类

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }
// a predicate implemented as a class:
class is_odd
{
public:
  bool operator() (const int& value) {return (value%2)==1; }
};
int _tmain(int argc, _TCHAR* argv[])
{
    list mylist;
    for(int i = 0; i < 20; i++)
    {
        mylist.push_back(i);
    }
    mylist.remove(10);
    mylist.remove_if(single_digit);
    mylist.remove_if(is_odd());
    for (list::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    {
        cout << *it << endl;
    }
    system("pause");
    return 0;
}

6. list使用注意

1)list::size()时间复杂度
SGI list::size()源码:
size_type size() const {
  size_type __result = 0;
  distance(begin(), end(), __result);
  return __result;
}
注意,不是直接返回一个值,而是使用了distance(begin(), end(), __result);因此,推测其复杂度为0(n).写一个程序测试下:

list mylist;
clock_t start,end;
//push10000个数据,得到运行时间T1
start = clock();
for(int i = 0; i < 10000; i++)
{
    mylist.push_back(i);
}
end = clock();
cout << (end-start) << endl;
//push10000个数据,并计算size,得到运行时间T2
start = clock();
for(int i = 0; i < 10000; i++)
{
    mylist.push_back(i);
    mylist.size();
}
end = clock();
cout << (end-start) << endl;

 

在win7,VS2010下,输出:
37
38

linux 2.6.9 gcc 3.4.5,输出:
0
104900000


并不是所有编译器下size的实现都是通过distance得到,vs对这部分实现做了优化。

2)list迭代器失效
由于list本质是一个双向链表,所以,增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。
list删除元素时正确的写法:

for(list::iterator it=mylist.begin();it!=mylist.end();)
{
    if(*it == 5)
        mylist.erase(it++);
    else
        it++;
} 


崩溃写法
for (list::iterator it=mylist.begin(); it!=mylist.end(); ++it)
{
    if(*it == 5)
        mylist.erase(it);
} 

7. 总结

list本质是一个双向环形链表,所以其不能随机访问一个元素。在开头、末尾和中间任何地方增加或删除元素所需时间都为常量。list可以动态增加或减少元素,内存管理自动完成。


转载于:https://my.oschina.net/zipu888/blog/549580

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值