当前位置: 首页 > news >正文

【STL】pair 与 map:基础、操作与应用

C++ 标准库中提供了许多用于处理数据结构的容器和工具。pair 和 map 是两个非常有用的工具,广泛应用于存储和处理关联数据。在本文中,我们将详细介绍 pair 与 map 的相关操作,并结合代码实例为读者提供清晰的理解。

pair:成对数据的存储

1. pair 基本介绍

pair 是 C++ 标准库中的一种数据结构,它允许我们将两个不同类型的数据组合成一对。它的典型用法是用来返回两个相关联的值,例如姓名和电话号码。每个 pair 包含两个值,这两个值分别可以通过 .first 和 .second 访问。

2. pair 的创建与使用

2.1创建 pair 的几种方式:

直接使用构造函数创建:

pair<string, int> p("Tom", 10086);

使用 make_pair 函数创建:

pair<string, int> p2 = make_pair("make", 191919190);

列表初始化(C++11 新特性):

pair<string, int> p3 = { "hhhh", 19298318 };

2.2pair 的常用操作:

访问 pair 中的第一个和第二个值:

cout << "姓名:" << p.first << endl;
cout << "电话:" << p.second << endl;

判断两个 pair 对象是否相等:

if (p != p2) 
{cout << "不相等" << endl;
}

整体操作如下:

//pair(二元组):成对出现的数据,利用对组可以返回两个数据
#include<iostream>
#include<string>
#include <utility>  // 包含 pair 对组相关的头文件
using namespace std;//pair<第一个值类型, 第二个值类型> pr// 第一个值类型:要储存的第一个值的数据类型
// 第二个值类型:要储存的第二个值的数据类型// 取第一个值:.first
// 取第二个值:.second// 判断相等:==, !=// 测试 pair 的各种构造与操作
void test0()
{// 使用构造函数直接创建 pair 对象,存储姓名和电话pair<string, int> p("Tom", 10086);// 输出 pair 的第一个元素(姓名)和第二个元素(电话)cout << "姓名:" << p.first << endl;cout << "电话:" << p.second << endl;// 使用 make_pair 创建 pair 对象,这是一种常见的方式pair<string, int> p2 = make_pair("make", 191919190);cout << "姓名:" << p2.first << endl;cout << "电话:" << p2.second << endl;// C++11 新特性,使用列表初始化 pair 对象pair<string, int> p3 = { "hhhh",19298318 };cout << "姓名:" << p3.first << endl;cout << "电话:" << p3.second << endl;// 判断两个 pair 对象是否相等,!= 表示不相等if (p != p2){cout << "不相等" << endl;  // 如果 p 和 p2 不相等,输出提示}
}int main()
{test0();  // 调用测试函数return 0;
}

在这里插入图片描述

map:关联式容器

1. map 基本介绍

map 是 C++ 中的一种关联容器,通常用于存储键值对。每个元素都是 pair,其中第一个元素为 键(key),第二个元素为 值(value)。 map 容器的特点是:所有元素会根据 键 的大小自动排序,并且 键值唯一。如果需要允许重复键,可以使用 multimap。

2.map基本操作一览

map<键类型, 值类型, 比较器> mp

  • 键类型:用于存储键的数据类型
  • 值类型:用于存储与键相关联的值的数据类型
  • 比较器:用于键值比较的规则,默认是 less<类型>,即从小到大排序,可以自定义为 greater<类型> 来改变排序顺序

2.1. map构造和赋值:对map容器进行构造和赋值操作

2.1.1 构造:

map<T1, T2> mp;
// map默认构造函数

map(const map& mp);
// 拷贝构造函数

2.1.2 赋值:

map& operator=(const map& mp);
// 重载等号操作符

2.2. map大小和交换:统计map容器的大小并交换两个map容器

size();
// 返回容器中的元素数量

empty();
// 判断容器是否为空

swap(st);
// 交换两个map容器

2.3. map插入和删除:对map容器插入和删除元素

insert(elem);
// 插入一个元素

clear();
// 清空所有元素

erase(pos);
// 删除pos迭代器所指的元素,返回下一个元素的迭代器

erase(beg, end);
// 删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

erase(key);
// 删除键值为 key 的元素

2.4. map查找和统计:查找和统计数据

find(key);
// 查找key是否存在,存在则返回该键的元素的迭代器,不存在则返回map.end()

count(key);
// 统计键值为key的元素个数:
//map 中的键唯一,因此结果要么为 0(不存在),要么为 1(存在)。

2.5. map排序:map容器默认使用键值的升序排序

降序排序使用map<类型,类型,greater<类型>>m;

3. map 构造和赋值

3.1构造:

map 容器提供了几种方式来构造对象,包括默认构造、拷贝构造等。

  • 默认构造: 使用默认构造函数创建一个空的 map 容器。
map<int, int> mp;  // 创建一个空的 map 容器
  • 拷贝构造: 通过拷贝另一个 map 容器来构造新的 map 对象。
map<int, int> mp2(mp);  // 用 mp 初始化 mp2

3.2赋值:

通过重载等号操作符 =,可以将一个 map 容器的内容赋值给另一个 map。

map<int, int> mp3 = mp2;  // 将 mp2 的内容赋值给 mp3

示例:

// 1. map构造和赋值
void test0()
{// 默认构造 map 容器map<int, int> m;// 插入键值对m.insert(pair<int, int>(1, 3));m.insert(pair<int, int>(4, 0));m.insert(pair<int, int>(1, 3));  // 重复键值不会插入m.insert(pair<int, int>(4, 9));  // 键值相同,实值不同,仍然只保留键值唯一的元素m.insert(pair<int, int>(5, 100));print(m);// 拷贝构造map<int, int> m2(m);  // 用 m 初始化 m2print(m2);// 赋值操作map<int, int> m3 = m2;  // 将 m2 的内容赋给 m3print(m3);
}

在这里插入图片描述

4.map的遍历

// 默认排序遍历:
void print(map<int, int>& m)
{// 使用迭代器遍历 map,按升序输出键值对for (map<int, int>::iterator it = m.begin(); it != m.end(); it++){cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";cout << endl;}cout << endl;// auto 简化迭代器类型(C++11)// for (auto it = m.begin(); it != m.end(); it++)// {// 	cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";// 	cout << endl;// }// 基于范围的 for 循环遍历 map (C++11)// for (pair<int,int> mm : m)// {// 	cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";// 	cout << endl;// }// 使用 auto 更简洁// for (auto mm:m)// {// 	cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";// 	cout << endl;// }
}// 降序遍历:使用 greater<int> 进行键值的降序排列
void print1(map<int, int, greater<int>>& m)
{// 通过迭代器遍历 map,按降序输出键值对for (map<int, int, greater<int>>::iterator it = m.begin(); it != m.end(); it++){cout << "键值:" << it->first << " " << "实值:" << it->second << " ";cout << endl;}cout << endl;// 使用 auto 简化代码// for (auto it = m.begin(); it != m.end(); it++)// {// 	cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";// 	cout << endl;// }/*基于范围for循环:注意这里的元素类型为二元组for (pair<int,int> mm : m){cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";cout << endl;}*//*auto最好用,没有之一for (auto mm:m){cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";cout << endl;}*/
}

5. map 大小和交换

5.1获取容器大小:

.size():返回 map 容器中的元素数量。
.empty():判断 map 是否为空。

cout << "Size: " << m.size() << endl;
cout << "Is empty: " << m.empty() << endl;

5.2交换:

.swap():交换两个 map 容器的内容。

map<int, int> m1, m2;
m1[1] = 10; m2[2] = 20;
m1.swap(m2);  // 交换 m1 和 m2 的内容

示例:

// 2. map大小和交换
void test1()
{map<int, int> m;// 插入键值对m.insert(pair<int, int>(1, 3));m.insert(pair<int, int>(2, 0));m.insert(pair<int, int>(5, 3));// 判断 map 是否为空if (m.empty()){cout << "m为空!" << endl;}else{cout << "m的长度为:" << m.size() << endl;}// 交换两个 map 容器map<int, int> m1;m1.insert(pair<int, int>(3, 1));m1.insert(pair<int, int>(4, 1));m1.insert(pair<int, int>(5, 3));cout << "交换前:" << endl;cout << "m: " << endl;print(m);cout << endl << "m1: " << endl;print(m1);// 执行交换m.swap(m1);cout << "交换后:" << endl;cout << "m: " << endl;print(m);cout << endl << "m1: " << endl;print(m1);
}

在这里插入图片描述

6. map 插入和删除

6.1 插入:

  • insert(elem):插入一个键值对元素。
    分为:
.insert(pair<int, int>(first, second)); 
.insert(make_pair(first, second));
.insert(map<int, int>::value_type(first, second));
  • 使用 [] 插入键值对。(好用)
m.insert(pair<int, int>(1, 100));
m[2] = 200;

6.2 删除:

erase(pos):删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end):删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(key):删除键值为 key 的元素。

m.erase(2);          // 删除键值为 2 的元素
m.erase(m.begin());  // 删除第一个元素
m.clear();           // 清空所有元素

示例:

// 3. map插入和删除
void test2()
{map<int, int> m;// 插入键值对的不同方法m.insert(pair<int, int>(1, 1));                // 方法一:pairm.insert(make_pair(2, 100));                  // 方法二:make_pairm.insert(map<int, int>::value_type(3, 44));   // 方法三:value_typem[4] = 55;                                     // 方法四:中括号操作符print(m);// 删除元素m.erase(m.begin());    // 删除迭代器指向的元素print(m);m.erase(3);            // 删除键值为3的元素print(m);m.erase(m.begin(), m.end());   // 删除区间中的所有元素//等价于m.clear();print(m);
}

在这里插入图片描述

7. map 查找和统计

7.1查找:

find(key):查找 key,返回指向该元素的迭代器,如果不存在则返回 map.end()。

auto it = m.find(1);
if (it != m.end()) 
{cout << "查找成功: " << it->first << "实值: " << it->second << endl;
} 
else 
{cout << "查找失败" << endl;
}

7.2统计:

count(key):返回键值为 key 的元素个数,map 中的键唯一,因此结果要么为 0(不存在),要么为 1(存在)

cout << "键值为1的元素数量: " << m.count(1) << endl;

示例:

// 4. map查找和统计
void test3()
{map<int, int> m;m[0] = 45;m[4] = 34;m[5] = 0;// 查找键值为4的元素map<int, int>::iterator it = m.find(4);if (it != m.end()){cout << "查找成功:" << it->first << " " << it->second << endl;}else{cout << "查找失败" << endl;}// 统计键值为0的元素个数if (m.count(0)){cout << "查找成功" << endl << "数量为:" << m.count(0) << endl;}else{cout << "查找失败" << endl;}
}

在这里插入图片描述

8. map 排序

map 默认按照键的升序进行排序。如果需要自定义排序顺序,可以通过第三个模板参数指定比较器(如 greater)。

8.1默认升序排序:

map<int, int> m;
m[3] = 100;
m[1] = 200;
m[2] = 300;

8.2自定义降序排序:

map<int, int, greater<int>> m1;
m1[3] = 100;
m1[1] = 200;
m1[2] = 300;

示例:

// 5. map排序:键值默认从小到大排序
void test4()
{// 默认升序排序map<int, int> m;m[0] = 11;m[1] = 23;m[-22] = 56;print(m);// 使用 greater<int> 进行降序排序map<int, int, greater<int>> m1;m1[0] = 11;m1[1] = 23;m1[-22] = 56;print1(m1);
}

在这里插入图片描述

整体操作如下:

//map:关联式容器// map中所有元素都是pair:
//匿名pair: pair<类型,类型>(键值,实值);//pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
//所有元素都会根据元素的键值自动排序//map不允许容器中有重复key值元素
//multimap允许容器中有重复key值元素#include<iostream>
#include<map>  // 引入 map 关联式容器头文件
using namespace std;// map<键类型, 值类型, 比较器> mp// 键类型:用于存储键的数据类型
// 值类型:用于存储与键相关联的值的数据类型
// 比较器:用于键值比较的规则,默认是 less<类型>,即从小到大排序,可以自定义为 greater<类型> 来改变排序顺序// 1. map构造和赋值:对map容器进行构造和赋值操作
// 构造:
// map<T1, T2> mp;                     // map默认构造函数
// map(const map& mp);                 // 拷贝构造函数// 赋值:
// map& operator=(const map& mp);      // 重载等号操作符// 2. map大小和交换:统计map容器的大小并交换两个map容器
// size();                             // 返回容器中的元素数量
// empty();                            // 判断容器是否为空
// swap(st);                           // 交换两个map容器// 3. map插入和删除:对map容器插入和删除元素
// insert(elem);                       // 插入一个元素
// clear();                            // 清空所有元素
// erase(pos);                         // 删除pos迭代器所指的元素,返回下一个元素的迭代器
// erase(beg, end);                    // 删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
// erase(key);                         // 删除键值为 key 的元素// 4. map查找和统计:查找和统计数据
// find(key);                          // 查找key是否存在,存在则返回该键的元素的迭代器,不存在则返回map.end()
// count(key);                         // 统计键值为key的元素个数// 5. map排序:map容器默认使用键值的升序排序// 默认排序遍历:
void print(map<int, int>& m)
{// 使用迭代器遍历 map,按升序输出键值对for (map<int, int>::iterator it = m.begin(); it != m.end(); it++){cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";cout << endl;}cout << endl;// auto 简化迭代器类型(C++11)// for (auto it = m.begin(); it != m.end(); it++)// {// 	cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";// 	cout << endl;// }// 基于范围的 for 循环遍历 map (C++11)// for (pair<int,int> mm : m)// {// 	cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";// 	cout << endl;// }// 使用 auto 更简洁// for (auto mm:m)// {// 	cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";// 	cout << endl;// }
}// 降序遍历:使用 greater<int> 进行键值的降序排列
void print1(map<int, int, greater<int>>& m)
{// 通过迭代器遍历 map,按降序输出键值对for (map<int, int, greater<int>>::iterator it = m.begin(); it != m.end(); it++){cout << "键值:" << it->first << " " << "实值:" << it->second << " ";cout << endl;}cout << endl;// 使用 auto 简化代码// for (auto it = m.begin(); it != m.end(); it++)// {// 	cout << "键值:" << (*it).first << " " << "实值:" << it->second << " ";// 	cout << endl;// }/*基于范围for循环:注意这里的元素类型为二元组for (pair<int,int> mm : m){cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";cout << endl;}*//*auto最好用,没有之一for (auto mm:m){cout << "键值:" << mm.first << " " << "实值:" << mm.second << " ";cout << endl;}*/
}// 1. map构造和赋值
void test0()
{// 默认构造 map 容器map<int, int> m;// 插入键值对m.insert(pair<int, int>(1, 3));m.insert(pair<int, int>(4, 0));m.insert(pair<int, int>(1, 3));  // 重复键值不会插入m.insert(pair<int, int>(4, 9));  // 键值相同,实值不同,仍然只保留键值唯一的元素m.insert(pair<int, int>(5, 100));print(m);// 拷贝构造map<int, int> m2(m);  // 用 m 初始化 m2print(m2);// 赋值操作map<int, int> m3 = m2;  // 将 m2 的内容赋给 m3print(m3);
}// 2. map大小和交换
void test1()
{map<int, int> m;// 插入键值对m.insert(pair<int, int>(1, 3));m.insert(pair<int, int>(2, 0));m.insert(pair<int, int>(5, 3));// 判断 map 是否为空if (m.empty()){cout << "m为空!" << endl;}else{cout << "m的长度为:" << m.size() << endl;}// 交换两个 map 容器map<int, int> m1;m1.insert(pair<int, int>(3, 1));m1.insert(pair<int, int>(4, 1));m1.insert(pair<int, int>(5, 3));cout << "交换前:" << endl;cout << "m: " << endl;print(m);cout << endl << "m1: " << endl;print(m1);// 执行交换m.swap(m1);cout << "交换后:" << endl;cout << "m: " << endl;print(m);cout << endl << "m1: " << endl;print(m1);
}// 3. map插入和删除
void test2()
{map<int, int> m;// 插入键值对的不同方法m.insert(pair<int, int>(1, 1));                // 方法一:pairm.insert(make_pair(2, 100));                   // 方法二:make_pairm.insert(map<int, int>::value_type(3, 44));    // 方法三:value_typem[4] = 55;                                     // 方法四:中括号操作符print(m);// 删除元素m.erase(m.begin());    // 删除迭代器指向的元素print(m);m.erase(3);            // 删除键值为3的元素print(m);m.erase(m.begin(), m.end());    // 删除区间中的所有元素//等价于m.clear();print(m);
}// 4. map查找和统计
void test3()
{map<int, int> m;m[0] = 45;m[4] = 34;m[5] = 0;// 查找键值为4的元素map<int, int>::iterator it = m.find(4);if (it != m.end()){cout << "查找成功:" << it->first << " " << it->second << endl;}else{cout << "查找失败" << endl;}// 统计键值为0的元素个数if (m.count(0)){cout << "查找成功" << endl << "数量为:" << m.count(0) << endl;}else{cout << "查找失败" << endl;}
}// 5. map排序:键值默认从小到大排序
void test4()
{// 默认升序排序map<int, int> m;m[0] = 11;m[1] = 23;m[-22] = 56;print(m);// 使用 greater<int> 进行降序排序map<int, int, greater<int>> m1;m1[0] = 11;m1[1] = 23;m1[-22] = 56;print1(m1);
}int main()
{test0();test1();test2();test3();test4();return 0;
}

9.相关注意事项

9.1. 键的唯一性

map 中的键必须是唯一的。这意味着你不能在 map 中插入具有相同键的多个元素。如果尝试插入一个已存在的键,map 将保持原来的值,不会更新或插入新的键值对。

map<int, int> m;
m.insert(make_pair(1, 100)); // 插入键值对 (1, 100)
m.insert(make_pair(1, 200)); // 插入失败,键 1 已存在cout << "键值:" << m[1] << endl; // 输出 100

如果你希望插入时更新键值,可以使用 [] 操作符

m[1] = 200; // 更新键 1 的值为 200

9.2. 使用 [] 操作符时的注意

当你使用 map[key] 来访问键时,如果该键不存在,map 会默认插入该键,并将值初始化为零或默认值。这可能导致意外的元素插入。

map<int, int> m;
int value = m[5];  
// 键 5 不存在,map 会自动插入键 5,其值为 0
cout << "m[5] = " << value << endl; // 输出 m[5] = 0

为避免这种行为,可以使用 find() 来检查键是否存在:

if (m.find(5) != m.end()) 
{cout << "键 5 存在" << endl;
}
else 
{cout << "键 5 不存在" << endl;
}

9.3. 修改键

map 不允许修改键。一旦键被插入到 map 中,它的值可以被修改,但键不能被更改。如果需要修改键,必须先删除该键,然后再插入新的键值对。

map<int, int> m;
m.insert(make_pair(1, 100));
m.begin()->first = 2;  // 错误,不能修改键

9.4. 避免重复插入(了解)

插入元素时,检查是否成功非常重要。map 的 insert() 函数返回一个 pair,其中 second 元素为 bool 值,指示插入是否成功。如果插入失败(因为键已存在),second 会是 false。

pair<map<int, int>::iterator, bool> ret = m.insert(make_pair(1, 100));
if (!ret.second){cout << "插入失败,键 1 已存在" << endl;
}

9.5. 迭代器失效

在 map 中,插入或删除元素时,当前的迭代器不会失效。唯一会使迭代器失效的操作是删除迭代器指向的元素。 因此,当你删除某个元素时,确保适当地处理迭代器,以避免使用失效的迭代器。

for (auto it = m.begin(); it != m.end(); ) 
{if (it->first == 3) {it = m.erase(it);  // erase 返回下一个有效的迭代器} else {it++;  // 手动递增迭代器}

}

9.6总结

  • 唯一键:map 不允许重复键,插入相同键时会保持原值。

  • [] 操作符自动插入:使用 [] 时要小心自动插入不存在的键。

  • 不可修改键:map 中键值对的键不可修改,只能删除后重新插入。

  • 避免迭代器失效:特别是在删除元素时,确保适当处理迭代器。

相关文章:

【STL】pair 与 map:基础、操作与应用

C 标准库中提供了许多用于处理数据结构的容器和工具。pair 和 map 是两个非常有用的工具&#xff0c;广泛应用于存储和处理关联数据。在本文中&#xff0c;我们将详细介绍 pair 与 map 的相关操作&#xff0c;并结合代码实例为读者提供清晰的理解。 pair&#xff1a;成对数据的…...

深度学习-图像处理篇4VGG网络

CNN感受野...

初级css+初级选择器

一、css基础样式 html: 标签 > 网页骨架 css: 美化这个网页的骨架 >样式去装饰网页 1. css 层叠样式表 (英文全称: Cascading Style Sheets) >修饰网页内容 比如: 文字大小 颜色 网页排版 高宽等等 2. css写在哪里?——行内样式 内部样式 外部样…...

gitlab 的CI/CD (二)

前言 上文完成了gitlab-runner的基础配置及将gitlab的制品上传至软件包库&#xff08;产品库&#xff09;的脚本编写&#xff1b; 本文实现gitlab的ci/cd对远程服务器的操作&#xff1b; 介绍 要让Gitlab Runner部署到远程机器&#xff0c;远程机器必须信任gitlab runner账…...

【html】基础(一)

本专栏内容为&#xff1a;前端专栏 记录学习前端&#xff0c;分为若干个子专栏&#xff0c;html js css vue等 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;js专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &am…...

【网站架构部署与优化】Nginx优化

文章目录 Nginx服务优化一、隐藏Nginx版本号&#xff0c;避免安全漏洞泄漏方法一&#xff1a;通过修改配置文件方法二&#xff1a;通过修改源码并重新编译安装 修改Nginx的用户和组修改用户与组 配置Nginx网页缓存时间配置Nginx连接保持的超时时间KeepAlive模式简介Nginx中的超…...

gitlab修改访问端口

目录 1.找到gitlab.rb文件&#xff0c;一般在/etc/gitlab/路径下 2.打开配置文件&#xff0c;加上代码 3.重新配置 4.重启gitlab 1.找到gitlab.rb文件&#xff0c;一般在/etc/gitlab/路径下 2.打开配置文件&#xff0c;加上代码 打开文件 sudo vi gitlab.rb 加上默认端口配…...

分库分表-分页排序查询

优质博文&#xff1a;IT-BLOG-CN 背景&#xff1a;我们系统上云后&#xff0c;数据根据用户UDL部分数据在国内&#xff0c;部分数据存储在海外&#xff0c;因此需要考虑分库查询的分页排序问题 一、分库后带来的问题 需求根据订单创单时间进行排序分页查询&#xff0c;在单表…...

【openwrt-21.02】openwrt PPTP Passthrough 不生效问题解决方案

Openwrt版本 NAME="OpenWrt" VERSION="21.02-SNAPSHOT" ID="openwrt" ID_LIKE="lede openwrt" PRETTY_NAME="OpenWrt 21.02-SNAPSHOT" VERSION_ID="21.02-snapshot" HOME_URL="https://openwrt.org/" …...

【编程基础知识】Mysql的各个索引数据结构及其适用场景

一、引言 在数据库的世界中&#xff0c;索引是提升查询速度的超级英雄。就像图书馔的目录帮助我们快速找到书籍一样&#xff0c;MySQL中的索引加速了数据检索的过程。本文将带你深入了解MySQL索引的多种数据结构、它们的适用场景以及如何巧妙地使用它们来优化性能。 二、索引…...

解决IDEA出现:java: 程序包javax.servlet不存在的问题

问题截图&#xff1a; 解决如下&#xff1a; 1. 点击文件——>项目结构 2. 点击库——>点击——>点击java 3. 找到Tomcat的文件夹&#xff0c;找到lib文件夹中的servlet-api.jar&#xff0c;点击确定 4. 选择要添加的模块 5. 点击应用——>确定...

Comfyui控制人物骨骼,细节也能完美调整!

前言 本文涉及的工作流和插件&#xff0c;需要的朋友请扫描免费获取哦~ 在我们利用Comfyui生成图像的工作中&#xff0c;是否常常因为人物的动作无法得到精确的控制而感到苦恼&#xff0c;生成出来的图片常常达不到自己心中满意的效果。 今天给大家分享的这个工作流&#xff…...

mysql学习教程,从入门到精通,SQL LEFT JOIN 语句(23)

1、SQL LEFT JOIN 语句 在SQL中&#xff0c;LEFT JOIN&#xff08;也称为左连接&#xff09;是一种将左表&#xff08;LEFT JOIN左侧的表&#xff09;的所有记录与右表&#xff08;LEFT JOIN右侧的表&#xff09;中匹配的记录结合起来的查询方式。如果左表中的记录在右表中没有…...

VSCode远程切换Python虚拟环境

VSCode远程切换Python虚拟环境 引言 在现代开发环境中&#xff0c;使用虚拟环境来管理项目依赖是一种普遍的做法。它不仅可以避免不同项目间的依赖冲突&#xff0c;还能让开发者更好地控制和隔离各个项目的环境。Visual Studio Code&#xff08;VSCode&#xff09;是一款广受…...

【CSS in Depth 2 精译_038】6.2 CSS 定位技术之:绝对定位

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…...

828 华为云征文|华为 Flexus 云服务器搭建 SamWaf 开源轻量级网站防火墙

在当今数字化高速发展的时代&#xff0c;网络安全问题日益凸显。为了保障网站的稳定运行和数据安全&#xff0c;我们可以借助华为 Flexus 云服务器搭建 SamWaf 开源轻量级网站防火墙。这不仅是一次技术的挑战&#xff0c;更是为网站筑牢安全防线的重要举措。 一、华为 Flexus …...

基于二自由度汽车模型的汽车质心侧偏角估计

一、质心侧偏角介绍 在车辆坐标系中&#xff0c;质心侧偏角通常定义为质心速度方向与车辆前进方向的夹角。如下图所示&#xff0c;u为车辆前进方向&#xff0c;v为质心速度方向&#xff0c;u和v之间的夹角便是质心侧偏角。 质心侧偏角的作用有如下三点&#xff1a; 1、稳定性…...

前端html+css+js 基础总结

​​​HTML 行级元素 标签分为行级元素与块级元素 行级元素占据区域由其显示内容决定&#xff0c;如span&#xff0c;img(图片)&#xff0c;<a></a>基本格式: <a href"链接" target"_blank"></a>用于跳转到其他网站&#xff0c…...

若依VUE项目安全kind-of postcss vite漏洞扫描和修复

npm install unplugin-auto-import0.16.7 npm install vite3.2.11 升级vite、unplugin-auto-import npm install 报错New major version of npm available! 8.5.5 -> 10.8.3&#xff0c;使用命令npm install --force npm install --force...

C语言实现简单凯撒密码算法

**实验2&#xff1a;传统密码技术 【实验目的】 通过本次实训内容&#xff0c;学习常见的传统密码技术&#xff0c;通过编程实现简单代替密码中的移位密码算法&#xff0c;加深对传统密码技术的了解&#xff0c;为深入学习密码学奠定基础。【技能要求】 分析简单代替密码中的移…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...