【c++丨STL】list的使用

news2024/11/20 3:38:39
🌟🌟作者主页:ephemerals__
🌟🌟所属专栏:C++、STL

目录

前言

list简介

一、list的默认成员函数

构造函数(constructor)

析构函数

赋值重载

二、list的迭代器接口

迭代器的功能分类

三、list的容量接口

empty

size

四、list的元素访问接口

front和back

五、list的增删查改

push_front

pop_front

push_back

pop_back

insert和erase

swap

resize

clear

find

六、list的其他操作接口

splice

remove

remove_if

unique

merge

sort

reverse

总结


前言

        之前我们已经学习了string、vector两个容器的使用方法及模拟实现,今天跟大家介绍list的使用方法。

        到了这个阶段,我们应该认识到:在STL中,尽管容器各异,但同名接口的功能往往是相似的。因此,在我们掌握了少数几个容器的使用方法后,对于未曾接触过的其他容器,只要了解其底层数据结构,就基本能够上手使用它们。

list简介

        list是STL中的一种容器,用于表示链表结构,底层实现是一个双向带头循环链表。如果你对双向带头循环链表不太了解,可以参阅这篇文章:

【数据结构】双向带头循环链表(c语言)(附源码)_c语言双向环链表初始化-CSDN博客

list在插入和删除操作方面非常高效,但在遍历和随机访问方面可能不如数组或者vector高效。因此,在选择容器时,需要根据具体的应用场景和需求进行权衡。

我们在使用list时,需要引头文件<list>,并且该容器定义在命名空间std当中。

list相关接口查阅:

list - C++ Reference

一、list的默认成员函数

        list显示实现的默认成员函数有三个:分别是构造函数、析构函数和赋值重载。 

构造函数(constructor)

c++11下,list共有六个构造函数,其中较为常用的有如下五种:

函数原型功能说明
list();无参构造(忽略空间配置器),创建一个空链表
list(size_type n, const value_type& val);用n个val值构造一个list对象
list(const list& x);拷贝构造,用一个对象构造另一个对象
list(InputIterator first,InputIterator last);迭代器区间构造
list(initializer_list<value_type> il);初始化器构造(大括号赋值)

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1;//无参构造
	list<int> l2(5, 3);//n个val值构造
	list<int> l3(l2);//拷贝构造
	list<int> l4(l2.begin(), l2.end());//迭代器区间构造
	list<int> l5({ 1,2,3,4,5 });//初始化器构造

	cout << "l1: ";
	print(l1);
	cout << "l2: ";
	print(l2);
	cout << "l3: ";
	print(l3);
	cout << "l4: ";
	print(l4);
	cout << "l5: ";
	print(l5);
	return 0;
}

析构函数

释放动态分配的内存空间,在对象声明周期结束时自动调用。

赋值重载

将新内容分配给已经存在的容器,替换其当前内容,并相应地修改其大小。较为常用的赋值重载有两个:

函数原型功能说明
list& operator= (const list& x);两个list容器之间的赋值
list& operator= (initializer_list<value_type> il);用初始化器给容器赋值

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1;
	list<int> l2({ 1,2,3,4,5 });

	l1 = l2;//将l2赋值给l1
	print(l1);

	l1 = { 5,4,3,2,1 };//初始化器赋值
	print(l1);
	return 0;
}

二、list的迭代器接口

迭代器接口在string和vector中的使用方法大致相同,这里就不多介绍。

由于list元素的内存地址是不连续的,因此在迭代器的实现上,它与vector和string存在较大差异。我们将在list模拟实现的部分中对此进行深入探讨。

我们在这里重点讲一下迭代器的功能分类

迭代器的功能分类

根据功能强弱,迭代器可以分为以下三种:

1. 单向迭代器:它仅支持在容器中进行从头到尾的遍历操作,重载了“++”运算符。

2. 双向迭代器:它支持从头到尾的遍历和从尾到头的遍历,重载了“++”和“--”运算符。

3. 随机迭代器:顾名思义,它不仅支持双向的遍历,还支持随机位置的访问,重载了“++”“--”“+”“-”等运算符。

这三种迭代器的功能是向下兼容的,即随机迭代器具有双向迭代器的功能,而双向迭代器具有单向迭代器的功能

为什么会有这样的分类呢?其实这是由底层数据结构的实现导致的。

        有些数据结构元素的内存地址连续,还能够支持双向遍历,并且遍历效率高,那么就可以支持随机迭代器(例如string、vector);有些数据结构能够支持双向遍历,但是随机访问的效率低下,那就支持双向迭代器(例如list);有些数据结构只能做到从前向后访问元素,那么就只能支持单向迭代器(例如单链表forward_list)。

所以我们在使用string、vector的迭代器时,可以使用“+”“-”操作符进行随机访问;而对于list,就只能通过“++”“--”来移动迭代器指向的位置。

三、list的容量接口

三个容量接口当中,前两个比较常用,我们重点介绍一下:

empty

empty函数用于判断该列表容器是否为空(即元素个数是否为0)。注意:该函数不会以任何方式修改容器。

size

size函数用于获取容器内元素的个数。 

代码示例:

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> l1;
	list<int> l2({ 1,2,3,4,5 });

	cout << "l1.size(): " << l1.size() << endl;
	cout << l1.empty() << endl;

	cout << "l2.size(): " << l2.size() << endl;
	cout << l2.empty() << endl;
	return 0;
}

四、list的元素访问接口

front和back

front函数返回对列表容器中第一个元素的引用,在空容器上调用此函数会导致未定义行为。


back函数返回对列表容器中最后一个元素的引用,在空容器上调用此函数会导致未定义行为。

代码示例:

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> l = { 1,2,3,4,5 };

	cout << l.front() << endl;
	cout << l.back() << endl;
	return 0;
}

相比vector的元素访问接口,list缺少了operator[ ]at。是因为它们不能实现吗?当然不是,而是由于链表的特殊结构。如果实现了这两个接口,则使用时都需要遍历元素,效率的代价是很大的。

五、list的增删查改

在涉及增删查改操作的接口中,鉴于部分接口功能有所重复,博主仅挑选几个进行介绍。

push_front

push_front的功能是在容器的开头插入一个新元素,就在它当前的第一个元素之前。val的内容被复制(或移动)到插入的元素中。这有效地将容器大小增加了1。

pop_front

pop_front的功能是删除列表容器中的第一个元素,有效地将其大小减小1。这将破坏被删除的元素。

push_back

push_back的作用是在容器的末尾插入一个新元素。val的内容被复制(或移动)到新元素中。这有效地将容器大小增加了1。

pop_back

pop_back的作用是删除容器中的最后一个元素,有效地将容器大小减少一个。这将破坏被删除的元素。

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1 = { 1,2,3,4,5 };
	cout << "原链表:";
	print(l1);

	l1.push_back(0);
	cout << "尾插:";
	print(l1);
	l1.push_front(0);
	cout << "头插:";
	print(l1);
	l1.pop_back();
	cout << "尾删:";
	print(l1);
	l1.pop_front();
	cout << "头删:";
	print(l1);
	return 0;
}

insert和erase

insert用于指定位置插入元素(需要使用迭代器指定)。该函数支持单个元素插入、n个val值插入、迭代器区间插入以及初始化器插入。操作结束后,该函数会返回新插入部分首元素的迭代器


erase的作用是删除指定位置的元素或区间(需要使用迭代器指定)。操作结束后,函数返回删除部分的后一个位置的迭代器(防止迭代器失效)。 

代码举例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l = { 1,2,3,4,5 };

	l.insert(++l.begin(), 0);//在第二个位置插入一个元素
	print(l);

	l.erase(----l.end());//删除倒数第二个元素
	print(l);
	return 0;
}

swap

swap的功能是交换两个list容器的内容。 当然,也有一个非成员函数的swap支持list的交换:

resize

resize的功能是调整容器的大小,使其包含n个元素

如果n小于当前容器的大小,则内容将被减少到n个元素,并删除超出的元素(销毁它们)

如果n大于当前容器的大小,则通过在末尾插入所需的元素来扩展内容,以达到n的大小。如果指定了val,则将新元素初始化为val的副本,否则调用其构造函数来初始化元素。

注意:这个函数通过插入或删除元素来改变容器的实际内容。

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1;
	list<int> l2;

	l1.resize(10);
	l2.resize(10, 5);
	print(l1);
	print(l2);

	list<int> l3({ 1,2,3,4,5 });
	print(l3);

	l3.resize(3);
	print(l3);
	return 0;
}

clear

clear的功能是从列表容器中删除所有元素,并将容器的大小保留为0。

find

与vector相同,list并没有用于查找的函数(find),要使用STL实现的通用find完成查找。该find函数定义在算法库<algorithm>当中,用于容器元素的查找。它接受两个迭代器参数和一个值参数,表示需要查找的区间和值如果找到了,函数会返回指向第一个查找到的元素的迭代器,否则返回尾迭代器

六、list的其他操作接口

除了传统的成员函数外,list还提供了一些特有的与插入删除相关的操作接口供我们使用。通过学习这些接口的使用方法,我们可以初步了解仿函数的相关知识。

splice

splice的功能是剪切它能够将 容器x 容器x的某个元素 容器的一部分 拷贝到原容器的指定位置,并且删除x中的相应元素

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1;
	list<int> l2({ 1,2,3,4,5 });

	l1.splice(l1.end(), l2);//将l2剪切到l1的末尾
	cout << "l1:";
	print(l1);
	cout << "l2:";
	print(l2);
	cout << endl;

	l2 = { 1,2,3,4,5 };
	l1.splice(l1.end(), l2, l2.begin());//将l2的首元素剪切到l1的末尾
	cout << "l1:";
	print(l1);
	cout << "l2:";
	print(l2);
	cout << endl;

	l2 = { 1,2,3,4,5 };
	l1.splice(l1.end(), l2, ++l2.begin(), --l2.end());//将l2掐头去尾的部分剪切到l1的末尾
	cout << "l1:";
	print(l1);
	cout << "l2:";
	print(l2);
	cout << endl;
}

remove

remove的功能是删除指定值的元素

该函数从容器中删除比较结果为val的所有元素。这将调用这些对象的析构函数,并按删除元素的数量减少容器大小。

与erase不同,erase根据元素的位置删除元素,该函数根据元素的值删除元素。

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l = { 1,2,3,2,4,2,2,5 };
	print(l);
	l.remove(2);//删除所有的2
	print(l);
	return 0;
}

 

remove_if

remove_if用于删除list容器中满足特定条件的所有元素(特定条件由我们设定)

该函数的参数是一个谓词(Predicate),如果容器中的某元素使得该谓词返回true,就将该元素删除。


这里简单介绍一下谓词

        之前我们在c语言部分使用qsort函数时,需要显示写一个比较函数用于确定排序的规则,谓词的功能就相当于我们显示写的比较函数。

        谓词可以是以下几种形式之一:

        1. 返回值为bool类型的函数指针

        2. 仿函数(重载了函数调用操作符"()"的类,且该重载函数的返回值是bool类型)

        3. Lambda表达式(c++11之后支持)

--------------------

        由于我们已经使用过函数指针,在接下来的代码示例当中,我们就尝试写一个仿函数来表示谓词。

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

//仿函数
class f
{
public:
	bool operator()(int value)
	{
		return value < 10;//将小于10的元素确定为true
	}
};

int main()
{
	list<int> l = { 20,1,5,9,15,17 };
	l.remove_if(f());//删除所有小于10的元素
	print(l);
	return 0;
}

 

unique

unique函数的功能是删除所有与它的前一个元素满足某特定关系(特定关系可由我们设定)的元素。当然,该特定关系也是使用谓词表示。当我们没有显示设置特定关系,那么该特定关系就是两元素相等,也就是说我们没有传参时,函数的功能是删除所有相邻的重复元素(保留一个重复的元素,不会全部删除)

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1 = { 1,1,2,3,3,4,4,4,5,5,6,7,8,8 };//有序序列
	l1.unique();
	print(l1);

	list<int> l2 = { 2,2,1,2,2 };//无序序列,无法直接删除所有重复元素
	l2.unique();
	print(l2);
	return 0;
}

对于一个无序list序列,如果想要删除所有的重复元素,那么就需要先对list进行排序,然后再调用unique函数。

merge

merge的作用是合并两个有序链表注意两个容器都应是有序状态

这实际上删除了x中的所有元素,但不是销毁其中元素,而是将节点的指针互相连接,最后全部并入到原容器中。

该函数可以接受一个特定的谓词(comp)来执行元素之间的比较操作。

函数执行后,等价元素的相对位置不变(即原容器的在前,x的在后)。

如果x就是原容器,那么函数什么也不做。

代码示例:

#include <iostream>
#include <list>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l1 = { 1,3,5,7,9 };
	list<int> l2 = { 2,4,6,8,10 };

	l1.merge(l2);//合并
	cout << "l1:";
	print(l1);
	cout << "l2:";
	print(l2);
	return 0;
}

sort

sort用于排序list容器。当然,我们也可以传入一个谓词来确定排序规则,否则默认升序。

它的底层是一个优化的归并排序,意味着等价元素相对位置不变

说起sort,博主在这里补充一点:与通用find函数相同,STL实现了一个通用的排序函数sort,参数是随机迭代器构成的迭代器区间,用于容器排序。

为什么要实现一个成员函数版的sort呢?直接使用算法库中的通用sort不行吗?刚才博主已经提到,list支持的是双向迭代器,并不具备随机迭代器的功能,所以list无法使用通用的sort函数完成排序,会发生报错。所以说list的成员函数当中,实现了一个排序函数sort。

接下来我们尝试使用该函数:

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l = { 5,1,7,2,4,8,0,3 };
	l.sort();//排序
	print(l);
	return 0;
}

由于list底层是一个链表,所以对于排序这种需要重复调整元素顺序的算法,它的效率不是很高。如果要对list排序,建议将list的内容拷贝给vector,然后进行排序,最后拷贝回list。

reverse

reverse的功能是反转链表

代码示例:

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

void print(list<int>& l)
{
	for (auto& e : l)
	{
		cout << e << ' ';
	}
	cout << endl;
}

int main()
{
	list<int> l = { 1,2,3,4,5 };

	l.reverse();//反转

	print(l);
	return 0;
}

总结

        今天我们学习了STL容器--list的使用方法。当我们需要频繁进行插入和删除操作时,可以考虑使用该容器。之后博主会和大家一起模拟实现list,并且借此来深入学习迭代器的底层实现。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2243782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何编译 Cesium 源码

如何编译 Cesium 源码 Cesium 是一个开源的 JavaScript 库&#xff0c;用于构建 3D 地球和地图应用程序。它提供了一套强大的 API 和工具&#xff0c;使开发者能够创建丰富的地理空间应用。本文将指导您如何从 GitHub 下载 Cesium 源码&#xff0c;并在本地进行编译。 TilesB…

实验5:网络设备发现、管理和维护

实验5&#xff1a;网络设备发现、管理和维护 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握Cisco 路由器和交换机的IOS配置管理。自动从NTP服务器获取时间信息。能够利用TFTP服务器实现路由器和交换机配置文件的备份和恢复。同时验证CDP协议和LLDP协议的网络参数。完…

全志T113双核异构处理器的使用基于Tina Linux5.0——RTOS编译开发说明

3、RTOS编译开发说明 3.1、RTOS SDK与TinaLinux开发环境 RTOS SDK相关代码已集成到Tina Linux开发环境&#xff0c;Tina Linux开发环境下的rtos子目录即为RTOS开发环境。 ├──brandy ├──bsp ├──build ├──buildroot ├──build.sh >build/top_build.sh ├──…

汽车资讯新篇章:Spring Boot技术启航

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-04

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-04 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-04目录1. Alopex: A Computational Framework for Enabling On-Device Function Calls with LLMs摘要&#xff1a;研究背景&…

细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的方法

目录 一、DMA基础知识 1、DMA简介 (1)DMA控制器 (2)DMA流 (3)DMA请求 (4)仲裁器 (5)DMA传输属性 2、源地址和目标地址 3、DMA传输模式 4、传输数据量的大小 5、数据宽度 6、地址指针递增 7、DMA工作模式 8、DMA流的优先级别 9、FIFO或直接模式 10、单次传输或突…

review-消息中间件MQ

RabbitMQ RabbitMQ&#xff0c;作为当今流行的开源消息代理软件&#xff0c;以其卓越的可靠性、灵活性和易用性在微服务架构和分布式系统中扮演着至关重要的角色。它不仅能够确保消息在不同系统组件间的高效传递&#xff0c;还能通过其高级消息队列协议&#xff08;AMQP&#x…

使用 .NET 创建新的 WPF 应用

本教程介绍如何使用 Visual Studio 创建新的 Windows Presentation Foundation &#xff08;WPF&#xff09; 应用。 使用 Visual Studio&#xff0c;可以向窗口添加控件以设计应用的 UI&#xff0c;并处理这些控件中的输入事件以与用户交互。 在本教程结束时&#xff0c;你有一…

【青牛科技】视频监控器应用

1、简介&#xff1a; 我司安防产品广泛应用在视频监控器上&#xff0c;产品具有性能优良&#xff0c;可 靠性高等特点。 2、图示&#xff1a; 实物图如下&#xff1a; 3、具体应用&#xff1a; 标题&#xff1a;视频监控器应用 简介&#xff1a;视频监控器工作原理是光&#x…

Android 项目依赖库无法找到的解决方案

目录 错误信息解析 解决方案 1. 检查依赖版本 2. 检查 Maven 仓库配置 3. 强制刷新 Gradle 缓存 4. 检查网络连接 5. 手动下载依赖 总结 相关推荐 最近&#xff0c;我在编译一个 Android 老项目时遇到了一个问题&#xff0c;错误信息显示无法找到 com.gyf.immersionba…

esp32c3开发板通过micropython的mqtt库连MQTT物联网消息服务器

MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息协议&#xff0c;旨在设备之间进行通信&#xff0c;尤其是在网络条件较差的情况下。MQTT v3.1.1 和 MQTT v5 是该协议的两个主要版本。 MQTT v3.1.1&#xff1a; 优点&#xff…

2、 家庭网络发展现状

上一篇我们讲了了解家庭网络历史(https://blog.csdn.net/xld_hung/article/details/143639618?spm1001.2014.3001.5502),感兴趣的同学可以看对应的文章&#xff0c;本章我们主要讲家庭网络发展现状。 关于家庭网络发展现状&#xff0c;我们会从国内大户型和小户型的网络说起&…

element ui 走马灯一页展示多个数据实现

element ui 走马灯一页展示多个数据实现 element ui 走马灯一页展示多个数据实现 element ui 走马灯一页展示多个数据实现 主要是对走马灯的数据的操作&#xff0c;先看js处理 let list [{ i: 1, name: 1 },{ i: 2, name: 2 },{ i: 3, name: 3 },{ i: 4, name: 4 },]let newL…

linux文件与重定向

目录 一、共识原理 二、回顾C语言文件函数 1.fopen 2.fwrite 3.fclose 三、文件系统调用 1.open 2.write 3.访问文件的本质 4.stdin&&stdout&&stderror 5.文件的引用计数 四、重定向 1.文件描述符的分配规则 2. 输出重定向 3.重定向系统调用 4.…

CS DAC的Matlab建模与电路设计

在模拟电路设计的复杂世界里&#xff0c;每一个细节都至关重要。Current Steering DAC作为模拟数字转换的核心组件&#xff0c;其设计和性能优化一直是工程师们追求的目标。 “什么是Current Steering DAC&#xff1f; CS DAC通过控制电流源的开关&#xff0c;将数字输入信号…

网络传输:网卡、IP、网关、子网掩码、MAC、ARP、路由器、NAT、交换机

目录 网卡IP网络地址主机地址子网子网掩码网关默认网关 MACARPARP抓包分析 路由器NATNAPT 交换机 网卡 网卡(Network Interface Card&#xff0c;简称NIC)&#xff0c;也称网络适配器。 OSI模型&#xff1a; 1、网卡工作在OSI模型的最后两层&#xff0c;物理层和数据链路层。物…

STM32完全学习——系统时钟设置

一、时钟框图的解读 首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟&#xff0c;由于内部HSI存在较大的误差&#xff0c;因此我们在系统完成上电初始化&#xff0c;之后需要将STM32的时钟切换到外部HSE作为系统时钟&#xff0c;那么我…

基于Java Springboot滁州市特产销售系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

H.265流媒体播放器EasyPlayer.js视频流媒体播放器关于直播流播放完毕是否能监听到

EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;无须安装任何插件&#xff0c;起播快、延迟低、兼容性强&#xff0c;使用非常便捷。 EasyPlayer.js播放器不仅支持H.264与H.265视频编码格式&#xff0c;也能支持WebS…

Ubuntu22.04基于ROS2-Humble安装moveit2教程(亲测)

一、安装ROS2-Humble 1、参考&#xff1a;Ubuntu22.04安装ROS2-humble-CSDN博客 2、确保安装完成 source /opt/ros/humble/setup.bash 方法一&#xff1a;二进制安装 sudo apt install ros-humble-moveit* 方法二&#xff1a;安装源码编译 一、卸载二进制安装包 sudo a…