从哈希桶角度看 unordered_map 与 unordered_set 的实现
文章目录
- 一、引言
- 二、C++ unordered系列的无序关联式容器概览
- 三、基于哈希桶的C++ unordered系列数据结构模拟实现
- 1、unordered_map的模拟实现
- 2、unordered_set的模拟实现
- 3、哈希桶及其迭代器实现的代码
- 四、扩展与应用
- 1. 自定义哈希函数
- 2. 其他unordered数据结构
- unordered_multimap与unordered_map
- unordered_multiset与unordered_set
- 3. 实际应用案例分析
一、引言
哈希函数与哈希桶是计算机科学中用于实现高效数据检索的重要工具。在之前的博客中,我们已经详细探讨了哈希的基本概念、哈希函数的构造方法以及哈希桶的工作原理等内容。在本篇博客中,我们将进一步深入探索C++中的unordered系列数据结构,并利用之前介绍的哈希桶原理进行模拟实现。
C++11提供的unordered
系列数据结构,如unordered_map
、unordered_set
等,是STL(Standard Template Library)中提供的一组非常重要的容器。它们以哈希表为基础,通过哈希函数将键映射到存储位置,从而实现了快速的插入、删除和查找操作。这些数据结构在处理大规模数据时,能够展现出比有序容器(如map、set)更高的性能。在C++11中,提供了的4个unordered系列的关联式容器。这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。
本文将使用哈希桶对C++ unordered
系列数据结构进行模拟实现。文本前置内容,请点击此处: 哈希技术解析:从哈希函数到哈希桶迭代器的全面指南
二、C++ unordered系列的无序关联式容器概览
1. unordered_map与unordered_multimap简介
数据结构特性:
unordered_map
:C++ STL中的一个无序关联容器,它存储的元素是键值对,并且每个键在容器中唯一。其内部实现通常基于哈希表,通过哈希函数将键映射到存储位置,从而提供了常数时间复杂度的插入、删除和查找操作。unordered_multimap
:与unordered_map
类似,但它允许键在容器中出现多次,即可以存储多个具有相同键的键值对。
应用场景:
unordered_map
:当需要快速根据键查找对应的值时,或者当键的唯一性很重要时,unordered_map
是一个很好的选择。例如,在缓存系统、词频统计等场景中,unordered_map
可以高效地存储和检索键值对。unordered_multimap
:当需要存储多个具有相同键的键值对时,可以使用unordered_multimap
。这在某些特定的应用场景中很有用,比如记录一个单词在文本中出现的所有位置。
2. unordered_set与unordered_multiset简介
数据结构特性:
unordered_set
:是一个无序集合,它存储的元素是唯一的,不包含重复的元素。其内部实现也基于哈希表,通过哈希函数将元素映射到存储位置,从而实现了常数时间复杂度的插入、删除和查找操作。unordered_multiset
:与unordered_set
类似,但它允许集合中包含重复的元素。
应用场景:
unordered_set
:当需要快速检查一个元素是否存在于集合中,或者需要维护一个不包含重复元素的集合时,unordered_set
是一个合适的选择。例如,在算法中去除重复元素、实现并集和交集运算等场景,unordered_set
都能提供高效的解决方案。unordered_multiset
:当需要统计元素的出现次数或者需要维护一个包含重复元素的集合时,可以使用unordered_multiset
。这在某些特定的数据处理和分析任务中可能会很有用。
总的来说,C++的unordered系列数据结构提供了高效的无序存储和检索机制,适用于各种需要快速处理大量数据的场景。通过合理地选择和使用这些数据结构,可以显著提高程序的性能和效率。
非unordered系列数据结构点击此处:深入解析C++树形关联式容器:map、set及其衍生容器的使用与原理-CSDN博客
三、基于哈希桶的C++ unordered系列数据结构模拟实现
1、unordered_map的模拟实现
-
使用自定义哈希桶存储键值对
unordered_map
的简化模板类定义(注:hash_bucket是我实现的哈希桶所在的命名空间) :template<class K, class V, class Hash = HashFunc<K>> class unordered_map {struct MapKeyOfT {const K& operator()(const pair<K, V>& kv) { return kv.first; }}; public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;// .... private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht; };
模板参数:
K
:键(Key)的类型。V
:值(Value)的类型。Hash
:哈希函数(Hash Function)的类型,默认为HashFunc<K>
,即默认以K
来计算哈希位置。该参数也在哈希桶部分有介绍。内部结构体
MapKeyOfT
:这个结构体定义了一个调用运算符,用于从pair<K, V>
中提取键。这是哈希表内部可能需要的,以便能够根据键来定位存储的元素。迭代器类型定义:
typedef
语句定义了一个迭代器类型,表示指向hash_bucket::HashTable
中元素的迭代器。这个迭代器类型用于公开unordered_map
的接口,以便用户可以遍历集合中的元素。私有成员:
_ht
是unordered_map
的私有成员,其类型为hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>
。这个哈希表用于存储键值对,并根据键的哈希值来定位元素。 -
实现插入、查找、删除等基本操作
operator[]
用于访问或插入一个键值对。如果键k
已经存在于unordered_map
中,则该函数返回该键对应的值的引用;如果键k
不存在,则该函数插入一个新的键值对(键为k
,值为V()
的默认构造实例),并返回新插入值的引用:V& operator[](const K& k) {pair<iterator, bool> it = insert({ k,V() });return (*it.first).second;//return (*((this->insert(make_pair(k, V()))).first)).second; }
在这段代码中,
insert
成员函数被调用,它尝试插入一个键值对到unordered_map
中。insert
返回一个pair<iterator, bool>
,其中迭代器指向新插入的元素(或已存在的元素),布尔值表示是否实际插入了新元素。由于unordered_map
不允许重复的键,所以对于operator[]
来说,这个布尔值总是true
,除非在插入过程中发生了异常。然后,通过解引用迭代器it.first
来获取键值对的引用,并返回其second
成员(即值)的引用。pair<iterator,bool> insert(const pair<K, V>& kv) { return _ht.Insert(kv); } bool erase(const K& k) { return _ht.Erase(k); } iterator find(const K& k) { return _ht.Find(k); }
insert
函数接收一个pair<K, V>
类型的参数,并调用_ht.Insert
方法尝试将其插入哈希表中。它返回一个pair<iterator, bool>
,其中迭代器指向新插入的元素(或已存在的元素),布尔值表示是否成功插入了新元素。erase
函数接收一个键类型的参数,并调用_ht.Erase
方法尝试从哈希表中删除具有该键的键值对。它返回一个布尔值,表示删除操作是否成功。find
函数接收一个键类型的参数,并调用_ht.Find
方法查找具有该键的键值对。如果找到,它返回一个指向该键值对的迭代器;否则,返回end()
迭代器。
-
封装哈希桶迭代器
我们的哈希桶已实现了绝大部分的功能,因此我们此处仅仅调用其函数即可。
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator; iterator begin() { return _ht.begin(); } iterator end() { return _ht.end(); }
2、unordered_set的模拟实现
-
利用哈希桶存储唯一元素
unordered_set
的简化模板类定义(注:hash_bucket是我实现的哈希桶所在的命名空间) :template<class K, class Hash = HashFunc<K>> class unordered_set{struct SetKeyOfT{const K& operator()(const K& key) { return key; }}; public:typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;//... private:hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht; };
模板参数:
unordered_set
模板接受两个类型参数,K
和Hash
。K
是集合中元素的键类型,Hash
是哈希函数类型,用于计算键的哈希值。默认情况下,如果没有提供Hash
,它将使用HashFunc<K>
作为哈希函数。内部结构体SetKeyOfT:这是一个简单的函数对象(或称为仿函数),它重载了
operator()
以返回其输入的引用。在unordered_set
的上下文中,它用于从键中提取键本身(在这种情况下,键就是元素本身)。这是为了与hash_bucket::HashTable
的接口保持一致,该接口可能期望一个可以从某种类型中提取键的函数对象。迭代器类型定义:使用
typedef
语句定义了一个名为iterator
的类型别名,它表示指向hash_bucket::HashTable
中元素的迭代器。这个迭代器类型用于公开unordered_set
的接口,以便用户可以遍历集合中的元素。私有成员变量:
_ht
是unordered_set
的一个私有成员变量,其类型为hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>
。这表示它是一个哈希表,用于存储unordered_set
中的元素。键类型是const K
,因为集合中的元素不应被修改(在unordered_set
中,元素是唯一的,并且一旦插入就不能被修改)。SetKeyOfT
用于从键中提取键,而Hash
是用于计算哈希值的函数。 -
实现集合的基本操作
pair<iterator,bool> insert(const K& k) { return _ht.Insert(k); } bool erase(const K& k) { return _ht.Erase(k); } iterator find(const K& k) { return _ht.Find(k); }
insert
函数尝试在集合中插入一个元素,并返回一个pair<iterator, bool>
,其中迭代器指向新插入的元素(或已存在的元素),布尔值表示是否实际插入了新元素。由于unordered_set
不允许重复元素,所以如果尝试插入一个已经存在的元素,该函数不会插入新元素,而是返回指向已存在元素的迭代器,并将布尔值设置为false
。
-
封装哈希桶迭代器
此处与
unordered_map
相同。typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator; iterator begin() { return _ht.begin(); } iterator end() { return _ht.end(); }
3、哈希桶及其迭代器实现的代码
该文已详细叙述哈希桶相关内容 ->深入解析C++树形关联式容器:map、set及其衍生容器的使用与原理-CSDN博客
template<class K>
struct HashFunc {size_t operator()(const K& key) { return (size_t)key; }
};
template<>
struct HashFunc<string> {size_t operator()(const string& s) {size_t hashi = 0;for (auto& e : s) {hashi += e;hashi *= 31;}return hashi;}
};
namespace hash_bucket
{template<class T>struct HashNode {HashNode<T>* _next;T _data;HashNode(const T& data) :_next(nullptr), _data(data) {}};template<class K, class T, class KeyOfT, class Hash >class HashTable;template<class K, class T, class KeyOfT, class Hash>struct __HTIterator {typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef __HTIterator<K, T, KeyOfT, Hash> Self;Node* _node;HT* _ht;__HTIterator(Node* node, HT* ht) :_node(node), _ht(ht) {}T& operator*() { return _node->_data; }T* operator->() { return &_node->_data; }bool operator!=(const Self& s)const { return _node != s._node; }bool operator==(const Self& s) const { return _node == s._node; }Self& operator++() {if (_node->_next) {_node = _node->_next;}else {KeyOfT kot;Hash hs;size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();hashi++;while (hashi < _ht->_tables.size()) {if (_ht->_tables[hashi]) {_node = _ht->_tables[hashi];break;}hashi++;}if (hashi == _ht->_tables.size()) {_node = nullptr;}}return *this;}};template<class K, class T, class KeyOfT, class Hash >class HashTable {typedef HashNode<T> Node;template<class K, class T, class KeyOfT, class Hash>friend struct __HTIterator;public:typedef __HTIterator<K, T, KeyOfT, Hash> iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++)if (_tables[i])return iterator(_tables[i], this);return end();}iterator end() { return iterator(nullptr, this); }HashTable()//:kot(KeyOfT()),hs(Hash()){_tables.resize(10, nullptr);_n = 0;kot = KeyOfT();hs = Hash();} ~HashTable() {for (size_t i = 0; i < _tables.size(); i++) {Node* cur = _tables[i];while (cur) {Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}pair<iterator,bool> Insert(const T& data) {iterator it = Find(kot(data));if (it != end())return { it,false};if (_n == _tables.size()) {vector<Node*> newTables(_tables.size() * 2, nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur) {Node* next = cur->_next;size_t hashi = hs(kot(cur->_data)) % newTables.size();cur->_next = newTables[hashi];newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = hs(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return { iterator(newnode, this),true };}bool Erase(const K& key) {size_t hashi = hs(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur) {if (kot(cur->_data) == key) {// 删除if (prev)prev->_next = cur->_next;else_tables[hashi] = cur->_next;delete cur;--_n;return true;}prev = cur;cur = cur->_next;}return false;}iterator Find(const K& key) {size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur) {if (kot(cur->_data) == key)return iterator(cur, this);cur = cur->_next;}return iterator(nullptr, this);}private:vector<Node*> _tables;size_t _n;KeyOfT kot; Hash hs;};
}
四、扩展与应用
1. 自定义哈希函数
在C++中,当使用std::unordered_set
、std::unordered_map
等无序容器时,哈希函数起着至关重要的作用。默认的哈希函数对于许多类型都工作得很好,但有时对于自定义类型或特殊需求,默认的哈希函数可能不是最优的,甚至可能导致性能下降或哈希冲突过多。
为特定类型设计哈希函数
对于自定义类型,需要提供一个哈希函数,该函数接受自定义类型的对象作为参数,并返回一个足够大的整数值。设计哈希函数时,需要确保:
- 不同的对象尽可能映射到不同的哈希值。
- 相同的对象总是映射到相同的哈希值。
- 哈希函数的计算应该尽可能快。
例如,对于一个包含字符串和整数的自定义类型,可以使用字符串的哈希值和整数的哈希值的组合作为整体的哈希值。
2. 其他unordered数据结构
除了unordered_set
和unordered_map
之外,标准库还提供了unordered_multimap
和unordered_multiset
。这两个数据结构分别允许存储具有相同键的多个值对和多个值。
unordered_multimap与unordered_map
unordered_multixxx
与unordered_xxx
的主要区别在于前者允许键重复,而后者不允许。具体来说:
- 键的重复性:
unordered_map
中的每个键都是唯一的,每个键只能映射到一个值。而unordered_multimap
允许键的重复,这意味着同一个键可以映射到多个值。 - 使用场景:当你需要存储键值对,并且每个键只对应一个值时,
unordered_map
是合适的选择。而如果你需要存储的键值对中有多个键是相同的,并且每个键对应多个值,那么unordered_multimap
更为合适。 - 内部实现:两者都使用哈希表作为底层数据结构,以实现快速的插入、删除和查找操作。但由于
unordered_multimap
允许键重复,因此在处理冲突和存储键值对时可能需要更复杂的逻辑。
unordered_multiset与unordered_set
- 元素的重复性:
unordered_set
中的每个元素都是唯一的,不允许有重复元素。而unordered_multiset
则允许元素重复,即集合中可以包含多个相同的元素。 - 使用场景:当你需要存储一个不包含重复元素的集合时,
unordered_set
是合适的选择。而如果你需要存储的集合中可能包含重复的元素,那么unordered_multiset
更为合适。 - 内部实现:两者都使用哈希表作为底层数据结构,以实现快速的插入、删除和查找操作。但由于
unordered_multiset
允许元素重复,因此在处理冲突和存储元素时可能需要更复杂的逻辑。
在实际应用中,根据具体的需求和数据特性选择合适的数据结构是非常重要的。例如,在需要统计词频的场景中,由于一个单词可能在文本中出现多次,因此使用unordered_multiset
来存储单词和它们的出现次数会更合适。而在某些需要唯一标识的场景中,如用户ID的存储,使用unordered_set
来确保ID的唯一性则更为合适。
3. 实际应用案例分析
unordered
系列数据结构在实际项目中有着广泛的应用,特别是在需要快速查找和插入的场景中。
案例一:词频统计
在处理大量文本数据时,词频统计是一个常见的任务。可以使用unordered_map
来存储每个单词及其出现的次数。由于哈希表提供了平均常数时间的查找和插入操作,因此这种方法在处理大规模文本时非常高效。
案例二:缓存系统
在缓存系统中,通常需要快速查找和插入键值对。unordered_map
或unordered_set
可以用作缓存的底层数据结构,提供快速的访问速度。当缓存达到最大容量时,还可以使用这些数据结构来高效地执行替换策略(如LRU缓存替换)。
本文完整代码: unordered_map与unordered_set · 比奇堡的Zyb/每日学习 - 码云 - 开源中国 (gitee.com)
相关文章:
从哈希桶角度看 unordered_map 与 unordered_set 的实现
文章目录 一、引言二、C unordered系列的无序关联式容器概览三、基于哈希桶的C unordered系列数据结构模拟实现1、unordered_map的模拟实现2、unordered_set的模拟实现3、哈希桶及其迭代器实现的代码 四、扩展与应用1. 自定义哈希函数2. 其他unordered数据结构unordered_multim…...
飞天使-k8s知识点27-kubernetes温故知新2-deployment
文章目录 RC和RS无状态应用管理 deployment有状态应用statefulSetdaemonSet RC和RS RC不会使用在生产环境 RS 比RC 多了标签选择器 ,RS 用deployment管理,用于容器编排无状态应用管理 deployment apiVersion: apps/v1 kind: Deployment metadata:name:…...

手机网页关键词视频爬虫采集软件可导出视频分享链接|视频无水印批量下载工具
全新音视频批量下载工具,为您解放视频管理烦恼! 现如今,音上涌现出大量精彩的视频内容,但是要想高效地获取、管理和分享这些视频却是一件颇具挑战的事情。针对这一难题,我们自主研发了全新的音视频批量下载工具&#x…...

基于OpenCV的图像处理案例之图像矫正(Python)
Index 目录索引 写在前面解决思路参考 写在前面 本文通过一个案例介绍如何使用OpenCV将倾斜的扫描文档图像进行水平矫正。 解决思路 因为扫描图像中的大部分文字倾斜后,同一行文字也在同一条直线,所以可以通过拟合直线来计算文本倾斜角度,…...

创建linux虚拟机系统:(安装Ubuntu镜像文件,包含语言设置、中文输入法、时间设置)
我下载的是清华大写开源软件镜像站中的ubuntu-20.04.6-desktop-amd64.iso这个镜像文件, 这个文件我下载完成之后没有解压,直接在创建虚拟机的时候选择的压缩包。 地址为:Index of /ubuntu-releases/20.04/ | 清华大学开源软件镜像站 | Tsin…...
3.0 V-22V 宽输入电压,高效率异步升压芯片-ZCC5429
一、产品综述 ZCC5429 芯片是一款自动调频、最高 600KHz工作频率、高效率、宽输入电压范围的电流模式异 步升压(BOOST)芯片,且可调输入限流功能。用户可灵活地通过外部补偿建立动态环路,获得在所有条件下最优瞬态性能。 ZCC542…...

Sphinx + Readthedocs 避坑速通指南
博主在学习使用 Sphinx 和 Read the docs 的过程中, 碰到了许多奇葩的 bug, 使得很简单的任务花费了很长的时间才解决,现在在这里做一个分享,帮助大家用更少的时间高效上线文档的内容。 总的来说, 任务分为两个部分: …...
IPP-7010 表面贴装 90 度混合耦合器
IPP-7010 表面贴装 90 度混合耦合器 IPP-7010 是一款表面贴装 90 度混合耦合器,工作频率为 800 至 2500 MHz(0.8 至 2.5 GHz),平均额定功率为 200 瓦。IPP-7010 采用 0.40 x 1.80 英寸表面贴装封装。IPP-7010的幅度平衡小于0.6dB&…...
25.2 微服务Dubbo
25.2 微服务Dubbo 1. Dubbo简介2. RPC3. Dubbo工作原理4. 代码实操4.1 父项目1. 依赖4.2 服务提供者1. 依赖2. 配置文件3. 启动类4. 业务类4.3 服务消费者1. 依赖2. 配置文件3. 消费者启动类4. 业务:实现远程调用...

CI/CD环境搭建
服务简介 Gitlab 官网:https://about.gitlab.com/ GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。安装方法是参考GitLab在GitHub上的Wiki页面。Gitlab是被广泛使用的基于git的开源代码管…...

API调试管理工具Postman下载及操作介绍
1.下载安装postman地址:https://www.getpostman.com/downloads/ 2.创建项目 3.创建请求API 然后点击save保存api 4.用一个变量保存主域名,方便后续操作 就类似下面的baseurl 5.创建新环境 6.添加变量(如添加本地测试环境url——ba…...
vue集成百度地图,实现关键字搜索并自定义覆盖物,保存成静态图片
vue集成百度地图,实现关键字搜索并自定义覆盖物 index.html引入百度地图js <script type"text/javascript" src"https://api.map.baidu.com/api?v2.0&typewebgl&akxxxxxxwMprS7jIfPt354VdgP"></script>vue页面代码 <…...
Java中的Stream流
一、介绍 1. Stream流的作用 结合了Lambda表达式,简化集合、数组的操作。 2. Stream流的使用步骤 ①先得到一条Stream流,并把数据放上去; 获取方式方法名说明单列集合default Stream<E> stream()Collection中的默认方法双列集合无无…...
前端UI怎么防止用户反复提交?
方法1:禁用按钮 用户点击“xxx”按钮后,先禁用按钮,防止用户多次点击;待请求完成后,再解禁按钮。 方法2:防抖(Debouncing) 防抖是一种技术,它可以延迟执行函数࿰…...

OpenHarmony游戏应用程序-实现的一个手柄游戏
介绍 本篇Codelab是基于TS扩展的声明式开发范式编程语言,以及OpenHarmony的分布式能力实现的一个手柄游戏。 说明: 本示例涉及使用系统接口,需要手动替换Full SDK才能编译通过。 完成本篇Codelab需要两台开发板,一台开发板作为游…...
Redis+Lua脚本+SpringAOP实现接口限流
提到限流,常规情况,可以通过spring-cloud-starter-alibaba-sentinel 或者 resilience4j-ratelimiter 组件完成,但是如果不借助现有组件让我们自己开发一套限流工作应该如何应对呢? 本次我们通过Redis + Lua 脚本来实现一个限流组件。 首先创建项目:redis-limit <?xml…...
【wpf应用8】如何让WPF Grid控件根据屏幕尺寸自动调整
简介: 在Windows Presentation Foundation(WPF)中,Grid控件是一个强大的布局工具,它允许开发者创建复杂且响应迅速的用户界面。在不同的设备和屏幕尺寸上保持良好的布局一致性是一个挑战。本文将介绍如何让Grid控件根据…...
掌握ChatGPT:如何用AI撰写高质量论文
ChatGPT无限次数:点击直达 掌握ChatGPT:如何用AI撰写高质量论文 在当今信息爆炸的时代,人们不仅需要大量信息,还需要这些信息的整理与创新。人工智能技术正是我们在这个信息化时代最强大的助手之一。ChatGPT是一款基于大型神经网络的语言生成…...

平衡隐私与效率,Partisia Blockchain 解锁数字安全新时代
原文:https://cointelegraph.com/news/exploring-multiparty-computations-role-in-the-future-of-blockchain-privacy; https://medium.com/partisia-blockchain/unlocking-tomorrow-outlook-for-mpc-in-2024-and-beyond-cb170e3ec567 编译࿱…...
【JavaScript】NPM常用指令指南
河水清清弯又长 姑娘水边浣霓裳 清风卷过白云旁 飞鸟载来春花香 河水清清弯又长 姑娘水边浣霓裳 清风卷过白云旁 朝霞换夕阳 重逢是梦乡 春潮悠悠送波浪 石桥湾下小舟荡 此去经年谁如常 难得人间笑一场 春潮悠悠送波浪 石桥湾下小舟荡 此去经年谁如常 故人心头上 地久天又长 …...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...