简述C++map容器
pair键值对
std::pair
在很多关联容器(如std::map
、std::multimap
、std::set
、std:multiset
等)中被广泛应用。以std::map
为例,std::map
是一个键值对的容器,其中每个元素都是一个std::pair
,键用于唯一标识元素,值则是与键相关联的数据。
pair是类模板,一般用于表示key/value数据,其实现是结构体。
pair结构模板的定义如下:
template <class T1, class T2>
struct pair
{
T1 first; // 第一个成员,一般表示key。
T2 second; // 第二个成员,一般表示value。
pair(); // 默认构造函数。
pair(const T1 &val1,const T2 &val2); // 有两个参数的构造函数。
pair(const pair<T1,T2> &p); // 拷贝构造函数。
void swap(pair<T1,T2> &p); // 交换两个pair。
};
make_pair函数模板的定义如下:
template <class T1, class T2>
make_pair(const T1 &first,const T2 &second)
{
return pair<T1,T2>(first, second);
}
示例代码:
#include <iostream>
#include<utility>using namespace std;template <class T1, class T2>
struct Pair
{T1 first; // 第一个成员,一般表示key。T2 second; // 第二个成员,一般表示value。Pair() {cout << "调用了有默认的构造函数。\n";}Pair(const T1& val1, const T2& val2) :first(val1), second(val2) {cout << "调用了有两个参数的构造函数。\n";}Pair(const Pair<T1, T2>& p) : first(p.first), second(p.second) {cout << "调用了拷贝构造函数。\n";}
};template <class T1, class T2>
Pair<T1, T2> make_Pair(const T1& first, const T2& second)
{// Pair<T1, T2> p(first, second);// return p; // 返回局部对象。return Pair<T1, T2>(first, second); // 返回临时对象。
}int main()
{pair<int, string> p0;cout << "p0 first=" << p0.first << ",second=" << p0.second << endl;pair<int, string> p1(1, "吴彦祖"); // 两个参数的构造函数。cout << "p1 first=" << p1.first << ",second=" << p1.second << endl;pair<int, string> p2 = p1; // 拷贝构造。cout << "p2 first=" << p2.first << ",second=" << p2.second << endl;p2.swap(p0);cout << "p0 first=" << p0.first << ",second=" << p0.second << endl;cout << "p2 first=" << p2.first << ",second=" << p2.second << endl;auto p3 = make_pair(2, "陈冠希");cout << "键:" << p3.first << ", 值:" << p3.second << endl;
}
运行结果:
map容器
map 容器封装了红黑树(平衡二叉排序树),用于查找。
包含头文件: #include<map>
map容器的元素是pair键值对。
迭代器是双向迭代器。
map类模板的声明:
template <class K, class V, class P = less<K>, class _Alloc = allocator<pair<const K, V >>>
class map : public _Tree<_Tmap_traits< K, V, P, _Alloc, false>>
{
…
}
第一个模板参数K:key的数据类型(pair.first)。
第二个模板参数V:value的数据类型(pair.second)。
第三个模板参数P:排序方法,缺省按key升序。
第四个模板参数_Alloc:分配器,缺省用new和delete。
map提供了双向迭代器。
二叉链表:
struct BTNode
{
pair<K,V> p; // 键值对。
BTNode *parent; // 父节点。
BTNode *lchirld; // 左子树。
BTNode *rchild; // 右子树。
};
一、构造函数
1)map(); // 创建一个空的map容器。
2)map(initializer_list<pair<K,V>> il); // 使用统一初始化列表。
3)map(const map<K,V>& m); // 拷贝构造函数。
4)map(Iterator first, Iterator last); // 用迭代器创建map容器。
5)map(map<K,V>&& m); // 移动构造函数(C++11标准)。
二、特性操作
size_t size() const; // 返回容器的实际大小(已使用的空间)。
bool empty() const; // 判断容器是否为空。
void clear(); // 清空容器。
三、元素操作
V &operator[](K key); // 用给定的key访问元素。
const V &operator[](K key) const; // 用给定的key访问元素,只读。
V &at(K key); // 用给定的key访问元素。
const V &at(K key) const; // 用给定的key访问元素,只读。
注意:
1)[ ]运算符:如果指定键不存在,会向容器中添加新的键值对;如果指定键不存在,则读取或修改容器中指定键的值。
2)at()成员函数:如果指定键不存在,不会向容器中添加新的键值对,而是直接抛出out_of_range 异常。
示例代码:
#include <iostream>
#include <map>
using namespace std;int main()
{map<string, string> m({ { "08","冠希" }, { "03","于晏" }, { "01","彦祖" }, { "07","德华" }, { "05","学友" } });cout << "m[08]=" << m["08"] << endl; // 显示key为08的元素的value。cout << "m[09]=" << m["09"] << endl; // 显示key为09的元素的value。key为09的元素不存在,将添加新的键值对。cout << "m.at(03)=" << m.at("03") << endl;//m.at("099");错误!!m["07"] = "黎明"; // 把key为07的元素的value修改为黎明。m["12"] = "富城"; // 将添加新的键值对。for (auto& val : m)cout << val.first << "," << val.second << " ";cout << endl;
}
运行结果:
四、赋值操作
给已存在的容器赋值,将覆盖容器中原有的内容。
1)map<K,V> &operator=(const map<K,V>& m); // 把容器m赋值给当前容器。
2)map<K,V> &operator=(initializer_list<pair<K,V>> il); // 用统一初始化列表给当前容器赋值。
五、交换操作
void swap(map<K,V>& m); // 把当前容器与m交换。
交换的是树的根结点。
六、比较操作
bool operator == (const map<K,V>& m) const;
bool operator != (const map<K,V>& m) const;
七、查找操作
1)查找键值为key的键值对
在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。
iterator find(const K &key);
const_iterator find(const K &key) const; // 只读。
2)查找键值>=key的键值对
在map容器中查找第一个键值>=key的键值对,成功返回迭代器;失败返回end()。
iterator lower_bound(const K &key);
const_iterator lower_bound(const K &key) const; // 只读。
3)查找键>key的键值对
在map容器中查找第一个键值>key的键值对,成功返回迭代器;失败返回end()。
iterator upper_bound(const K &key);
const_iterator upper_bound(const K &key) const; // 只读。
4)统计键值对的个数
统计map容器中键值为key的键值对的个数。
size_t count(const K &key) const;
八、插入和删除
1)void insert(initializer_list<pair<K,V>> il); // 用统一初始化列表在容器中插入多个元素。
2)pair<iterator,bool> insert(const pair<K,V> &value); // 在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。
3)void insert(iterator first,iterator last); // 用迭代器插入一个区间的元素。
4)pair<iterator,bool> emplace (...); // 将创建新键值对所需的数据作为参数直接传入,map容器将直接构造元素。返回值pair:first是已插入元素的迭代器,second是插入结果。
例:mm.emplace(piecewise_construct, forward_as_tuple(8), forward_as_tuple("冰冰", 18));
5)iterator emplace_hint (const_iterator pos,...); // 功能与第4)个函数相同,第一个参数提示插入位置,该参数只有参考意义,如果提示的位置是正确的,对性能有提升,如果提示的位置不正确,性能反而略有下降,但是,插入是否成功与该参数元关。该参数常用end()和begin()。成功返回新插入元素的迭代器;如果元素已经存在,则插入失败,返回现有元素的迭代器。
6)size_t erase(const K & key); // 从容器中删除指定key的元素,返回已删除元素的个数。
7)iterator erase(iterator pos); // 用迭代器删除元素,返回下一个有效的迭代器。
8)iterator erase(iterator first,iterator last); // 用迭代器删除一个区间的元素,返回下一个有效的迭代器。
示例代码:
#include <iostream>
#include <map>
using namespace std;int main()
{map<string, string> m({ { "08","冠希" }, { "03","于晏" }, { "01","彦祖" }, { "07","德华" }, { "05","学友" } });// 执行插入操作并检查返回值auto result = m.insert(make_pair("08", "富城"));// result的类型是std::pair<std::map<std::string, std::string>::iterator, bool>// result.first是指向插入位置的迭代器(如果插入成功)或已存在相同键的迭代器(如果插入失败)// result.second是一个布尔值,表示插入是否成功if (result.second) {std::cout << "插入成功" << std::endl;}else {std::cout << "插入失败,键已存在" << std::endl;}for (auto& val : m)cout << val.first << "," << val.second << " ";cout << endl;// 在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。auto it1 = m.find("05");if (it1 != m.end())cout << "查找成功:" << it1->first << "," << it1->second << endl;elsecout << "查找失败。\n";// 在map容器中查找第一个键值 >= key的键值对,成功返回迭代器;失败返回end()。auto it2 = m.lower_bound("05");if (it2 != m.end())cout << "查找成功:" << it2->first << "," << it2->second << endl;elsecout << "查找失败。\n";// 在map容器中查找第一个键值 > key的键值对,成功返回迭代器;失败返回end()。auto it3 = m.upper_bound("05");if (it3 != m.end())cout << "查找成功:" << it3->first << "," << it3->second << endl;elsecout << "查找失败。\n";// 统计map容器中键值为key的键值对的个数。cout << "count(05)=" << m.count("05") << endl; // 返回1。cout << "count(06)=" << m.count("06") << endl; // 返回0。
}
运行结果:
std::map
的 insert
函数在遇到重复键的情况时,会根据其内部实现做出相应处理。通常情况下,它不会覆盖已有的键值对(与 std::unordered_map
不同,std::unordered_map
若插入重复键,会覆盖原来的值),而是会返回一个表示插入结果的对象,这个对象包含了一些信息来表明插入操作是否真正成功插入了新元素。 我们可以接受返回值来确认是否插入成功。
在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。
按照字符串的字典序比较规则(这也是 std::map
默认用于比较键的规则,因为键是 std::string
类型):
"01"
< "03"
< "05"
< "07"
< "08"
所以查找lower和upper时候会找到学友和德华;
unordered_map容器
unordered(无序)
unordered_map容器封装了哈希表,查找、插入和删除元素时,只需要比较几次key的值。
包含头文件: #include<unordered_map>
unordered_map容器的元素是pair键值对。
unordered_map类模板的声明:
template <class K, class V, class _Hasher = hash<K>, class _Keyeq = equal_to<K>,
class _Alloc = allocator<pair<const K, V>>>
class unordered_map : public _Hash<_Umap_traits<K, V, _Uhash_compare<K, _Hasher, _Keyeq>, _Alloc, false>>
{
…
}
第一个模板参数K:key的数据类型(pair.first)。
第二个模板参数V:value的数据类型(pair.second)。
第三个模板参数_Hasher:哈希函数,默认值为std::hash<K>
第四个模板参数_Keyeq:比较函数,用于判断两个key是否相等,默认值是std::equal_to<K>。
第五个模板参数_Alloc:分配器,缺省用new和delete。
创建std::unordered_map类模板的别名:
template<class K,class V>
using umap = std::unordered_map<K, V>;
std::map
和 std::unordered_map
区别:
1. 底层数据结构
-
std::map
:std::map
的底层数据结构是基于红黑树(Red-Black Tree)实现的。红黑树是一种自平衡二叉搜索树,它在插入和删除节点时会通过一系列的旋转和颜色调整操作来保持树的平衡,使得树的高度始终保持在一个相对较低的水平(最坏情况下为 O(logn),其中n 是树中节点的数量)。- 这种数据结构的优点是能够保证元素按照键的大小顺序进行有序存储,并且在查找、插入和删除操作时,平均时间复杂度都为O(logn) 。例如,当你插入一个新的键值对到
std::map
中时,它会根据键的大小在红黑树中找到合适的位置进行插入,并自动调整树的结构以保持平衡和有序。
-
std::unordered_map
:std::unordered_map
的底层数据结构是基于哈希表(Hash Table)实现的。哈希表通过一个哈希函数将键映射到一个特定的桶(Bucket)中,每个桶可以存储一个或多个键值对。理想情况下,当哈希函数设计得比较好时,查找操作可以在常数时间O(1) 内完成,因为可以通过计算键的哈希值直接定位到对应的桶,然后在桶内进行查找。- 然而,哈希表存在哈希冲突(Hash Collision)的问题,即不同的键可能通过哈希函数计算得到相同的哈希值,从而被映射到同一个桶中。为了解决哈希冲突,通常会采用一些冲突解决策略,如链地址法(将冲突的键值对链接成一个链表存放在同一个桶中)或开放地址法(通过一定的规则在哈希表中重新寻找空闲的位置来存放冲突的键值对)。
2、元素顺序
由于其基于红黑树的实现,std::map
中的元素会按照键的大小顺序自动进行排序。unordered_map
中的元素是无序的,因为哈希表本身并不保证元素的顺序。键值对在哈希表中的存储位置主要取决于键的哈希值以及冲突解决策略。所以,当你遍历 unordered_map
时,元素的出现顺序是不确定的,可能与插入顺序不同,也不一定按照键的任何特定顺序排列。
例如:
#include <iostream>
#include <unordered_map>int main() {std::unordered_map<int, std::string> myUnorderedMap;myUnorderedMap.insert({ 1, "one" });myUnorderedMap.insert({ 3, "three" });myUnorderedMap.insert({ 2, "two" });// 遍历unordered_map输出所有键值对,顺序不确定for (auto it = myUnorderedMap.begin(); it != myUnorderedMap.end(); ++it) {std::cout << "键:" << it->first << ", 值:" << it->second << std::endl;}return 0;
}
这个结果每次输出结果都一样,这其实是有一定概率会出现的情况。虽然理论上 std::unordered_map
的遍历顺序是不确定的,因为它是基于哈希表实现的,元素存储位置取决于键的哈希值以及哈希冲突解决策略等因素。但在实际情况中,如果数据量比较小,而且哈希函数(std::unordered_map
默认的哈希函数或者你自定义的哈希函数,如果有的话)对于你所插入的这些键计算出来的哈希值分布相对比较均匀,没有产生过多的哈希冲突,那么就有可能每次遍历输出的顺序看起来是一样的。
不过,当你插入的数据量逐渐增大,或者插入一些特殊的键值使得哈希冲突情况发生变化时,就很可能会出现不同的遍历顺序了。
例如:
#include <iostream>
#include <unordered_map>
#include<random>
#include<utility>
int main() {std::unordered_map<int, int> myUnorderedMap;for (int i = 1; i < 1000000; i++){std::random_device rd;std::mt19937 gen(rd());// 定义分布范围为1到1000000std::uniform_int_distribution<> dis(1, 1000000);// 生成随机数int randomNumber = dis(gen);myUnorderedMap.insert(std::make_pair(i, randomNumber));}// 遍历unordered_map输出所有键值对,顺序不确定for (auto it = myUnorderedMap.begin(); it != myUnorderedMap.end(); ++it) {std::cout << "键:" << it->first << ", 值:" << it->second << std::endl;}return 0;
}
如果生成的数足够多,顺序是不确定的。
3、查找、插入和删除操作的性能特点
-
std::map
:- 查找、插入和删除操作的平均时间复杂度都是 O(logn)。这意味着在数据量较大时,这些操作的执行时间会随着数据量的增加而以对数级别的速度增长。虽然这种增长速度相对较慢,但相比一些常数时间复杂度的操作(如理想情况下的哈希表查找)还是要慢一些。不过,由于
std::map
能够保持元素的有序性,在一些需要基于顺序进行查找(如查找某个键值对之后的所有键值对)或者进行范围查找(如查找键在某个区间内的所有键值对)的场景下,它具有独特的优势。
- 查找、插入和删除操作的平均时间复杂度都是 O(logn)。这意味着在数据量较大时,这些操作的执行时间会随着数据量的增加而以对数级别的速度增长。虽然这种增长速度相对较慢,但相比一些常数时间复杂度的操作(如理想情况下的哈希表查找)还是要慢一些。不过,由于
-
std::unordered_map
:- 在理想情况下,查找操作的时间复杂度可以达到 O(1),即可以在常数时间内完成查找。这是因为通过哈希函数可以直接定位到键值对可能所在的桶,然后在桶内进行查找。然而,实际情况中,由于哈希冲突的存在,当哈希冲突比较严重时,查找操作可能会退化为链表查找(如果采用链地址法解决冲突),此时查找时间复杂度可能会变为O(n) ,其中 是桶内键值对的数量。插入和删除操作的时间复杂度也类似,在理想情况下为 O(1),但在哈希冲突严重时可能会变差。总体来说,当哈希函数设计得比较好,并且哈希冲突不太严重时,
std::unordered_map
在查找、插入和删除操作上的性能要优于std::map
。
- 在理想情况下,查找操作的时间复杂度可以达到 O(1),即可以在常数时间内完成查找。这是因为通过哈希函数可以直接定位到键值对可能所在的桶,然后在桶内进行查找。然而,实际情况中,由于哈希冲突的存在,当哈希冲突比较严重时,查找操作可能会退化为链表查找(如果采用链地址法解决冲突),此时查找时间复杂度可能会变为O(n) ,其中 是桶内键值对的数量。插入和删除操作的时间复杂度也类似,在理想情况下为 O(1),但在哈希冲突严重时可能会变差。总体来说,当哈希函数设计得比较好,并且哈希冲突不太严重时,
4. 内存占用
-
std::map
:- 由于红黑树需要存储节点之间的指针以及用于保持树平衡的额外信息(如节点的颜色等),相对来说内存占用可能会比
std::unordered_map
要多一些。具体的内存占用情况还会受到键值对类型、树的大小等因素的影响。
- 由于红黑树需要存储节点之间的指针以及用于保持树平衡的额外信息(如节点的颜色等),相对来说内存占用可能会比
-
std::unordered_map
:std::unordered_map
的内存占用主要取决于哈希表的大小(即桶的数量)以及键值对的数量。一般来说,为了减少哈希冲突,哈希表可能需要设置较大的桶数,这可能会导致一定的内存浪费。但总体而言,在数据量较大且哈希冲突不严重的情况下,std::unordered_map
的内存占用可能相对std::map
会有一定的优势。
5、总结
std::map
和 std::unordered_map
各有优缺点,在实际应用中,需要根据具体的应用场景和需求来选择合适的容器。如果需要元素按照键的顺序存储并且对查找、插入和删除操作的平均性能要求不是特别高(能够接受O(logn) 的时间复杂度),那么 std::map
是一个不错的选择;如果更看重查找、插入和删除操作的快速执行(希望在理想情况下达到 O(1) 的时间复杂度),并且不需要元素按照特定顺序排列,那么 std::unordered_map
则更为合适。
相关文章:

简述C++map容器
pair键值对 std::pair在很多关联容器(如std::map、std::multimap、std::set、std:multiset等)中被广泛应用。以std::map为例,std::map是一个键值对的容器,其中每个元素都是一个std::pair,键用于唯一标识元…...
Vue 学习随笔系列十七 -- 表格样式修改
表格样式修改 文章目录 表格样式修改一、表格背景颜色修改1、方法一2、方法二 二、多级表头颜色修改 一、表格背景颜色修改 1、方法一 表格外套一个 div ,修改div的背景色,并将表格背景色设置为透明 参考代码: <template><div cl…...

08 —— Webpack打包图片
【资源模块 | webpack 中文文档 | webpack中文文档 | webpack中文网】https://www.webpackjs.com/guides/asset-modules/?sid_for_share99125_3 Webpack打包图片以8KB为临界值判断 大于8KB的文件:发送一个单独的文件并导出URL地址 小于8KB的文件:导出一…...

01.Django快速入门
一、Django 快速入门 使用最新版本 Django4.2LTS 版本,3 年内不需要更换版本由浅入深讲解,浅显易懂课程大纲全面包含 Django 框架知识点,内容丰富全面细致知识点结合项目实战实现全栈项目应用 Django 官网(文档): https://docs.djangoproject.com/zh-h…...

【大数据学习 | Spark-Core】spark-shell开发
spark的代码分为两种 本地代码在driver端直接解析执行没有后续 集群代码,会在driver端进行解析,然后让多个机器进行集群形式的执行计算 spark-shell --master spark://nn1:7077 --executor-cores 2 --executor-memory 2G sc.textFile("/home/ha…...
Modern Effective C++ Item 14 如果函数不抛出异常请使用noexcept
C11 noexcept关键字用于指定函数不会抛出异常,有助于提高程序的异常安全性,还能够使编译器生成更加高效的代码。 noexcept 是函数接口的一部分 函数是否声明为 noexcept 是接口设计的一部分,客户端代码可能会依赖这一点。如果一个函数被声明…...
cudatoolkit安装(nvcc -V错误版本解决)
CudaToolKit安装(nvcc) cudatoolkit 是 CUDA 开发工具包(CUDA Toolkit) 的核心部分,包含了一系列用于开发和运行 CUDA 应用程序的软件组件。nvcc 是 NVIDIA CUDA 编译器驱动,用于将 CUDA C/C 代码编译成可…...
DTO和VO的区别及使用场景详解
随着互联网的发展,前后端分离的开发模式越来越流行。在前后端数据交互过程中,为了保证数据的安全性和效率,通常会采用 DTO 和 VO 来封装数据。本篇博客将详细介绍 DTO 和 VO 的区别以及使用场景。 大家可能会有个疑问,既然DTO是展…...

百度在下一盘大棋
这两天世界互联网大会在乌镇又召开了。 我看到一条新闻,今年世界互联网大会乌镇峰会发布“2024 年度中国互联网企业创新发展十大典型案例”,百度文心智能体平台入选。 这个智能体平台我最近也有所关注,接下来我就来讲讲它。 百度在下一盘大棋…...
第十六届蓝桥杯模拟赛第二期题解—Java
第十六届蓝桥杯模拟赛/校赛第二期个人题解,有错误的地方欢迎各位大佬指正 问题一(填空题) 【问题描述】 如果一个数 p 是个质数,同时又是整数 a 的约数,则 p 称为 a 的一个质因数。 请问, 2024 的最大的质因数是多少? …...
驱动开发笔记:关于3588GPIO
1.概要 2.内容 1.3588GPIO 关于RK3588的GPIO(General-Purpose Input/Output,通用输入输出引脚),以下是一些关键信息和操作指南: 一、GPIO基本概念 定义:GPIO是嵌入式系统中常见的通信接口,…...
【RK3588 Linux 5.x 内核编程】-内核线程与Mutex
内核线程与Mutex 文章目录 内核线程与Mutex1、Mutex介绍1.1 竞争条件1.2 Mutex特性2、Linux内核中的Mutex2.1 初始化Mutex2.1.1 静态方式初始化2.1.2 动态方式初始化2.2 互斥锁获取2.3 互斥锁释放3、Mutex使用示例4、驱动验证在前面的文章中,介绍了如何Linux内核中的线程,但是…...
【0342】分配并初始化 Proc Signal 共享内存 (1)
1. Proc Signal (procsignal)共享内存 Postgres内核在启动postmaster守护进程时候, 会通过函数 ProcSignalShmemInit() 去为 Proc Signal 分配并初始化指定大小的共享内存空间。整个调用链路如下。 (gdb) bt #0 ProcSignalShmemInit () at procsignal.c:118 #1 0x000000000…...

管家婆财贸ERP BR035.回款利润明细表
最低适用版本: 财贸系列 23.5 插件简要功能说明: 报表统计销售单/销售退货单/销售发票回款情况更多细节描述见下方详细文档插件操作视频: 进销存类定制插件--回款利润明细表 插件详细功能文档: 1. 应用中心增加报表【回款利润明细表】 a. b. 查询条件: ⅰ. 日期区间:…...

数据库MYSQL——表的设计
文章目录 前言三大范式:几种实体间的关系:一对一关系:一对多关系:多对多关系: 前言 之前的博客中我们讲解的是关于数据库的增删改查与约束的基本操作, 是在已经创建数据库,表之上的操作。 在实…...

netstat -tuln | grep 27017(显示所有监听状态的 TCP 和 UDP 端口,并且以数字形式显示地址和端口号)
文章目录 1. 确定占用端口的进程使用 lsof 命令使用 fuser 命令 2. 结束占用端口的进程3. 修改 MongoDB 配置文件4. 检查 MongoDB 日志文件5. 重新启动 MongoDB 服务6. 检查 MongoDB 服务状态总结 [rootlocalhost etc]# netstat -tuln | grep 27017 tcp 0 0 127.0.…...
非线性控制器设计原理
非线性控制器设计原理 非线性控制器设计旨在解决非线性系统的控制问题,克服传统线性控制器在处理非线性现象(如饱和、死区、耦合、时变性等)时的不足。其核心在于利用非线性数学工具和设计方法,使控制系统在非线性条件下具备良好…...

MySQL数据库6——SQL优化
一.SQL优化 1.插入优化 优化1:批量插入 insert into 表名 values(记录1),(记录2),……;优化2:手动提交事务 start transaction; insert into 表名 values(记录1),(记录2); insert into 表名 values(记录1),(记录2); …… commit;优化3:主键顺…...

IDEA配置本地maven
因为idea和maven是没有直接关系的。所以使用idea创建maven工程之前需要将本地的maven配置到idea环境中,这样才可以在idea中创建maven工程。配置方法如下: 1.1 配置本地maven 第一步:关闭当前工程,回到idea主界面找到customize--…...

学习日记_20241123_聚类方法(高斯混合模型)续
前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...