c++ list详解

list

  • [1. list的介绍](#1. list的介绍)
  • [2. list常见重要的接口](#2. list常见重要的接口)
    • [2.1 构造函数](#2.1 构造函数)
    • [2.2 iterator](#2.2 iterator)
      • [2.2.1 理解](#2.2.1 理解)
      • [2.2.2 使用](#2.2.2 使用)
    • [3. 容量和大小](#3. 容量和大小)
    • [4. 查找元素](#4. 查找元素)
    • [5. 增、删、改](#5. 增、删、改)
  • [3. 迭代器失效](#3. 迭代器失效)
  • [4. vector和list对比](#4. vector和list对比)

1. list的介绍

list的底层结构是带头双向循环链表 ,因为该结构的特性,使list可以在常数范围内在任意位置进行插入和删除,但是不支持[]随机访问。

2. list常见重要的接口

2.1 构造函数

默认构造 list()
构造n个val list(n,val_type = val_type())
拷贝构造 list(const list& l)
迭代区间构造 list (InputIterator first,InputIterator last)

代码演示

cpp 复制代码
int main()
{
	//n个val
	list<int> li(5, 1);
	//拷贝构造
	list<int> li1(li);
	//迭代器区间构造
	list<int> li2(li.begin(), li.end());
	return 0;
}

2.2 iterator

2.2.1 理解

vector的iterator可以简单的理解成指针,事实上底层也是对指针typedef了,但是list的iterator不是这样,因为vector的空间是连续的,对iterator进行++或者--的操作是很自然的指向下一个或上一个元素,但是对于list的空间不是连续的,对list的iterator进行++或--是拿不到相应的元素,所以我们肯定要对++、--等操作符进行重载,但是对于内置类型,进行不了重载的操作,所以底层对该iterator进行了一层封装,变成了一个自定义的类,然后进行运算符重载,就可以得到理想的结果。

cpp 复制代码
//迭代器类
	template<class T,class Ref,class Ptr>
	class ListIterator
	{
		typedef ListNode<T>* PNode;
		typedef ListIterator<T, Ref, Ptr> Self;
	public:
		ListIterator(PNode pNode = nullptr)
			:_pNode(pNode)
		{}
		ListIterator(const Self& l)
			:_pNode(l._pNode)
		{}
		Ref operator*()
		{
			return _pNode->_data;
		}
		Ptr operator->()
		{
			return &_pNode->_data;
		}
		Self& operator++()
		{
			_pNode = _pNode->_next;
			return *this;
		}
		Self operator++(int)
		{
			Self tmp(*this);
			_pNode = _pNode->_next;
			return tmp;
		}
		Self& operator--()
		{
			_pNode = _pNode->_pre;
			return *this;
		}
		Self& operator--(int)
		{
			Self tmp(*this);
			_pNode = _pNode->_pre;
			return tmp;
		}
		bool operator!=(const Self& l)
		{
			return _pNode != l._pNode;
		}
		bool operator==(const Self& l)
		{
			return _pNode == l._pNode
		}
	private:
		PNode _pNode;
	};

2.2.2 使用

begin() 返回第一个元素的迭代器
end() 返回最后一个元素的下一个元素的迭代器
rebegin() 返回end位置的反向迭代器
rend() 返回begin位置

代码演示

cpp 复制代码
int main()
{
	//n个val
	list<int> li(5, 1);
	list<int>::iterator it = li.begin();
	while (it != li.end())
	{
		cout << *it << endl;
		it++;
	}
	return 0;
}

3. 容量和大小

判断list是否为空 empty()
返回list有效节点个数 size()

代码演示

cpp 复制代码
int main()
{
	//n个val
	list<int> li(5, 1);
	if (li.empty())
		cout << "list is empty" << endl;
	else
		cout << li.size() << endl;
	return 0;
}

4. 查找元素

获取第一个元素 front()
获取最后一个元素 back()

代码演示

cpp 复制代码
int main()
{
	//n个val
	list<int> li;
	li.push_back(1);
	li.push_back(2);
	li.push_back(3);
	li.push_back(4);
	li.push_back(5);
	cout << li.front() << endl;
	cout << li.back() << endl;
	return 0;
}

5. 增、删、改

push_front(const val_type& x) 头插
pop_front 头删
push_back(const val_type& x) 尾插
pop_back() 尾删
insert(iterator pos,const val_type& x) 在pos位置前面插入元素
erase(iterator pos) 删除pos位置元素
swap(const list& l) 交换两个list
clear() 清空有效节点

代码演示

cpp 复制代码
int main()
{
	list<int> li;
	li.push_back(1);
	li.push_back(2);
	li.push_back(3);
	li.push_back(4);
	li.push_back(5);
	li.push_front(6);

	li.pop_front();
	li.pop_back();

	list<int>::iterator it = li.begin();
	it++;
	li.insert(it, 7);
	it++;
	li.erase(it);

	list<int> li2(5, 1);
	li2.swap(li);
	li2.clear();
	return 0;
}





3. 迭代器失效

前面介绍vector容器的时候说过,vector在进行插入删除的时候很容易导致迭代器失效,但list只有在删除的时候会发生迭代器失效,而且不会影响其它的迭代器。

cpp 复制代码
void TestListIterator1()
	{
		int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
		list<int> l(array, array + sizeof(array) / sizeof(array[0]));
		auto it = l.begin();
		while (it != l.end())
		{
			// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
			其赋值
				l.erase(it);
			++it;
		}
	}

4. vector和list对比

  1. 底层结构:vector是动态顺序表,连续空间,list是带头结点的双向循环链表
  2. 访问:vector支持[]随机访问,list只能遍历访问
  3. 插入删除:vector尾插尾删效率高,但头插头删效率低,所以没该接口,list任意位置插入效率都高。
  4. 空间利用率:vector底层为连续空间,不容易造成内存碎片,空间利用率较高,缓存利用率高。可以一次将一个数据附近的空间都加载到缓存,不用频繁地从内存读取数据,list底层节点动态开辟,容易造成内存碎片,空间利用率低,缓存利用率低。
  5. 迭代器:vector为原生指针,list进行了封装。
  6. 迭代器失效:vector插入、删除都会导致迭代器失效,list只有在删除时会导致当前迭代器失效。
  7. 使用场景:vector适用不关心插入和删除效率,支持随机访问,list适用大量插入和删除操作,不关心随机访问的场景。
相关推荐
悄悄敲敲敲3 小时前
C++:dfs习题四则
c++·算法·深度优先
安於宿命4 小时前
【Linux】进程间通信——进程池
linux·c++
网硕互联的小客服7 小时前
如何提高网站在百度中的权重?
linux·运维·服务器·windows·安全
魔希达7 小时前
windows在wsl ubuntu环境中启用cuda加速AI推理和训练
人工智能·windows·ubuntu
南郁9 小时前
001-监控你的文件-FSWatch-C++开源库108杰
c++·开源·文件系统·文件监控·fswatch·文件变动信息·libfswatch
青啊青斯9 小时前
Windows搭建CUDA大模型Docker环境
windows·docker·容器
linux开发之路10 小时前
C++Linux进阶项目分析-仿写Redis之Qedis
linux·c++·redis·多线程·后端开发
EPSDA10 小时前
Linux线程库与线程库封装
linux·运维·服务器·开发语言·c++
孤独得猿11 小时前
排序算法复习——包括插入排序、希尔排序、冒泡排序、快排(包括霍尔法、挖坑法、快慢指针法)、堆排、选择排序、归并排序等 (代码采用c/c++混编)
c语言·数据结构·c++·笔记·算法·排序算法
编程探索者小陈11 小时前
【C++】智能指针的使用及其原理
开发语言·c++