C++STL:顺序容器之list

news2024/9/23 1:37:36

文章目录

  • 1. 概述
  • 2. 成员函数
  • 3. list容器的创建
  • 4. 迭代器
  • 5. 访问元素
  • 6. 添加/插入元素
    • list insert()成员方法
    • list splice()成员方法
  • 7. 删除元素

1. 概述

STL list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。 下图展示了 list 双向链表容器是如何存储元素的:

在这里插入图片描述

可以看到,list 容器中各个元素的前后顺序是靠指针来维系的,每个元素都配备了 2 个指针,分别指向它的前一个元素和后一个元素。其中第一个元素的前向指针总为 null,因为它前面没有元素;同样,尾部元素的后向指针也总为 null。

基于这样的存储结构,list 容器具有一些其它容器(array、vector 和 deque)所不具备的优势,即它可以在序列已知的任何位置快速插入或删除元素(时间复杂度为O(1)),并且在 list 容器中移动元素,也比其它容器的效率高。

使用 list 容器的缺点是,它不能像 array 和 vector 那样,通过位置直接访问元素。举个例子,如果要访问 list 容器中的第 6 个元素,它不支持容器对象名[6]这种语法格式,正确的做法是从容器中第一个元素或最后一个元素开始遍历容器,直到找到该位置。

实际场景中,如何需要对序列进行大量添加或删除元素的操作,而直接访问元素的需求却很少,这种情况建议使用 list 容器存储序列。

list 容器以模板类 list<T>(T 为存储元素的类型)的形式在<list>头文件中,并位于 std 命名空间中。因此,在使用该容器之前,代码中需要包含下面两行代码:

#include <list>
using namespace std;

注意,std 命名空间也可以在使用 list 容器时额外注明,两种方式都可以。

2. 成员函数

成员函数功能
begin()返回指向容器中第一个元素的双向迭代器。
end()返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。
rbegin()返回指向最后一个元素的反向双向迭代器。
rend()返回指向第一个元素所在位置前一个位置的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
size()返回当前容器实际包含的元素个数。
max_size()返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 2^32-1,所以我们很少会用到这个函数。
front()返回第一个元素的引用。
back()返回最后一个元素的引用。
assign()用新元素替换容器中原有内容。
emplace_front()在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。
push_front()在容器头部插入一个元素。
pop_front()删除容器头部的一个元素。
emplace_back()在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。
push_back()在容器尾部插入一个元素。
pop_back()删除容器尾部的一个元素。
emplace()在容器中的指定位置插入元素。该函数和 insert() 功能相同,但效率更高。
insert()在容器中的指定位置插入元素。
erase()删除容器中一个或某区域内的元素。
swap()交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
resize()调整容器的大小。
clear()删除容器存储的所有元素。
splice()将一个 list 容器中的元素插入到另一个容器的指定位置。
remove(val)删除容器中所有等于 val 的元素。
remove_if()删除容器中满足条件的元素。
unique()删除容器中相邻的重复元素,只保留一个。
merge()合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。
sort()通过更改容器中元素的位置,将它们进行排序。
reverse()反转容器中元素的顺序。

除此之外,C++ 11 标准库还新增加了 begin() 和 end() 这 2 个函数,和 list 容器包含的 begin() 和 end() 成员函数不同,标准库提供的这 2 个函数的操作对象,既可以是容器,还可以是普通数组。当操作对象是容器时,它和容器包含的 begin() 和 end() 成员函数的功能完全相同;如果操作对象是普通数组,则 begin() 函数返回的是指向数组第一个元素的指针,同样 end() 返回指向数组中最后一个元素之后一个位置的指针(注意不是最后一个元素)。

list 容器还有一个std::swap(x , y)非成员函数(其中 x 和 y 是存储相同类型元素的 list 容器),它和 swap() 成员函数的功能完全相同,仅使用语法上有差异。

3. list容器的创建

根据不同的使用场景,有以下 5 种创建 list 容器的方式供选择。

  1. 创建一个没有任何元素的空 list 容器:
std::list<int> values;

和空 array 容器不同,空的 list 容器在创建之后仍可以添加元素,因此创建 list 容器的方式很常用。

  1. 创建一个包含 n 个元素的 list 容器:
std::list<int> values(10);

通过此方式创建 values 容器,其中包含 10 个元素,每个元素的值都为相应类型的默认值(int 类型的默认值为 0)。

  1. 创建一个包含 n 个元素的 list 容器,并为每个元素指定初始值。例如:
std::list<int> values(10, 5);

如此就创建了一个包含 10 个元素并且值都为 5 的 values 容器。

  1. 在已有 list 容器的情况下,通过拷贝该容器可以创建新的 list 容器。例如:
std::list<int> value1(10);
std::list<int> value2(value1);

注意,采用此方式,必须保证新旧容器存储的元素类型一致。

  1. 通过拷贝其他类型容器(或者普通数组)中指定区域内的元素,可以创建新的 list 容器。例如:
// 拷贝普通数组,创建list容器
int a[] = { 1,2,3,4,5 };
std::list<int> values(a, a+5);
// 拷贝其它类型的容器,创建 list 容器
std::array<int, 5> arr{ 11,12,13,14,15 };
std::list<int> alues(arr.begin()+2, arr.end());	// 拷贝arr容器中的{13,14,15}

4. 迭代器

只有运用迭代器,才能访问 list 容器中存储的各个元素。list 模板类提供了如下表所示的这些迭代器函数:

迭代器函数功能
begin()返回指向容器中第一个元素的双向迭代器(正向迭代器)。
end()返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。(正向迭代器)。
rbegin()返回指向最后一个元素的反向双向迭代器。
rend()返回指向第一个元素所在位置前一个位置的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,正向迭代器增加了 const 属性,即不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上,正向迭代器增加了 const 属性,即不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过在其基础上,反向迭代器增加了 const 属性,即不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上,反向迭代器增加了 const 属性,即不能用于修改元素。

除此之外,C++ 11 新添加的 begin() 和 end() 全局函数也同样适用于 list 容器。即当操作对象为 list 容器时,其功能分别和上表中的 begin()、end() 成员函数相同。

这些成员函数通常是成对使用的,即 begin()/end()、rbegin()/rend()、cbegin()/cend()、crbegin()/crend() 各自成对搭配使用。其中,begin()/end() 和 cbegin/cend() 的功能是类似的,同样 rbegin()/rend() 和 crbegin()/crend() 的功能是类似的。

前面章节已经详细介绍了 array、vector、deque 容器的迭代器,和它们相比,list 容器迭代器最大的不同在于,其配备的迭代器类型为双向迭代器,而不再是随机访问迭代器。这意味着,假设 p1 和 p2 都是双向迭代器,则它们支持使用 ++p1p1++p1--p1++*p1p1==p2 以及 p1!=p2 运算符,但不支持以下操作(其中 i 为整数):

  • p1[i]:不能通过下标访问 list 容器中指定位置处的元素。
  • p1-=ip1+=ip1+ip1-i:双向迭代器 p1 不支持使用 -=、+=、+、- 运算符。
  • p1<p2p1>p2p1<=p2p1>=p2:双向迭代器 p1、p2 不支持使用 <、 >、 <=、 >= 比较运算符。

下面这个程序演示了如何使用迭代器遍历 list 容器中的各个元素:

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

int main()
{
    // 创建 list 容器
    std::list<char> values{'h','t','t','p',':','/','/','c','.','b','i','a','n','c','h','e','n','g','.','n','e','t'};
    // 使用begin()/end()迭代器函数对输出list容器中的元素
    for (std::list<char>::iterator it = values.begin(); it != values.end(); ++it) {
        std::cout << *it;
    }
    cout << endl;
    // 使用 rbegin()/rend()迭代器函数输出 lsit 容器中的元素
    for (std::list<char>::reverse_iterator it = values.rbegin(); it != values.rend();++it) {
        std::cout << *it;
    }
    return 0;
}

输出结果为:

http://c.biancheng.net
ten.gnehcnaib.c//:ptth

注意,程序中比较迭代器之间的关系,用的是 != 运算符,因为它不支持 < 等运算符。另外在实际场景中,所有迭代器函数的返回值都可以传给使用 auto 关键字定义的变量,因为编译器可以自行判断出该迭代器的类型。

值得一提的是,list 容器在进行插入(insert())、接合(splice())等操作时,都不会造成原有的 list 迭代器失效,甚至进行删除操作,而只有指向被删除元素的迭代器失效,其他迭代器不受任何影响。举个例子:

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

int main()
{
    // 创建 list 容器
    std::list<char> values{'h','t','t','p',':','/','/','c','.','b','i','a','n','c','h','e','n','g','.','n','e','t'};
    // 创建 begin 和 end 迭代器
    std::list<char>::iterator begin = values.begin();
    std::list<char>::iterator end = values.end();
    // 头部和尾部插入字符 '1'
    values.insert(begin, '1');
    values.insert(end, '1');
    while (begin != end)
    {
        std::cout << *begin;
        ++begin;
    }
    return 0;
}

运行结果为:

http://c.biancheng.net1

可以看到,在进行插入操作之后,仍使用先前创建的迭代器遍历容器,虽然程序不会出错,但由于插入位置的不同,可能会遗漏新插入的元素。

5. 访问元素

不同于之前学过的 STL 容器,访问 list 容器中存储元素的方式很有限,即要么使用 front() 和 back() 成员函数,要么使用 list 容器迭代器。

list 容器不支持随机访问,未提供下标操作符 [] 和 at() 成员函数,也没有提供 data() 成员函数。

  1. 通过 front() 和 back() 成员函数,可以分别获得 list 容器中第一个元素和最后一个元素的引用形式。举个例子:
#include <iostream>
#include <list>
using namespace std;

int main()
{
    std::list<int> mylist{ 1,2,3,4 };
    int &first = mylist.front();
    int &last = mylist.back();
    cout << first << " " << last << endl;
    first = 10;
    last = 20;
    cout << mylist.front() << " " << mylist.back() << endl;
    return 0;
}

输出结果为:

1 4
10 20

可以看到,通过 front() 和 back() 的返回值,我们不仅能分别获取当前 list 容器中的首尾元素,必要时还能修改它们的值。

  1. 除此之外,如果想访问 list 容存储的其他元素,就只能使用 list 容器的迭代器。例如:
#include <iostream>
#include <list>
using namespace std;

int main()
{
    const std::list<int> mylist{1,2,3,4,5};
    auto it = mylist.begin();
    cout << *it << " ";
    ++it;
    while (it!=mylist.end())
    {
        cout << *it << " ";
        ++it;  
    }
    return 0;
}

运行结果为:

1 2 3 4 5

值得一提的是,对于非 const 类型的 list 容器,迭代器不仅可以访问容器中的元素,也可以对指定元素的值进行修改。

当然,对于修改容器指定元素的值,list 模板类提供有专门的成员函数 assign()。

6. 添加/插入元素

list 模板类中,与“添加或插入新元素”相关的成员方法有如下几个:

  • push_front():向 list 容器首个元素前添加新元素;
  • push_back():向 list 容器最后一个元素后添加新元素;
  • emplace_front():在容器首个元素前直接生成新的元素;
  • emplace_back():在容器最后一个元素后直接生成新的元素;
  • emplace():在容器的指定位置直接生成新的元素;
  • insert():在指定位置插入新元素;
  • splice():将其他 list 容器存储的多个元素添加到当前 list 容器的指定位置处。

以上这些成员方法中,除了 insert() 和 splice() 方法有多种语法格式外,其它成员方法都仅有 1 种语法格式。下面程序演示了它们的具体用法:

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

int main()
{
    std::list<int> values{1,2,3};
    values.push_front(0);//{0,1,2,3}
    values.push_back(4); //{0,1,2,3,4}
    values.emplace_front(-1);//{-1,0,1,2,3,4}
    values.emplace_back(5);  //{-1,0,1,2,3,4,5}
   
    // emplace(pos,value),其中 pos 表示指明位置的迭代器,value为要插入的元素值
    values.emplace(values.end(), 6);//{-1,0,1,2,3,4,5,6}
    for (auto p = values.begin(); p != values.end(); ++p) {
        cout << *p << " ";
    }
    return 0;
}

输出结果为:

-1,0,1,2,3,4,5,6

list insert()成员方法

insert() 成员方法的语法格式有 4 种,如下表所示:

语法格式用法说明
iterator insert(pos,elem)在迭代器 pos 指定的位置之前插入一个新元素 elem,并返回表示新插入元素位置的迭代器。
iterator insert(pos,n,elem)在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,first,last)在迭代器 pos 指定的位置之前,插入其他容器(例如 array、vector、deque 等)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,initlist)在迭代器 pos 指定的位置之前,插入初始化列表(用大括号 { } 括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。

下面的程序演示了如何使用 insert() 方法向 list 容器中插入元素:

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

int main()
{
    std::list<int> values{ 1,2 };
    // 第一种格式用法
    values.insert(values.begin() , 3); // {3,1,2}
    // 第二种格式用法
    values.insert(values.end(), 2, 5); // {3,1,2,5,5}
    // 第三种格式用法
    std::array<int, 3>test{ 7,8,9 };
    values.insert(values.end(), test.begin(), test.end()); // {3,1,2,5,5,7,8,9}
    // 第四种格式用法
    values.insert(values.end(), { 10,11 }); // {3,1,2,5,5,7,8,9,10,11}
    for (auto p = values.begin(); p != values.end(); ++p)
    {
        cout << *p << " ";
    }
    return 0;
}

输出结果为:

3 1 2 5 5 7 8 9 10 11

同样是实现插入元素的功能,无论是 push_front()、push_back() 还是 insert(),都有以 emplace 为名且功能和前者相同的成员函数。这是因为,后者是 C++ 11 标准新添加的,在大多数场景中,都可以完全替代前者实现同样的功能。更重要的是,实现同样的功能,emplace 系列方法的执行效率更高。

list splice()成员方法

和 insert() 成员方法相比,splice() 成员方法的作用对象是其它 list 容器,其功能是将其它 list 容器中的元素添加到当前 list 容器中指定位置处。

splice() 成员方法的语法格式有 3 种,如下表所示:

语法格式功能
void splice (iterator position, list& x);position 为迭代器,用于指明插入位置;x 为另一个 list 容器。 此格式的 splice() 方法的功能是,将 x 容器中存储的所有元素全部移动当前 list 容器中 position 指明的位置处。
void splice (iterator position, list& x, iterator i);position 为迭代器,用于指明插入位置;x 为另一个 list 容器;i 也是一个迭代器,用于指向 x 容器中某个元素。 此格式的 splice() 方法的功能是将 x 容器中 i 指向的元素移动到当前容器中 position 指明的位置处。
void splice (iterator position, list& x, iterator first, iterator last);position 为迭代器,用于指明插入位置;x 为另一个 list 容器;first 和 last 都是迭代器,[fist,last) 用于指定 x 容器中的某个区域。 此格式的 splice() 方法的功能是将 x 容器 [first, last) 范围内所有的元素移动到当前容器 position 指明的位置处。

我们知道,list 容器底层使用的是链表存储结构,splice() 成员方法移动元素的方式是,将存储该元素的节点从 list 容器底层的链表中摘除,然后再链接到当前 list 容器底层的链表中。这意味着,当使用 splice() 成员方法将 x 容器中的元素添加到当前容器的同时,该元素会从 x 容器中删除。

下面程序演示了 splice() 成员方法的用法:

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

int main()
{
    // 创建并初始化 2 个 list 容器
    list<int> mylist1{ 1,2,3,4 }, mylist2{10,20,30};
    list<int>::iterator it = ++mylist1.begin(); // 指向 mylist1 容器中的元素 2
   
    // 调用第一种语法格式
    mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4
                                 // mylist2:
                                 // it 迭代器仍然指向元素 2,只不过容器变为了 mylist1
    // 调用第二种语法格式,将 it 指向的元素 2 移动到 mylist2.begin() 位置处
    mylist2.splice(mylist2.begin(), mylist1, it);   // mylist1: 1 10 20 30 3 4
                                                    // mylist2: 2
                                                    // it 仍然指向元素 2
   
    // 调用第三种语法格式,将 [mylist1.begin(),mylist1.end())范围内的元素移动到 mylist.begin() 位置处                  
    mylist2.splice(mylist2.begin(), mylist1, mylist1.begin(), mylist1.end()); // mylist1:
                                                                              // mylist2:1 10 20 30 3 4 2
   
    cout << "mylist1 包含 " << mylist1.size() << "个元素" << endl;
    cout << "mylist2 包含 " << mylist2.size() << "个元素" << endl;
    // 输出 mylist2 容器中存储的数据
    cout << "mylist2:";
    for (auto iter = mylist2.begin(); iter != mylist2.end(); ++iter) {
        cout << *iter << " ";
    }
    return 0;
}

程序执行结果为:

mylist1 包含 0个元素
mylist2 包含 7个元素
mylist2:1 10 20 30 3 4 2

7. 删除元素

对 list 容器存储的元素执行删除操作,需要借助该容器模板类提供的成员函数。幸运的是,相比其它 STL 容器模板类,list 模板类提供了更多用来实现此操作的成员函数,如下表所示:

成员函数功能
pop_front()删除位于 list 容器头部的一个元素。
pop_back()删除位于 list 容器尾部的一个元素。
erase()该成员函数既可以删除 list 容器中指定位置处的元素,也可以删除容器中某个区域内的多个元素。
clear()删除 list 容器存储的所有元素。
remove(val)删除容器中所有等于 val 的元素。
unique()删除容器中相邻的重复元素,只保留一份。
remove_if()删除容器中满足条件的元素。
  1. 其中,pop_front()、pop_back() 和 clear() 的用法非常简单,这里仅给出一个样例,不再过多解释:
#include <iostream>
#include <list>
using namespace std;

int main()
{
    list<int>values{ 1,2,3,4 };
   
    // 删除当前容器中首个元素
    values.pop_front();//{2,3,4}
   
    // 删除当前容器最后一个元素
    values.pop_back();//{2,3}
   
    // 清空容器,删除容器中所有的元素
    values.clear(); //{}
   
    for (auto begin = values.begin(); begin != values.end(); ++begin)
    {
        cout << *begin << " ";
    }
    return 0;
}

运行程序,可以看到输出结果为“空”。

  1. erase() 成员函数有以下 2 种语法格式:
iterator erase (iterator position);
iterator erase (iterator first, iterator last);

利用第一种语法格式,可实现删除 list 容器中 position 迭代器所指位置处的元素,例如:

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

int main()
{
    list<int> values{ 1,2,3,4,5 };
    // 指向元素 1 的迭代器
    auto del = values.begin();
    // 迭代器右移,改为指向元素 2
    ++del;
    values.erase(del); // {1,3,4,5}
    for (auto begin = values.begin(); begin != values.end(); ++begin)
    {
        cout << *begin << " ";
    }
    return 0;
}

运行结果为:

1 3 4 5

利用第二种语法格式,可实现删除 list 容器中 first 迭代器和 last 迭代器限定区域内的所有元素(包括 first 指向的元素,但不包括 last 指向的元素)。例如:

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

int main()
{
    list<int> values{ 1,2,3,4,5 };
    // 指定删除区域的左边界
    auto first = values.begin();
    ++first; // 指向元素 2
    // 指向删除区域的右边界
    auto last = values.end();
    --last; // 指向元素 5
    // 删除 2、3 和 4
    values.erase(first, last);
    for (auto begin = values.begin(); begin != values.end(); ++begin)
    {
        cout << *begin << " ";
    }
    return 0;
}

运行结果为:

1 5
  1. erase() 成员函数是按照被删除元素所在的位置来执行删除操作,如果想根据元素的值来执行删除操作,可以使用 remove() 成员函数。例如:
#include <iostream>
#include <list>
using namespace std;

int main()
{
    list<char> values{'a','b','c','d'};
    values.remove('c');
    for (auto begin = values.begin(); begin != values.end(); ++begin)
    {
        cout << *begin << " ";
    }
    return 0;
}

运行结果为:

a b d
  1. unique() 函数也有以下 2 种语法格式:
void unique()
void unique(BinaryPredicate)// 传入一个二元谓词函数

以上 2 种格式都能实现去除 list 容器中相邻重复的元素,仅保留一份。但第 2 种格式的优势在于,我们能自定义去重的规则,例如:

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

// 二元谓词函数
bool demo(double first, double second)
{
    return (int(first) == int(second));
}
int main()
{
    list<double> mylist{ 1,1.2,1.2,3,4,4.5,4.6 };
    // 删除相邻重复的元素,仅保留一份
    mylist.unique(); // {1, 1.2, 3, 4, 4.5, 4.6}
    for (auto it = mylist.begin(); it != mylist.end(); ++it)
        cout << *it << ' ';
    cout << endl;
    // demo 为二元谓词函数,是我们自定义的去重规则
    mylist.unique(demo);
    for (auto it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << *it << ' ';
    return 0;
}

运行结果为:

1 1.2 3 4 4.5 4.6
1 3 4

注意,除了以上一定谓词函数的方式,还可以使用 lamba表达式以及函数对象的方式定义。

可以看到,通过调用无参的 unique(),仅能删除相邻重复(也就是相等)的元素,而通过我们自定义去重的规则,可以更好的满足在不同场景下去重的需求。

  1. 除此之外,通过将自定义的谓词函数(不限定参数个数)传给 remove_if() 成员函数,list 容器中能使谓词函数成立的元素都会被删除。举个例子:
#include <iostream>
#include <list>
using namespace std;

int main()
{
    std::list<int> mylist{ 15, 36, 7, 17, 20, 39, 4, 1 };
    // 删除 mylist 容器中能够使 lamba 表达式成立的所有元素。
    mylist.remove_if([](int value) {return (value < 10); }); // {15 36 17 20 39}
    for (auto it = mylist.begin(); it != mylist.end(); ++it)
        std::cout << ' ' << *it;
    return 0;
}

运行结果为:

15 36 17 20 39

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

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

相关文章

RTOS学习笔记

前言 进程&#xff1f;线程&#xff1f;并发&#xff1f;并行&#xff1f;主线程&#xff1f;子线程&#xff1f;主线程中创建子线程&#xff1f;每个线程就是一个死循环&#xff1f; 进程 多个线程&#xff0c;每个线程可以写一个死循环处理一个需要循环执行的代码块&#x…

leetcode-203.移除链表元素

leetcode-203.移除链表元素 文章目录 leetcode-203.移除链表元素题目描述代码提交 题目描述 代码提交 代码 class Solution { public:ListNode* removeElements(ListNode* head, int val) {ListNode *dummyhead new ListNode(0); // 设置一个虚拟头结点,堆上dummyhead->ne…

SOLIDWORKS、UG、Proe三款三维绘图软件哪个好?

提到制图&#xff0c;很多人可能会先想到AutoCAD&#xff0c;但它现在主要会被用来进行二维的平面制图。3DMAX是一款被广泛应用的三维制图软件。Proe也是一种比较好用的三维建模软件。而SW也就是SolidWorks更为知名&#xff0c;它是世界上第一个专为Windows系统开发的三维CAD建…

解决小程序 scroll-view 里面的image有间距、小程序里面的图片之间有空隙的问题。

1&#xff09;小程序 image跟view标签上下会有间隙&#xff0c;解决方法如下&#xff1a; 在image那里设置vertical-align:top/bottom/text-top/text-bottom 原因&#xff1a;图片文字等inline元素默许是跟父级元素的baseline对齐&#xff0c;而baseline又和父级底边有必定间距…

web 前端 Day 3

伪类选择器 <title>伪类选择器</title> </head> <style>a:link {color: beige;} a:visited {color: aquamarine; } a:hover { 鼠标悬停cursor: cell; 鼠标样式font-size: 80px; } a:active {font-size: 70px; } div{width: 300px;height: 400…

813. 打印矩阵

链接&#xff1a; 打印矩阵 题目&#xff1a; 给定一个 rowcolrowcol 的二维数组 aa&#xff0c;请你编写一个函数&#xff0c;void print2D(int a[][N], int row, int col)&#xff0c;打印数组构成的 rowrow 行&#xff0c;colcol 列的矩阵。 注意&#xff0c;每打印完一整行…

JPA的saveAndFlush

#Stable Diffusion 美图活动一期# 关于MyBatis与JPA&#xff1a; 笔者初次接触这两个持久层框架的时候&#xff0c;那还是得从iBatis、Hibernate开始说起。那时候知道的一个很浅显、但最明显的区别就是&#xff1a;iBatis是半自动化的ORM框架&#xff0c;适用于表关联关系复杂的…

浅谈利用树莓派卡片电脑进行图像识别学习和研发

利用树莓派进行图像识别学习和研发是一个非常有前景和潜力的领域。树莓派是一款小巧且功能强大的单板计算机&#xff0c;具备较高的处理能力和丰富的接口&#xff0c;非常适合用于图像识别的应用开发。 在图像识别方面&#xff0c;树莓派可以利用其强大的计算能力和丰富的软件…

react知识点汇总四--react router 和 redux

react-router React-Router 是一个用于在 React 应用中实现页面导航和路由管理的库。它提供了一种方式来创建单页应用&#xff08;Single-Page Application&#xff0c;SPA&#xff09;&#xff0c;其中页面的切换是在客户端进行的&#xff0c;而不需要每次跳转都向服务器请求…

Mac上绿色软件怎么长期保存

1、找到想长期保存的绿色软件&#xff0c;右键拷贝 2、来到「应用程序」&#xff0c;点工具栏-操作-粘贴项目 3、这样绿色软件就长期保留下来了

华纳云:一台香港多IP服务器如何设置多个IP?

在一台香港多IP服务器上设置多个IP的步骤如下&#xff1a; 1.确认服务器支持多个IP地址&#xff1a;首先&#xff0c;确保你的服务器有多个网卡接口或虚拟网卡接口&#xff0c;以支持多个IP地址。 2.查看当前IP配置&#xff1a;运行以下命令来查看当前的IP配置信息&#xff1a;…

深度学习——神经网络参数的保存和提取

代码与详细注释&#xff1a; Talk is cheap. Show you the code&#xff01; import torch import matplotlib.pyplot as plt# 造数据 x torch.unsqueeze(torch.linspace(-1, 1, 100), dim1) # x data (tensor), shape(100, 1) y x.pow(2) 0.2*torch.rand(x.size()) # n…

unity 调用高德SDK

unity 2022.2.20f1c1 一、准备工作&#xff1a; 方式一&#xff1a;Unity打包arr 导入AndroidStudio &#xff0c;AndroidStudio打包 方式二&#xff1a;Unity通过MainActivity.java调用SDK &#xff0c;MainActivity.java 放入到Android Studio中编写代码 二、打包环境…

数字化时代,企业的数据指标体系

在社会节奏越来越快&#xff0c;处理的信息量越来越大的今天&#xff0c;传统的经营管理模式已经适应不了当下的环境。而由经验、情感组成的业务调整以及决策能力不再能正确指导企业走在正确的方向上&#xff0c;所以数据就成为了企业新的业务优化调整和支撑企业高层管理进行决…

关于saltstack的监控系统部署

环境 master 是centos7-linux 192.14.0.79 minios 是 windows11 192.14.0.207 下载saltstack主节点 sudo yum install salt-master下载saltstack 客户端 windows的minios配置Salt-Minion-3006.1-Py3-AMD64-Setup.exe 过程 master 端 vim /etc/salt/master.d/network.conf…

如何让一个盒子因为内容不同,而样式也不同呢

例如&#xff0c;每个盒子上面都有一个色块&#xff0c;静态&#xff0c;动态&#xff0c;岗位。如何让不同的内容就有不同的字体颜色和背景呢&#xff1f; 可以给每个盒子重复一样的步骤&#xff0c;但是显然最简单的方法是用一个循环。循环遍历数据&#xff0c;直接写一个盒…

《Pytorch深度学习和图神经网络(卷 1)》学习笔记——第八章

本书之后的内容与当前需求不符合不再学习 信息熵与概率的计算关系… 联合熵、条件熵、交叉熵、相对熵&#xff08;KL散度&#xff09;、JS散度、互信息 无监督学习 监督训练中&#xff0c;模型能根据预测结果与标签差值来计算损失&#xff0c;并向损失最小的方向进行收敛。无…

CRYPTO-36D-rsaEZ

0x00 前言 CTF 加解密合集&#xff1a;CTF 加解密合集 0x01 题目 给了一个秘钥&#xff0c;三个加密后的文件 0x02 Write Up 先获取n和e # 导入公钥 with open(r"C:\Users\wdd\Downloads\flag\fujian\public.key", "rb") as f:key RSA.import_key(f…

行业追踪,2023-07-10,汽车零部件如期调整,需要耐心等待第二波

自动复盘 2023-07-10 成交额超过 100 亿 排名靠前&#xff0c;macd柱由绿转红 成交量要大于均线 有必要给每个行业加一个上级的归类&#xff0c;这样更能体现主流方向 rps 有时候比较滞后&#xff0c;但不少是欲杨先抑&#xff0c; 应该持续跟踪&#xff0c;等 macd 反转时参与…

Vue简单使用及整合elementui

创建vue工程 在vue工程目录下npm install vue 下载离线vue https://v2.vuejs.org/v2/guide/installation.html 引入工程中 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" c…