C++容器用法简介——list

本文翻译自cplusplus,介绍了C++中的list容器,重点讲解了其作为双向链表的特性,如常量时间插入删除操作,以及各种元素操作函数的使用,包括构造、迭代器、容量、元素访问、修改等。尽管list不支持随机访问,但适用于需要频繁插入和删除的场景。
摘要由CSDN通过智能技术生成

C++容器用法简介——list

翻译自cplusplus

原文链接

一、简介

        List是一种的顺序容器,它允许你在任何地方以常量的时间完成插入或者删除操作(因为链表在删除或增加的的时候只是简单的修改一下指针的指向,是在O(1)的时间内完成的),List的迭代器是双向的。

        List容器在实现上采用双向链表,这种链表能存储一些位置不同且不相关的元素(这里原文没看懂随便翻译的啦~),元素通过自己的指针域来指向下一个结点,或者上一个结点,通过这种方式可以使链表保持一定的顺序。

        List容器和forward_listC++11以上版本新增的)很像,唯一的区别是forward_list是单向链表,所以forward_list的迭代器是单向的,不过forward_list拥有更小的存储空间和更高的效率(因此我们在使用链表的时候,如果明确知道这是一个单向的链表应该优先使用forward_list

       和其他的标准顺序容器(比如array(数组 C++11),vector(向量),deque(双端队列))相比,List获得迭代器的时候(实际上就是当指针指向这个地方的时候,如果迭代器没有到位,实际上这些操作时间复杂度也是O(n),因为你首先需要找到它们,原因在一下段中给出了),在任何位置的插入,移动,获取元素操作会更加的高效。所以在算法中经常出现,比如排序算法(不知道这里的algorithms,是指常规意义的算法还是说algorithm这个头文件

       但是,不管是List还是forward_list和其他顺序容器相比,它们失去了随机读取的特性,例如:为了访问列表里面的第6个元素,你不得不花费线性(时间复杂度O(n))的时间,使用迭代器从List的某个已知位置(头或者尾这种地方)一直循环到这里。另外由于需要存储下一个结点或者上一个结点的位置信息,需要单独使用一个或者多个指针,会消耗过多的内存空间。尤其是使用大的链表存储小容量的数据时。(比如在链表中每个结点放置一个char,指针所占的空间已经超过数据了,指针的大小一般是4个字节,64位的电脑的话应该是8个字节,但是一个char才1个字节

二、容器特点

1.序列

每个List里面都是严格的线性顺序,每个元素可以通过它们的位置来访问。

2.双向链表

每个元素都存储了关于下一个和上一个元素位置的信息,允许在常数时间内对特定的元素完成插入和删除操作(甚至是整个链表),但是不能随机访问(比如数组a[1]

3.动态内存分配

List通过动态内存分配需要的存储空间(C++的new,或者是C语言的malloc

三、函数用法示例

1、构造与析构(C++11版本)

const allocator_type& alloc = allocator_type()这句话是STL里面为了合理分配空间定义的类,作为默认参数,如果需要使用自己的分配方式请参阅std::allocator

//default (1)	
//构造一个空的链表。
explicit list (const allocator_type& alloc = allocator_type());
list<int>list1;


//fill (2)	
//构造一个拥有n个元素的链表,每个元素的值为val(如果提供的话,没有一般就是按照全局变量的方式初始化)
explicit list (size_type n);
         list (size_type n, const value_type& val,
                const allocator_type& alloc = allocator_type());
list<int>list2(10);      //0->0->0->......->0
list<int>list2(10, 1);  //1->1->1->.......->1


//range (3)	
//从区域<tt>[first,last)</tt>中构造一个链表,顺序保持不变
template <class InputIterator>
  list (InputIterator first, InputIterator last,
         const allocator_type& alloc = allocator_type());
int num[] = {1, 2, 3, 4};
list<int>list3(num, num + 2);    //1->2

//copy (4)	
//从另一个链表中复制相同的元素,且顺序不变,拷贝构造函数
list (const list& x);
list (const list& x, const allocator_type& alloc);
list<int>list4_1(10, 1);
list<int>list4_2(list4_1);


//move (5)	
//C++11提供的move语义,可以是效率更高,避免复制
list (list&& x);
list (list&& x, const allocator_type& alloc);

//initializer list (6)	
//C++11允许构造函数和其他函数把初始化列表当做参数。
list (initializer_list<value_type> il,
       const allocator_type& alloc = allocator_type());
//list<int>list6 = {1, 2, 3, 4, 5, 6}; 

2.迭代器函数

2.1 begin()

返回容器中第一个元素的迭代器,和front()不同,begin()返回的只是一个指向第一个元素的双向迭代器而已,如果容器为空返回的迭代器是无效的。

例如:

    list<int>l1 = {1, 2, 3, 4, 5};
    cout << *l1.begin() << endl;   //输出1
2.2 cbegin()

返回一个const_iterator,与前者的区别是const_iterator只能用于指向容器中的元素但是不能修改它,实际上begin是一个重载函数,当容器中数据是const时,自动返回const_iterator,但是cbegin()只能返回const_iterator

    list<int>l1 = {1, 2, 3, 4, 5};
    cout << *l1.cbegin() << endl;   //输出1
    *l1.begin() = 2;
    cout << *l1.begin() << endl;    //输出2
    *l1.cbegin() = 1;      //error error: assignment of read-only location
2.3 end()与cend()
返回一个超过容器中最后一个元素的位置迭代器,所以事实上不指向任何元素,返回的引用不可用,( 之所以返回一个指向最后一个元素后一个的迭代器,事实上可以简化计算,理由参考链接,其实可以发现在很多编程语言里面都是使用前闭后开区间), end()一般和 begin()
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值