C++容器list

C++容器list

定义

std::list - cppreference.cn - C++参考手册

  • 双向链表:每个元素(节点)包含数据、一个指向前一个节点的指针和一个指向后一个节点的指针
  • 非连续存储:元素在内存中不是连续存放的,而是通过指针链接
  • 高效修改 :插入和删除操作(包括中间位置)的时间复杂度为 O(1),前提是已知插入/删除位置的迭代器
  • 不支持随机访问 :不能通过下标 [] 直接访问第 n 个元素,必须从头或尾遍历,时间复杂度为 O(n)
  • 稳定迭代器 :只要不删除元素,插入操作不会使其他元素的迭代器、指针或引用失效。这是 list 相对于 vectordeque 的巨大优势

构造函数

1、默认构造函数

创建空的list,长度为0

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1;

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
}

2、指定大小构造函数

cpp 复制代码
std::string getStringFromU8string(const std::u8string& u8str) {
	return std::string(reinterpret_cast<const char*>(u8str.data()), u8str.size());
}

std::u8string getU8stingFromString(const std::string& str) {
	return std::u8string(reinterpret_cast<const char8_t*>(str.data()), str.size());
}

int main()
{
	system("chcp 65001");
	list<std::u8string> list1(4);

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}
}

3、指定大小与初始值构造函数

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1(4, u8"&&");

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}
}

4、拷贝构造函数

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
	// 拷贝构造函数
	list<std::u8string> list2(list1);

	cout << "list2.size()= " << list2.size() << endl;
	cout << "list2.max_size()= " << list2.max_size() << endl;
	for (auto it : list2)
	{
		cout << "list2-> " << getStringFromU8string(it) << endl;
	}
}

5、移动构造函数‌

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
	// 移动构造函数
	list<std::u8string> list2(std::move(list1));

	cout << "list2.size()= " << list2.size() << endl;
	cout << "list2.max_size()= " << list2.max_size() << endl;
	for (auto it : list2)
	{
		cout << "list2-> " << getStringFromU8string(it) << endl;
	}

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
}

6、范围构造函数

cpp 复制代码
int main()
{
	system("chcp 65001");
	std::array<std::u8string, 4> arr1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };

	// 范围构造函数
	list<std::u8string> list1(arr1.rbegin(), arr1.rend());

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}
}

7、指定初始化列表构造函数

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
	list<std::u8string> list2{ u8"张三", u8"李四" };

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}
}

元素访问

不支持下标访问

函数 描述
front() 返回第一个元素的引用。
back() 返回最后一个元素的引用。
cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };

	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	cout << "list1.front()= " << getStringFromU8string(list1.front()) << endl;
	cout << "list1.back()= " << getStringFromU8string(list1.back()) << endl;
}

容量大小

函数 描述
empty() 如果 list 为空,返回 true
size() 返回当前元素数量。
max_size() 返回容器可容纳的最大元素数量。
cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };

	cout << "list1.empty()= " << boolalpha << list1.empty() << endl;
	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	cout << "list1.front()= " << getStringFromU8string(list1.front()) << endl;
	cout << "list1.back()= " << getStringFromU8string(list1.back()) << endl;
}

迭代器

begin-endrbegin-rend

cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };

	// for循环
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}

	//begin-end
	for (auto it = list1.begin(); it != list1.end(); it++)
	{
		cout << "begin-end list1-> " << getStringFromU8string(*it) << endl;
	}

	//cbegin-cend
	for (auto it = list1.cbegin(); it != list1.cend(); it++)
	{
		cout << "cbegin-cend list1-> " << getStringFromU8string(*it) << endl;
	}

	//rbegin-rend
	for (auto it = list1.rbegin(); it != list1.rend(); it++)
	{
		cout << "rbegin-rend list1-> " << getStringFromU8string(*it) << endl;
	}
}

修改操作

函数 描述
push_back(value) 在末尾插入一个元素
push_front(value) 在开头插入一个元素。
pop_back() 删除最后一个元素。
pop_front() 删除第一个元素。
emplace_back(args...) 在末尾就地构造一个元素(不用复制)
emplace_front(args...) 在开头就地构造一个元素(不用复制)
emplace(pos, args...) 在位置 pos 就地构造一个元素(不用复制)
insert(pos, value) 在位置 pos 插入一个元素。
insert(pos, n, value) 在位置 pos 插入 n 个 value
insert(pos, first, last) 在位置 pos 插入范围 [first, last) 的元素。
erase(pos) 删除位置 pos 的元素,返回下一个元素的迭代器。
erase(first, last) 删除范围 [first, last) 的元素,返回 last 迭代器。
clear() 删除所有元素。
resize(n) 调整大小到 n。如果变大,新元素用默认值初始化(小于实际元素个数,会删除后面的元素)
swap(other) 与另一个 list 交换内容。
cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
	//头部添加数据
	list1.push_front(u8"哈尔滨");
	list1.emplace_front(u8"长春");

	// 尾部添加数据
	list1.push_back(u8"沈阳");
	list1.emplace_back(u8"葫芦岛");
	for (auto it : list1)
	{
		cout << "list1-> " << getStringFromU8string(it) << endl;
	}

	// 删除元素
	list1.pop_front();
	list1.pop_back();
	// 删除第一个
	list1.erase(list1.begin());
	// 删除第三个	
	list1.erase(std::next(list1.begin(), 2));
	// 清空list
	list1.erase(list1.begin(), list1.end());
	for (auto it : list1)
	{
		cout << "after delete, list1-> " << getStringFromU8string(it) << endl;
	}

	// 插入数据
	list1.insert(list1.begin(), u8"测试1");
	list1.insert(std::next(list1.begin(), 1), u8"测试2");
	list1.insert(std::next(list1.begin(), 2), 2, u8"&&");

	std::array<std::u8string, 2> arr1 = { u8"张三",u8"李四" };
	list1.insert(list1.begin(), arr1.begin(), arr1.end());
	for (auto it : list1)
	{
		cout << "after insert, list1-> " << getStringFromU8string(it) << endl;
	}

	// 调整大小
	list1.resize(2);
	cout << "list1.size()= " << list1.size() << endl;
	cout << "list1.max_size()= " << list1.max_size() << endl;
	for (auto it : list1)
	{
		cout << "after resize, list1-> " << getStringFromU8string(it) << endl;
	}
	list1.clear();
}

链表操作

函数 描述
splice(pos, other, it) otherit 指向的元素移动到 lpos 位置。O(1)
splice(pos, other, first, last) other[first, last) 范围的元素移动到 lpos 位置。O(1)
remove(value) 删除所有值为 value 的元素。
remove_if(pred) 删除所有满足谓词 pred 的元素。
unique() 删除连续的重复元素(只保留一个)。
unique(pred) 使用自定义比较函数删除连续的重复元素。
sort() 对元素进行排序(默认升序)。
sort(comp) 使用自定义比较函数排序。
reverse() 反转 list 中元素的顺序。
merge(other) 将已排序的 other 合并到 l 中,并保持有序。other 变为空。
cpp 复制代码
int main()
{
	system("chcp 65001");
	list<std::u8string> list1 = { u8"北京", u8"上海", u8"广州", u8"深圳" };
	list<std::u8string> list2 = { u8"张三",u8"李四" };
	// 将list2的第一个元素移动到list1的第一个位置
	list1.splice(list1.begin(), list2, list2.begin());

	// 将list2的前两个元素移动到list1的第一个位置
	// list1.splice(list1.begin(), list2, list2.begin(), list2.end());
	for (auto it : list1)
	{
		cout << "afet splice, list1-> " << getStringFromU8string(it) << endl;
	}

	// 删除排序
	list1.remove(u8"张三");
	list1.sort();
	for (auto it : list1)
	{
		cout << "afet sort, list1-> " << getStringFromU8string(it) << endl;
	}

	// 转置
	list1.reverse();
	for (auto it : list1)
	{
		cout << "afet reverse, list1-> " << getStringFromU8string(it) << endl;
	}

	// 合并另外一个list(要求已经排好序)
	list1.sort();
	list2.sort();
	list1.merge(list2);
	cout << "afet merge, list1.size()= " << list1.size() << endl;
	cout << "afet merge, list2.size()= " << list2.size() << endl;
}

其他

特性 std::list std::vector std::deque
任意位置插入/删除 O(1) (已知位置) O(n) O(n) (中间) / O(1) (首尾)
头部插入/删除 O(1) O(n) O(1)
尾部插入/删除 O(1) O(1) 均摊 O(1)
随机访问 不支持 O(1) O(1)
内存布局 非连续 (链表) 连续 分段连续
迭代器失效 仅被删除元素的迭代器失效 插入/删除可能导致大量失效 插入/删除可能导致大量失效
splice 操作 O(1) 不支持 不支持
内存开销 高 (每个元素有额外的指针开销) 中等
缓存局部性 中等
相关推荐
大肘子咒你3 小时前
数字狂潮来袭
数据结构·c++·1024程序员节
张较瘦_3 小时前
[论文阅读] 从 5MB 到 1.6GB 数据:Java/Scala/Python 在 Spark 中的性能表现全解析
java·python·scala
hansang_IR3 小时前
【算法速成课 3】康托展开(Cantor Expansion)/ 题解 P3014 [USACO11FEB] Cow Line S
c++·算法·状态压缩·康托展开·排列映射
m0_748233643 小时前
【类与对象(中)】C++类默认成员函数全解析
开发语言·c++·算法
Han.miracle3 小时前
数据库圣经-----最终章JDBC
java·数据库·学习·maven·database
艾菜籽4 小时前
MyBatis操作数据库入门
java·数据库·mybatis
zfoo-framework4 小时前
使用VisualVM进行java性能瓶颈定位 1.无需像JProfiler那样必须加启动参数???
java
bug攻城狮4 小时前
Spring Boot 2.6+ 整合 PageHelper 启动报错:循环依赖解决方案全解析
java·spring boot·后端
源代码•宸5 小时前
Qt6 学习——一个Qt桌面应用程序
开发语言·c++·经验分享·qt·学习·软件构建·windeployqt