【C++】list详解、list与vector的对比

一、list的介绍和使用

1.1 list的介绍

  1. list 是一个允许在常数时间( O(1) )内进行任意位置插入/删除操作的顺序容器,并且该容器可以前后双向迭代。
  2. list 的实现方法类似于双向链表:双向链表在不同的且没有关联的存储空间存储每一个元素,但是每个元素保持链接着它的前一个和后一个元素。
  3. list 的实现方法也类似于双向链表:他们最大的不同是单链表是单向的链表,每一个元素只链接着其后一个元素。单链表只能朝前迭代,所以它规模更小也更高效。
  4. 相较于其它基础的标准顺序容器(arrayvector and deque),list 在任意位置的插入/删除/移动元素效率更高
  5. list 相较于其他顺序容器而言,最主要的缺点就是它不支持任意位置的随机访问。例如去访问list的第六个元素,就必须从一个已知的位置(例如开始或结尾)迭代到这个位置。
    不仅查找元素需要线性的时间,list 也需要消耗一些额外的空间去保证每个元素与它相邻元素的链接。

1.2 list的使用

由于C++引入了STL(标准模板库)的概念,list、vector这些模板类提供了类似的接口,通过之前对vector的学习,相信你也会很快地学会list的使用和其背后的原理。

1.2.1 构造函数、析构函数和赋值重载

std::list::list

  • list()         无参构造,构造空的list。
  • list (size_type n, const value_type& val = value_type())   用n个val填充构造的list
  • list (const list& x)    拷贝构造
  • list (InputIterator first, InputIterator last)
    用两个迭代器(first, last)区间之间的值填充一个构造的list。(区间左闭右开)

 std::list::~list

  •  ~list();        销毁容器对象

 std::list::operator=

  •  list& operator= (const list& x);        
    分配一个新容器(新容器对x拷贝构造),替换当前的容器,相应地修改容器的大小

 1.2.2 Iterators:

  • begin       返回指向list第一个元素的迭代器。
    iterator begin(); const_iterator begin() const;
  • end          返回指向list最后一个元素下一个位置(即end位置)的迭代器。
    iterator end(); const_iterator end() const;
  • rbegin     返回指向list最后一个元素的迭代器。
    reverse_iterator rbegin(); const_reverse_iterator rbegin() const;
  • rend        返回指向list第一个元素前一个位置(即end位置)的迭代器。
    reverse_iterator rend(); const_reverse_iterator rend() const;

 注: end() 和 rend() 指向的是同一个位置,因为list是有头节点的双向环型链表。

 1.2.3 Capacity:

  • size           返回容器元素个数
    size_type size() const;
  • empty       判断容器是否为空
    bool empty() const;

1.2.4 Element access

  • front        访问第一个元素
    reference front(); const_reference front() const;
  • back        访问最后一个元素
    reference back(); const_reference back() const;

1.2.5 Modifiers:

  • push_front         在list首元素前插入值为val的元素
    void push_front (const value_type& val);
  • pop_front           删除list中第一个元素
    void pop_front();
  • push_back         在list尾部插入值为val的元素
    void push_back (const value_type& val);
  • pop_back           删除list中最后一个元素
    void pop_back();
  • insert                  在list position 位置中插入值为val的元素
    iterator insert (iterator position, const value_type& val);
  • erase                  删除list position位置的元素
    iterator erase (iterator position);   iterator erase (iterator first, iterator last);
  • swap                  交换两个list中的元素
    void swap (list& x);
  • clear                   清空list中的有效元素
    void clear();

 1.2.6 Operations:

  • unique        移除重复的元素
    void unique();
  • sort             对容器内元素排序
    void sort();

注:

  1. unique() 移除list中每一组相等的连续元素,只留下各组的第一个元素,而不是移除所有相等元素只留下一个。
    例如122333444221,unique()之后为123421。
  2. sort() 排序效率不是很高。

二、list与vector的对比

2.1 迭代器的种类

iterator

definition

list

random access iterator to value_type

vector

bidirectional iterator to value_type

  • 迭代器从功能上分类,可以分成正向迭代器反向迭代器,又能根据const再次分成四种 :iterator、const_iterator、reverse_iterator、const_reverse_iterator。
  • 迭代器从性质上分类,可以分成单向迭代器、双向迭代器和随机迭代器。
  • 单向迭代器(forward iterator)支持++操作,例如forward_list
    双向迭代器(
    bidirectional iterator)支持++、--操作,例如list
    随机迭代器(
    random access iterator)支持+、-、++、--操作,例如vector

2.2  list与vector的迭代器失效

vector使用随机迭代器,其底层结构为动态顺序表,有一段连续的存储空间

迭代器失效原因:

  1. 会引起其底层空间改变的操作,都有可能使迭代器失效(例如扩容)。
  2. 指定位置元素的插入或删除操作。

list使用的是双向迭代器,其底层结构为带头结点双向循环链表。
因此list中不存在扩容,在进行插入时不会导致list的迭代器失效只有在删除时迭代器才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

void Test1()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> ll(arr, arr + sizeof(arr) / sizeof(arr[0]));
	list<int>::iterator it = ll.begin();
	while (it != ll.end())
	{
		if (*it % 2 == 0)
		{
			it = ll.erase(it);
		}
		else
		{
			it++;
		}
	}
	for (auto x : ll)
	{
		cout << x << " ";
	}
	cout << endl;
}

注:  
        erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vectorlistC++中的两种容器,它们在内存空间、存取、插入删除、存储结构和对迭代器的支持等方面有一些不同。首先,vector的内存空间是连续的,地址不变,而list是双向链表实现的,内存空间是不连续的\[1\]。其次,vector能进行高效的随机存取操作,时间复杂度为O(1),而list通过指针访问数据,不能随机访问,时间复杂度为O(n)\[1\]。再次,插入或删除操作时,vector需要进行内存块的拷贝复制,时间复杂度是O(n),而list是非连续的存储结构,可以进行快速的插入和删除操作\[1\]。此外,vector是连续的存储结构,支持动态增长的对象数组,对数组的访问和在尾部的插入和删除操作高效,但在中间和头部的删除操作比较不易,需要移动大量的数据;而list是非连续的存储结构,是双链表结构,支持链表的双向遍历,可以进行高效的访问和插入删除操作\[1\]。最后,对迭代器的支持方面,vectorlist都重载了"++"操作,但vector的迭代器还支持"+", "+=", "<"等操作,而list不支持\[1\]。总的来说,vector适用于需要高效的随机存取操作的场景,而list适用于需要频繁的插入和删除操作的场景\[2\]。 #### 引用[.reference_title] - *1* [vectorlist的区别](https://blog.csdn.net/hsh_123456789/article/details/114906509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [vectorlist有什么区别?分别在什么场景下应用?](https://blog.csdn.net/yu876876/article/details/81698269)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值