STL之list

list同样是序列式容器,可排序但是未排序。
list和vector相比较,list的优点是每次插入或删除一个元素,就会分配或释放一个元素都空间。因此,list对空间的运用有绝对的精准,一点儿也不浪费。而且,list对于任何位置的元素的插入或移除,时间复杂度永远是常数级。

下面我们从节点、迭代器、list结构、list 的constructor, push_back, insert、list元素的操作这五点进行分析。

1.节点
首先看一下list的节点(node)的定义

template <class T>
struct __list_node {
	typedef void* void_pointer;
	void_pointer prev; // 类型为 void*。其实可设为 __list_node<T>*
	void_pointer next;
	T data;
};

可以看到每个node有自己的数据,并且有前指针和后指针。
显然这个是一种双向链表。
在这里插入图片描述
值得注意的是,list的节点不保证在空间上是连续存储的。

2.迭代器
list有一个重要的特性,插入动作(insert)和接合动作(splice)都不会造成原有的list的迭代器失效。这在vector是不成立的,因为vector的插入动作造成记忆体重新配置,导致原有的迭代器全部失效。甚至list的删除动作(erase),也只有【指向被删除元素】的那个迭代器失效,其他迭代器不受任何影响。
在这里插入图片描述
3.list的结构
正如前面提到的那样,list是个双向链表,但是不仅如此,它还是个环状链表,因此只需要一个指针就可以完成整个list的遍历。
在这里插入图片描述
4.list 的constructor, push_back, insert
话不多说,先看一下list的这三种基本操作

    int i;
	list<int> ilist;
	cout << "size=" << ilist.size() << endl; // size=0
	ilist.push_back(0);
	ilist.push_back(1);
	ilist.push_back(2);
	ilist.push_back(3);
	ilist.push_back(4);
	cout << "size=" << ilist.size() << endl; // size=5
	
	list<int>::iterator ite;
	for (ite = ilist.begin(); ite != ilist.end(); ++ite)
		cout << *ite << ' '; // 0 1 2 3 4
	cout << endl;
	
	ite = find(ilist.begin(), ilist.end(), 3);
	if (ite !=ilist.end())
		ilist.insert(ite, 99);
	cout << "size=" << ilist.size() << endl; // size=6
	cout << *ite << endl; // 3
	for (ite = ilist.begin(); ite != ilist.end(); ++ite)
		cout << *ite << ' '; // 0 1 2 99 3 4
	cout << endl;
	
	ite = find(ilist.begin(), ilist.end(), 1);
	if (ite != ilist.end())
		cout << *(ilist.erase(ite)) << endl; // 2
	for (ite = ilist.begin(); ite != ilist.end(); ++ite)
		cout << *ite << ' '; // 0 2 99 3 4
	cout << endl;

输出:
在这里插入图片描述
list有许多constructors,其中的一个是default constructor,允许我们不指定任何参数做出一个空的list

当我们以 push_back() 將新元素安插于 list 尾端,此函数內部呼叫 insert() :

void push_back(const T& x) { insert(end(), x); }

而insert有多种重载类型,其中一下如下

// 函式目的:在迭代器 position 所指位置安插一个节点,內容为 x。
iterator insert(iterator position, const T& x)

由于 list 不像 vector 那样有可能在空间不足时做重新配置、资料搬移的动作,所以插入前的所有迭代器在插入动作之后都仍然有效。
在这里插入图片描述
5.list 的元素操作:push_front, push_back, erase, pop_front, pop_back,clear, remove, unique, splice, merge, reverse, sort
功能描述

// 安插一个节点,做为头节点
void push_front(const T& x) { insert(begin(), x); }
// 安插一个节点,做为尾节点(上一小节才介紹过)
void push_back(const T& x) { insert(end(), x); }
// 移除迭代器 position 所指节点
iterator erase(iterator position)
// 移除头结点
void pop_front() { erase(begin()); }
// 移除尾节点
void pop_back()
// 清除所有节点(整個链表)
template <class T, class Alloc>
void list<T, Alloc>::clear()
// 將数值为value 的所有元素移除
template <class T, class Alloc>
void list<T, Alloc>::remove(const T& value)
// 移除数值相同的连续元素。注意,只有「连续而相同的元素」,才会被移除剩一个。
template <class T, class Alloc>
void list<T, Alloc>::unique()

下图展示了移除值为1的节点
在这里插入图片描述
下面是splice、reverse、sort操作,输出即为注释。

    int iv[5] = { 5,6,7,8,9 };
	list<int> ilist2(iv, iv + 5);
	// 目前,ilist 的內容為 0 2 99 3 4
	ite = find(ilist.begin(), ilist.end(), 99);
	ilist.splice(ite, ilist2);  // 0 2 5 6 7 8 9 99 3 4
	ilist.reverse(); // 4 3 99 9 8 7 6 5 2 0
	ilist.sort(); // 0 2 3 4 5 6 7 8 9 99

在这里插入图片描述

// merge() 將 x 合并到 *this 身上。两个 lists 的內容都必须先经过递增排序。
template <class T, class Alloc>
void list<T, Alloc>::merge(list<T, Alloc>& x)

具体操作

	int d1[5] = { 1,3,5,7,9 };
	int d2[5] = { 2,4,6,8,10 };
	list<int> list1(d1,d1+5);//前闭后开区间
	list<int> list2(d2,d2+5);
	list1.merge(list2);
	list<int>::iterator it;
	for (it = list1.begin(); it != list1.end(); ++it)
		cout << *it << " ";
	cout << endl;

输出:
在这里插入图片描述

### C++ STL List 容器删除元素 #### 使用 `erase` 函数 对于C++ STL中的`list`容器,可以使用成员函数`erase`来移除指定位置的元素。此函数接受迭代器作为参数并删除该迭代器指向的位置上的项目[^2]。 ```cpp #include <iostream> #include <list> int main() { std::list<int> myList = {1, 2, 3, 4, 5}; // 创建一个迭代器指向第三个元素 (即值为3) auto it = myList.begin(); advance(it, 2); // 删除第三个元素 myList.erase(it); // 输出剩余列表项 for(auto& elem : myList){ std::cout << elem << " "; } } ``` 上述代码展示了如何通过创建指向目标位置的迭代器,并将其传递给`erase`来进行单个元素的移除操作。 #### 移除最后面的一个元素 要从`list`中去除最末端的一项,则可以直接调用`pop_back()`方法实现这一点。实际上,在某些标准库实现在内部会利用`erase`配合`end()`来完成这一功能。 ```cpp std::list<int>::iterator popBackExample(std::list<int>& lst) { if (!lst.empty()) { return lst.erase(--lst.end()); } return lst.end(); // 如果为空则返回结束迭代器 } ``` 这段例子说明了当执行`pop_back`时发生的实际过程:先定位到最后一个有效元素之前的位置再做清除处理。 #### 清空整个链表 如果目的是清空整个`list`对象内的全部内容,那么应该采用`clear()`成员函数;这将高效地释放所有关联资源而不必逐一遍历各个节点去单独销毁它们[^1]。 ```cpp myList.clear(); ``` 以上就是几种常见的用于管理`list`内存储单元生命周期的操作手段介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值