【C++】_list常用方法解析及模拟实现

2024-09-09 17:20

本文主要是介绍【C++】_list常用方法解析及模拟实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓

目录

  ✨说在前面

🍋知识点一:什么是list?

•🌰1.list的定义

•🌰2.list的基本特性

•🌰3.常用接口介绍

🍋知识点二:list常用接口

•🌰1.默认成员函数

🔥构造函数(⭐)

🔥析构函数

•🌰2.list对象的访问和遍历操作

🔥front、back

🔥迭代器(⭐)

•🌰3.list对象的容量操作

🔥empty

🔥size

•🌰4.list对象的修改操作

🔥push_back、pop_back

🔥push_front、pop_front

🔥insert(⭐)

🔥reverse

🔥merge

🔥sort(⭐)

🔥unique

🔥remove、remove_if

🔥splice

•🌰5.list的模拟实现

 • ✨SumUp结语


  ✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,上一篇文章我给大家介绍了一下vector的定义、常用接口以及模拟实现。如果大家没有掌握好相关的知识,上一篇篇文章讲解地很详细,可以再回去看看,复习一下,再进入今天的内容。

我们今天简单给大家讲解一下STL中的一员——list。ilst对应C语言中的链表,也是STL标准库中的一大容器。如果大家准备好了,那就接着往下看吧~

  👇👇👇
💘💘💘知识连线时刻(直接点击即可)

【C++】_string类字符串万字详细解析

【C++】_vector定义、_vector常用方法解析

  🎉🎉🎉复习回顾🎉🎉🎉

         

 博主主页传送门:愿天垂怜的博客

 ​​​​​

 ​​​​​​

🍋知识点一:什么是list?

•🌰1.list的定义

在C++中,list是一个双向链表容器,它允许在序列的任何位置进行快速的插入和删除操作。与vector(基于数组的连续存储容器)不同,list的元素在内存中不是连续存储的,而是通过指针(或引用)相互连接。这种结构使得list在进行元素插入和删除时不需要移动其他元素,从而提高了这些操作的效率。

我们来看看文档中list的定义:list的文档介绍

那么list的底层是如何实现的呢? 

list的底层实现是一个双向带头循环链表。每个节点(node)包含三个部分:

  1. 数据部分存储元素的值。
  2. 指向前一个节点的指针允许从后向前遍历链表。
  3. 指向下一个节点的指针允许从前向后遍历链表。

这种结构使得list支持高效的插入和删除操作,因为你可以直接修改指针来添加或删除节点,而不需要移动其他元素。然而,由于元素在内存中的非连续存储,list的随机访问(如通过索引直接访问元素)效率较低,因为需要从头或尾开始遍历链表直到找到目标元素。

​​​​​​

•🌰2.list的基本特性

🔥动态大小

 list的大小可以动态地增长和缩小。你可以随时向其中添加或删除元素,而不需要担心容器的容量限制。

🔥非连续存储

 与vector不同,list的元素在内存中不是连续存储的。每个元素都是一个节点,节点之间通过指针(或引用)相互连接。这种非连续存储的特性使得list在进行插入和删除操作时不需要移动其他元素。

 🔥双向遍历

list提供了双向遍历的能力。每个节点都包含指向前一个节点和下一个节点的指针(或引用),这使得你可以轻松地从头遍历到尾,或者从尾遍历到头。

🔥高效的插入和删除

由于list的非连续存储和双向遍历特性,它在序列的任何位置插入或删除元素都是高效的。这些操作通常只需要修改几个指针,而不需要移动其他元素。

🔥不支持随机访问

尽管list提供了灵活的插入和删除操作,但它不支持通过索引直接访问元素。这是因为元素在内存中的位置不连续,无法直接通过索引计算出元素的地址。相反,你需要从头或尾开始遍历链表,直到找到目标元素。

🔥迭代器失效

在list中进行插入或删除操作时,只有指向被插入或删除元素本身的迭代器会失效。其他迭代器(包括指向其他元素的迭代器)仍然保持有效。这与vector不同,后者在插入或删除元素时可能会使所有指向该元素之后元素的迭代器失效。

🔥内存分配

由于list的每个节点都是单独分配的,因此它可能会比vector消耗更多的内存(因为每个节点都需要额外的空间来存储指针)。然而,这种内存分配方式也使得list在处理大量小对象时更加灵活和高效。

🔥排序和搜索

尽管list不支持随机访问,但它仍然提供了排序(如std::sort)和搜索(如std::find)算法。这些算法通过遍历链表来工作,因此它们的效率可能低于在随机访问容器(如vector)上执行的相同算法。

 ​​​​​

•🌰3.常用接口介绍

🔥list对象的常见构造

构造函数( (constructor)接口说明
list (size_type n, const value_type& val = value_type())
构造的 list 中包含 n 个值为 val 元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)[first, last)区间中的元素构造list

🔥list iterator的使用

函数声接口说明
begin + end
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin  rend
返回第一个元素的 reverse_iterator, end 位置 返回最后一个元素下一个位 置的 reverse_iterator, begin 位置 

注意:

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)于rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

 🔥list capacity

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数

🔥list element access

函数声明接口说明
front返回list的第一个节点中值的引用
back返回list的最后一个节点中值的引用

 🔥list modifiers

函数声明接口说明
push_frontlist首元素前插入值为val的元素
pop_front删除list中第一个元素
push_backlist尾部插入值为val的元素
pop_back删除list中最后一个元素
insertlist position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

list中还有一些操作,需要用到时大家可参阅list的文档说明。

 ​​​​​​

🍋知识点二:list常用接口

•🌰1.默认成员函数

🔥构造函数(⭐)

接口如下,前面也有,大家再仔细看看:

 在文档中我们可以查看它们的具体用法: 

我们大家也需要学会查看英文文档,有不懂的就去查,锻炼我们查看英文文章的能力。 

代码示例如下:

#include <iostream>
using namespace std;
#include <list>int main() 
{//test_list1();list<int> first;                                list<int> second(4, 100);                       list<int> third(second.begin(), second.end());  list<int> fourth(third);                    int myints[] = { 16,2,77,29 };list<int> fifth(myints, myints + sizeof(myints) / sizeof(int));return 0;
}

 有效list数据如下:

100 100 100 100
100 100 100 100
100 100 100 100
16 2 77 29

以上这些就是常规操作。那如果我们要遍历它呢?由于list不支持通过索引直接访问元素,所以有两种方式:

1. 利用迭代器

void print_list(const list<int>& lt)
{//迭代器list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}

2. 利用范围for

void print_list(const list<int>& lt)
{//范围forfor (auto& e : lt){cout << e << " ";}cout << endl;
}

 ​​​​​

🔥析构函数

析构函数直接用编译器默认生成、调用的就可以了,非常简单~

 

•🌰2.list对象的访问和遍历操作

🔥front、back

【front】和【back】是两个非常常用的成员函数,它们分别用于访问list容器中的第一个元素和最后一个元素。

front

【front】用于访问list中的第一个元素。调用【front】成员函数时,它返回对列表中第一个元素的引用。如果list为空(即没有任何元素),那么调用【front】会导致未定义行为(通常是程序崩溃),因此在使用之前应该检查list是否为空。

 【front】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList = { 1, 2, 3, 4, 5 };if (!myList.empty()) {cout << "The first element is: " << myList.front() << endl;}else {cout << "The list is empty." << endl;}return 0;
}

back

与【front】类似,【back】用于访问list中的最后一个元素。调用【back】成员函数时,它返回对列表中最后一个元素的引用。同样地,如果list为空,则调用篇【back】会导致未定义行为。 

  【back】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList = { 1, 2, 3, 4, 5 };if (!myList.empty()) {cout << "The last element is: " << myList.back() << endl;}else {cout << "The list is empty." << endl;}return 0;
}

🔥迭代器(⭐)

C++中的迭代器(Iterator)是一种允许你访问容器中元素的对象,而无需暴露容器的内部结构。迭代器提供了一种统一的方法来遍历容器中的所有元素,无论容器的具体类型如何(如数组、向量vector列表list等)。通过使用迭代器,你可以读取、写入或删除容器中的元素,而无需关心容器的具体实现细节。

🔥list iterator的使用

函数声接口说明
begin + end
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin  rend
返回第一个元素的 reverse_iterator, end 位置 返回最后一个元素下一个位 置的 reverse_iterator, begin 位置 

注意:

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2. rbegin(end)于rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

3. 在list中,迭代器并不是原生指针,不能通过+或-来访问对应的节点元素。

	//不能直接加it = lt.begin();lt.erase(it + 3);

 在这里,我们可以对迭代器进行更加深层次的总结:

按照功能划分

按照迭代器的功能,我们可以将迭代器的类型分为iterator、reverse_iterator、const_iterator和const_reverse_iterator,我们再之前的string和vector中都了解过他们的功能。

按照性质划分

按照迭代器的性质,我们可以将迭代器分为单向迭代器、双向迭代器和随机迭代器。

1、单向迭代器

单向迭代器可以向前遍历容器中的元素,但只能++它们来访问下一个元素。你不能通过单向迭代器回退(即,你不能使用--运算符)。单向迭代器至少满足输入迭代器的所有要求,并添加了能够递增自身的能力。

单向迭代器的有:forward_list、unordered map/set...

2、双向迭代器

双向迭代器比单向迭代器更强大,因为它们可以向前遍历容器(递增),还可以向后遍历(递减)。这意味着你可以使用++和--运算符来遍历容器中的元素。

双向迭代器的有:list、map、set...

3、随机迭代器

随机访问迭代器是最强大的迭代器类型,它们支持上述所有操作,并增加了随机访问容器元素的能力。这意味着你可以使用迭代器算术来访问或比较容器中的元素。

随机迭代器的有:vector、string、deque...

也就是说,迭代器的性质是由对应数据结构的底层结构所决定的。

•🌰3.list对象的容量操作

list对象的容量操作比较简单,我们介绍一下三个:

或如下: 

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数

🔥empty

【empty】是list容器的一个成员函数,用于检查该容器是否为空

  【empty】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList;  if (myList.empty()) {cout << "List is empty." << endl;}else {cout << "List is not empty." << endl;} myList.push_back(10);myList.push_back(20);if (myList.empty()) {cout << "List is empty." << endl;}else {cout << "List is not empty." << endl;}return 0;
}

运行结果:

List is empty.
List is not empty.

🔥size

【size】是一个非常重要的成员函数,它用于返回容器中元素的数量。这是一个只读操作,其时间复杂度为常数时间O(1),因为list内部通常维护了一个表示元素数量的计数器。

【size】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList = { 1, 2, 3, 4, 5 };cout << "The size of myList is: " << myList.size() << endl;myList.push_back(6);cout << "After adding an element, the size of myList is: " << myList.size() << endl;return 0;
}

输出将会是:

The size of myList is: 5  
After adding an element, the size of myList is: 6

 ​​​​​

•🌰4.list对象的修改操作

🔥push_back、pop_back

push_back

【push_back】用于在list的末尾添加一个元素。这个操作的时间复杂度是常数时间O(1),因为它只是简单地修改链表末尾的节点来指向新添加的节点,并更新链表的尾部指针。

 【push_back】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList;myList.push_back(10);myList.push_back(20);for (int n : myList) {cout << n << " ";}cout << endl;return 0;
}

注意:在list的成员函数中,有一个叫作【emplace_back】的成员函数。它的功能类似于【push_back】,但是它们有本质上的区别。

在我们现在的阶段,暂时理解一下的区别即可:

struct A
{
public:A(int a1 = 1, int a2 = 2):_a1(a1),_a2(a2){cout << "A(int a1 = 1, int a2 = 2)" << endl;}int _a1;int _a2;A(const A& aa):_a1(aa._a1),_a2(aa._a2){cout << "A(const A& aa)" << endl;}
};
void test_list2()
{list<int> lt1;lt1.push_back(1);lt1.emplace_back(2);lt1.emplace_back(3);lt1.emplace_back(4);lt1.emplace_back(5);print_list(lt1);list<A> lt2;//有名对象A aa1(1, 2);lt2.push_back(aa1);//匿名对象lt2.push_back(A(1, 2));//隐式类型转换lt2.push_back({ 1, 2 });//而emplace back支持直接传构造A对象的参数lt2.emplace_back((1, 2));
}

pop_back

【pop_back】用于移除list的最后一个元素。与【push_back】一样,这个操作的时间复杂度也是常数时间O(1)。它简单地删除链表末尾的节点,并更新链表的尾部指针。

 【pop_back】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList;myList.push_back(10);myList.push_back(20);if (!myList.empty()) {myList.pop_back();}for (int n : myList) {cout << n << ' ';}return 0;
}

 ​​​​​

🔥push_front、pop_front

push_front

【push_front】用于在list的开头添加一个元素。这个操作的时间复杂度是常数时间O(1),因为它只是简单地创建一个新节点,将其指向当前列表的第一个节点,并更新列表的头部指针以指向这个新节点。

【push_front】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList;myList.push_front(10);myList.push_front(20);for (int n : myList) {cout << n << " ";}return 0;
}

 pop_front

 【pop_front】用于移除list的第一个元素。与【push_front】一样,这个操作的时间复杂度也是常数时间O(1)。它简单地删除列表的第一个节点,并更新列表的头部指针以指向下一个节点。

【pop_front】使用示例:

#include <iostream>  
using namespace std;
#include <list>  int main() 
{list<int> myList;myList.push_front(10);myList.push_front(20);if (!myList.empty()) {myList.pop_front();}for (int n : myList) {std::cout << n << " ";}return 0;
}

 ​​​​​

🔥insert(⭐)

🔥reverse

【reverse】没有参数,也不返回任何值。它的作用是就地(in-place)反转list中元素的顺序。这意味着原始容器被直接修改,而不是创建一个新的反转后的容器。

 【reverse】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> myList = { 1, 2, 3, 4, 5 };cout << "原始list: ";for (int num : myList) {cout << num << " ";}cout << endl;myList.reverse();cout << "反转后的list: ";for (int num : myList){cout << num << " ";}cout << endl;return 0;
}

输出将会是:

原始list: 1 2 3 4 5   
反转后的list: 5 4 3 2 1

 ​​​​​

🔥merge

【merge】用于合并两个已排序的list容器。与通用【merge】算法(定义在<algorithm>头文件中,用于合并两个已排序的范围)不同,list的【merge】成员函数是专门为链表设计的,并且它直接在原链表上操作,而不需要额外的存储空间来存储合并后的结果。

【merge】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> list1 = { 1, 3, 5 };list<int> list2 = { 2, 4, 6 };//合并list1和list2,list2的内容将被移动到list1中,且list2将变为空  list1.merge(list2);for (int num : list1) {std::cout << num << " ";}std::cout << std::endl; //输出: 1 2 3 4 5 6  // list2现在是空的  if (list2.empty()) {std::cout << "list2 is empty after merge." << std::endl;}return 0;
}

 注意:

1. 在调用【merge】之前,两个list必须已经是有序的。如果它们不是有序的,则合并后的结果将不是有序的。

2. 【merge】函数会修改调用它的list对象,并清空另一个list对象(other)。

 ​​​​​

🔥sort(⭐)

list是一个双向链表,它不支持随机访问迭代器,因此不能直接使用通用【sort】算法进行排序。但是list提供了自己的【sort】成员函数,该函数使用链表特有的排序算法(如归并排序或某种形式的插入排序),以就地(in-place)方式对链表中的元素进行排序

【sort】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> myList = { 4, 1, 3, 5, 2 };myList.sort();  for (int num : myList){cout << num << " ";}cout << endl;return 0;
}

与通用【sort】对比

1. 适用容器

通用【sort】算法适用于支持随机访问迭代器的容器(如vector、deque),而list的【sort】成员函数仅适用于list。

2. 性能

对于list,使用其【sort】成员函数通常比尝试使用通用【sort】算法更高效,因为list的【sort】成员函数利用了链表的结构特性。然而,对于支持随机访问的容器,通用【sort】算法通常能提供更快的排序速度。

3. 稳定性

两者都提供稳定的排序,即相等元素的相对顺序在排序后保持不变。

4. 用法

通用【sort】算法需要指定排序范围的开始和结束迭代器,而list的【sort】成员函数则不需要,因为它直接作用于整个链表。此外,通用【sort】算法允许指定自定义的比较函数或函数对象,而list的【sort】成员函数也支持这一点,但通常是通过成员函数模板的重载来实现的。

测试算法库中【sort】和list中【sort】的性能:

//测试算法库中sort和list中sort的性能
void test_op1()
{srand((unsigned int)time(nullptr));const int N = 1000000;list<int> lt;vector<int> v;for (size_t i = 0; i < N; i++){auto e = rand() + i;lt.push_back(e);v.push_back(e);}//排序int begin1 = clock();sort(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt.sort();int end2 = clock();printf("vector sort:%d\n", end1 - begin1);printf("list1 sort:%d\n", end2- begin2);
}

在Release版本下的其一运行结果为:

vector sort:61
list sort:128

再看另外一个代码:

void test_op2()
{srand(time(0));const int N = 1000000;list<int> lt1;list<int> lt2;for (int i = 0; i < N; i++){auto e = rand() + i;lt1.push_back(e);lt2.push_back(e);}int begin1 = clock();//拷贝vectorvector<int> v(lt2.begin(), lt2.end());//排序sort(v.begin(), v.end());//拷贝回lt2lt2.assign(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt1.sort();int end2 = clock();printf("list copy vector sort copy list sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}

 其中lt2先拷贝到vector上用库里的【sort】进行排序,然后lt1依然调用自身的【sort】,我们来看其中一个运行结果:

list copy vector sort copy list sort:82
list sort:191

 显然在数据量比较大的时候,list尽量不要用它自己的【sort】进行排序。

 ​​​​​

🔥unique

【unique】用于移除容器中连续重复的元素,只保留每个元素组中的第一个元素。注意,这里的“重复”是指相邻元素的相等性,而不是在整个容器范围内的唯一性。【unique】函数通过比较相邻元素来工作,如果两个相邻元素相等,则删除第二个元素。

【unique】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> myList = { 1, 2, 2, 3, 4, 4, 4, 5 };myList.unique();for (int num : myList) {cout << num << " ";}cout << endl; //输出: 1 2 3 4 5  return 0;
}

 ​​​​​

remove 

🔥remove、remove_if

【remove】接受一个值作为参数,并移除容器中所有等于该值的元素。它使用元素的==运算符来比较元素与给定值。

 【remove】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> myList = { 1, 2, 3, 2, 4, 2, 5 };myList.remove(2);for (int num : myList) {cout << num << " ";}cout << endl;//输出: 1 3 4 5  return 0;
}

remove_if

如果你希望删除的不是某个特定值的元素,而是满足某个条件的元素,此时就可以使用【remove_if】。【remove_if】接受一个谓词(即一个返回布尔值的函数或函数对象)作为参数,并移除容器中所有使该谓词返回true的元素。

 【remove_if】使用示例: 

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> myList = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//这里使用了lambda表达式作为谓词 myList.remove_if([](int i) { return i <= 5; });for (int num : myList) {cout << num << " ";}cout << endl;//输出: 6 7 8 9  return 0;
}

 ​​​​​

🔥splice

【splice】用于合并两个list容器中的部分或全部元素,同时保持元素的相对顺序不变。与list的其他成员函数相比,【splice】函数的一个显著优点是它可以在不复制或移动元素的情况下重新排列元素,这就更加高效了,特别是对于大型容器或包含复杂对象的容器。

 【splice】使用示例:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> list1 = { 1, 2, 3, 4, 5 };list<int> list2 = { 6, 7, 8, 9, 10 };//将list2的所有元素移动到list1的开头  auto it = list1.begin();list1.splice(it, list2);//输出处理后的list1  for (int num : list1) {cout << num << " ";}cout << endl;//输出: 6 7 8 9 10 1 2 3 4 5  return 0;
}

【splice】不仅可以将一个链表的节点转移到另一个链表,也可以调整当前链表的顺序。比如我们想将[1,2,3,4,5,6]中的某个元素后面的节点移动到最前面,我们可以:

#include <iostream>
using namespace std;
#include <list>int main() 
{list<int> lt = { 1, 2, 3, 4, 5, 6};int x = 0;cin >> x;list<int>::iterator it = find(lt.begin(), lt.end(), x);if (it != lt.end()){lt.splice(lt.begin(), lt, it, lt.end());}return 0;
}

list2现在是空的,因为没有元素被复制或移动到list1,而是被重新链接到了list1上。  

 ​​​​​

•🌰5.list的模拟实现

list这块的源代码可以参考:list的源码

源代码看明白是有些难度的,我们可以结合这一篇文章,再参考一下我写的模拟实现:list模拟实现

 • ✨SumUp结语

到这里本篇文章的内容就结束了,本节介绍了C++中list的相关知识。这里的内容虽然很熟悉了,毕竟我们有了string和vector的基础,但是有一定的难度。希望大家能够认真学习,打好基础,迎接接下来的挑战,期待大家继续捧场~💖💖💖

这篇关于【C++】_list常用方法解析及模拟实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1151794

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time