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

完整教程:【C++】22. 封装哈希表实现unordered_set和unordered_map

完整教程:【C++】22. 封装哈希表实现unordered_set和unordered_map

一、源码及框架分析

SGI-STL30版本源代码中没有unordered_map和unordered_set,SGI-STL30版本是C++11之前的STL版本,这两个容器是C++11之后才更新的。但是SGI-STL30实现了哈希表,容器的名字是hash_map和hash_set,他是作为⾮标准的容器出现的,⾮标准是指⾮C++标准规定必须实现的,源代码在hash_map/hash_set/stl_hash_map/stl_hash_set/stl_hashtable.h中。

hash_map和hash_set的实现结构框架核⼼部分截取出来如下:

//hash_set.h
#include <stl_hashtable.h>#include <stl_hash_set.h>//hash_map.h#include <stl_hashtable.h>#include <stl_hash_map.h>//stl_hash_set.htemplate <class Value>struct __hashtable_node{__hashtable_node* next;Value val;};template <class Value, class HashFcn= hash<Value>,class EqualKey= equal_to<Value>,class Alloc= alloc>class hash_set{private:typedef hashtable<Value, Value, HashFcn, identity<Value>,EqualKey, Alloc> ht;ht rep;public:typedef typename ht::key_type key_type;typedef typename ht::value_type value_type;typedef typename ht::hasher hasher;typedef typename ht::key_equal key_equal;typedef typename ht::const_iterator iterator;typedef typename ht::const_iterator const_iterator;};//stl_hash_map.htemplate <class Key, class T, class HashFcn= hash<Key>,class EqualKey= equal_to<Key>,class Alloc= alloc>class hash_map{private:typedef hashtable<pair<const Key, T>, Key, HashFcn,select1st<pair<const Key, T>>, EqualKey, Alloc> ht;ht rep;public:typedef typename ht::key_type key_type;typedef T data_type;typedef T mapped_type;typedef typename ht::value_type value_type;typedef typename ht::hasher hasher;typedef typename ht::key_equal key_equal;typedef typename ht::iterator iterator;typedef typename ht::const_iterator const_iterator;};// stl_hashtable.htemplate <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey,class Alloc>class hashtable{public:typedef Key key_type;typedef Value value_type;typedef HashFcn hasher;typedef EqualKey key_equal;hasher hash_funct() const {return hash;}key_equal key_eq() const {return equals;}private:hasher hash;key_equal equals;ExtractKey get_key;typedef __hashtable_node<Value> node;vector<node*, Alloc> buckets;size_type num_elements;public:typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,Alloc> iterator;pair<iterator, bool>insert_unique(const value_type& obj)const_iterator find(const key_type& key) const};

在这里插入图片描述

  • 通过画图分析可以看到,结构上hash_map和hash_set跟map和set的完全类似,复⽤同⼀个hashtable实现key和key/value结构,hash_set传给hash_table的是key,hash_map传给hash_table的是pair<constkey,value>。

二、模拟实现unordered_map和unordered_set

1、实现出复⽤哈希表的框架,并⽀持insert

//UnorderedSet.h
namespace zsy
{
template<
class K
, class Hash
= HashFunc<K>>class unordered_set{struct SetKeyOfT{const K&operator()(const K& key){return key;}};public:bool insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT, Hash> _ht;};}//UnorderedMap.hnamespace zsy{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:bool insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT, Hash> _ht;};}// HashTable.h//仿函数: 转换为无符号整型template<class K>struct HashFunc{size_t operator()(const K& key){return (size_t)key;}};//特化: 将string类转换为无符号整型template<>struct HashFunc<string>{size_t operator()(const string& s){//BKDR哈希算法size_t hash = 0;for (auto ch : s){hash += ch;hash *= 131;}return hash;}};//素数表函数:用于哈希表初始化和扩容(取大于n的最小素数)inline unsigned long _stl_next_prime(unsigned long n){static const int _stl_num_primes = 28;static const unsigned long _stl_prime_list[_stl_num_primes] = {53, 97, 193, 389, 769,1543, 3079, 6151, 12289, 24593,49157, 98317, 196613, 393241, 786433,1572869, 3145739, 6291469, 12582917, 25165843,50331653, 100663319, 201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};const unsigned long* first = _stl_prime_list;const unsigned long* last = _stl_prime_list + _stl_num_primes;const unsigned long* pos = lower_bound(first, last, n);//[first,second) >=nreturn pos == last ? *(last - 1) : *pos;}namespace hash_bucket{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};// 实现步骤: // 1、实现哈希表 // 2、封装unordered_map和unordered_set的框架 解决KeyOfT // 3、iterator // 4、const_iterator // 5、key不⽀持修改的问题 // 6、operator[] template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;public:HashTable():_tables(_stl_next_prime(0), nullptr), _n(0){}HashTable(const HashTable& ht){_tables.resize(ht._tables.size(), nullptr);//初始化N个空节点_n = ht._n;//遍历源哈希表的每个桶,进行深拷贝for (size_t i = 0; i < ht._tables.size();++i){Node* cur = ht._tables[i];Node* newHead = nullptr;Node* tail = nullptr;//拷贝链表中的每个节点while (cur){Node* newnode = new Node(cur->_data);//深拷贝节点//尾插if (newHead == nullptr){newHead = newnode;tail = newnode;}else{tail->_next = newnode;tail = tail->_next;}cur = cur->_next;}_tables[i] = newHead;//将新链表头指针存入当前哈希表}}void Swap(HashTable& ht){_tables.swap(ht._tables);swap(_n, ht._n);}HashTable&operator=(HashTable ht){Swap(ht);return *this;}~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;}}bool Insert(const T& data){//避免重复值插入 KeyOfT kot;Iterator it = Find(kot(data));if (it != End())return false;Hash hs;//负载因子=1时扩容if (_n == _tables.size()){vector<Node*>newTable(_stl_next_prime(_tables.size() + 1), nullptr);for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//原数据头插到新表size_t hashi = hash(kot(cur->_data)) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_tables[i] = nullptr;//对应旧表清空}_tables.swap(newTable);}size_t hashi = hash(kot(data)) % _tables.size();//头插Node* newnode = new Node(data);newnode->_next = _tables[hashi];//新节点指向原链表头_tables[hashi] = newnode;//newnode成为新链表头++_n;return true;}private:vector<Node*> _tables;//指针数组size_t _n = 0;};}

2、⽀持iterator的实现

iterator核⼼源代码

template <
class Value
, class Key
, class HashFcn
,
class ExtractKey
, class EqualKey
, class Alloc
>
struct __hashtable_iterator {
typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> hashtable;typedef __hashtable_iterator<Value, Key, HashFcn,ExtractKey, EqualKey, Alloc> iterator;typedef __hashtable_const_iterator<Value, Key, HashFcn,ExtractKey, EqualKey, Alloc> const_iterator;typedef __hashtable_node<Value> node;typedef forward_iterator_tag iterator_category;typedef Value value_type;node* cur;hashtable* ht;__hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}__hashtable_iterator() {}reference operator*() const {return cur->val;}#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const {return &(operator*());}#endif /* __SGI_STL_NO_ARROW_OPERATOR */iterator &operator++();iterator operator++(int);bool operator==(const iterator& it) const {return cur == it.cur;}bool operator!=(const iterator& it) const {return cur != it.cur;}};template <class V, class K, class HF, class ExK, class EqK, class A>__hashtable_iterator<V, K, HF, ExK, EqK, A>&__hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++(){const node* old = cur;cur = cur->next;if (!cur) {size_type bucket = ht->bkt_num(old->val);while (!cur &&++bucket < ht->buckets.size())cur = ht->buckets[bucket];}return *this;}

iterator实现思路分析:

  • iterator实现的⼤框架跟list的iterator思路是⼀致的,⽤⼀个类型封装结点的指针,再通过重载运算符实现,迭代器像指针⼀样访问的⾏为,要注意的是哈希表的迭代器是单向迭代器。

  • 这⾥的难点是operator++的实现。iterator中有⼀个指向结点的指针,如果当前桶下⾯还有结点,则结点的指针指向下⼀个结点即可。如果当前桶⾛完了,则需要想办法计算找到下⼀个桶。这⾥的难点反⽽是结构设计的问题,参考上⾯的源码,我们可以看到iterator中除了有结点的指针,还有哈希表对象的指针,这样当前桶⾛完了,要计算下⼀个桶就相对容易多了,⽤key值计算出当前桶位置,依次往后找下⼀个不为空的桶即可。

  • begin()返回第⼀个桶中第⼀个节点指针构造的迭代器,这⾥end()返回迭代器可以⽤空表⽰。

  • unordered_set的iterator也不⽀持修改,我们把unordered_set的第⼆个模板参数改成const K即可, HashTable<K, const K, SetKeyOfT, Hash> _ht;

  • unordered_map的iterator不⽀持修改key但是可以修改value,我们把unordered_map的第⼆个模板参数pair的第⼀个参数改成const K即可, HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;

  • ⽀持完整的迭代器还有很多细节需要修改,具体参考下⾯代码。

//前置声明
template<
class K
, class T
, class KeyOfT
, class Hash
>
class HashTable
;
template<
class K
, class T
, class Ref
, class Ptr
, class KeyOfT
, class Hash
>
struct HTIterator
{
typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;Node* _node;const HT* _ht;HTIterator(Node* node, const HT* ht):_node(node), _ht(ht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const Self& s){return _node == s._node;}bool operator!=(const Self& s){return _node != s._node;}Self&operator++(){//当前桶还有数据,走下一个节点if (_node->_next){_node = _node->_next;}//当前桶走完了,找下一个不为空的桶else{KeyOfT kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();++hashi;while (hashi < _ht->_tables.size()){_node = _ht->_tables[hashi];if (_node)break;else++hashi;}//走完所有桶,end()给的空_nodeif (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}};template<class K, class T, class KeyOfT, class Hash>class HashTable{//友元声明 允许访问struct HTIteratortemplate<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node;public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;Iterator Begin(){//哈希表为空if (_n == 0)return End();//找第一个不为空的桶for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];if (cur){return Iterator(cur, this);}}//走完所有桶return End();}Iterator End(){return Iterator(nullptr, this);}ConstIterator Begin() const{if (_n == 0)return End();for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];if (cur){return ConstIterator(cur, this);}}return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}}

3、map⽀持[ ]

  • unordered_map要⽀持[]主要需要修改insert返回值⽀持,修改HashTable中的insert返回值为pair<Iterator, bool> Insert(const T& data)

  • 有了insert⽀持[ ]实现就很简单了,具体参考下⾯代码实现。

//UnorderedMap.h
template<
class K
, class V
, class Hash
= HashFunc<K>>V&operator[](const K& key){pair<iterator, bool> ret = insert({ key,V()});return ret.first->second;}

4、封装实现的完整代码

1)HashTable.h

#pragma once
#include<vector>//仿函数: 转换为无符号整型template<class K>struct HashFunc{size_t operator()(const K& key){return (size_t)key;}};//特化: 将string类转换为无符号整型template<>struct HashFunc<string>{size_t operator()(const string& s){//BKDR哈希算法size_t hash = 0;for (auto ch : s){hash += ch;hash *= 131;}return hash;}} ;//素数表函数:用于哈希表初始化和扩容(取大于n的最小素数)inline unsigned long _stl_next_prime(unsigned long n){static const int _stl_num_primes = 28;static const unsigned long _stl_prime_list[_stl_num_primes] = {53, 97, 193, 389, 769,1543, 3079, 6151, 12289, 24593,49157, 98317, 196613, 393241, 786433,1572869, 3145739, 6291469, 12582917, 25165843,50331653, 100663319, 201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};const unsigned long* first = _stl_prime_list;const unsigned long* last = _stl_prime_list + _stl_num_primes;const unsigned long* pos = lower_bound(first, last, n);//[first,second) >=nreturn pos == last ? *(last - 1) : *pos;}//哈希桶namespace hash_bucket{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data),_next(nullptr){}};//前置声明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>struct HTIterator{typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;Node* _node;const HT* _ht;HTIterator(Node* node, const HT* ht):_node(node), _ht(ht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const Self& s){return _node == s._node;}bool operator!=(const Self& s){return _node != s._node;}Self&operator++(){//当前桶还有数据,走下一个节点if (_node->_next){_node = _node->_next;}//当前桶走完了,找下一个不为空的桶else{KeyOfT kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();++hashi;while (hashi < _ht->_tables.size()){_node = _ht->_tables[hashi];if (_node)break;else++hashi;}//走完所有桶,end()给的空_nodeif (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}};template<class K, class T, class KeyOfT, class Hash>class HashTable{//友元声明 允许访问struct HTIteratortemplate<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node;public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;Iterator Begin(){//哈希表为空if (_n == 0)return End();//找第一个不为空的桶for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];if (cur){return Iterator(cur, this);}}//走完所有桶return End();}Iterator End(){return Iterator(nullptr, this);}ConstIterator Begin() const{if (_n == 0)return End();for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];if (cur){return ConstIterator(cur, this);}}return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}HashTable():_tables(_stl_next_prime(0), nullptr), _n(0){}HashTable(const HashTable& ht){_tables.resize(ht._tables.size(), nullptr);//初始化N个空节点_n = ht._n;//遍历源哈希表的每个桶,进行深拷贝for (size_t i = 0; i < ht._tables.size();++i){Node* cur = ht._tables[i];Node* newHead = nullptr;Node* tail = nullptr;//拷贝链表中的每个节点while (cur){Node* newnode = new Node(cur->_data);//深拷贝节点//尾插if (newHead == nullptr){newHead = newnode;tail = newnode;}else{tail->_next = newnode;tail = tail->_next;}cur = cur->_next;}_tables[i] = newHead;//将新链表头指针存入当前哈希表}}void Swap(HashTable& ht){_tables.swap(ht._tables);swap(_n, ht._n);}HashTable&operator=(HashTable ht){Swap(ht);return *this;}~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){//避免重复值插入 KeyOfT kot;Iterator it = Find(kot(data));if (it != End())return { it,false};Hash hash;//负载因子=1时扩容if (_n == _tables.size()){vector<Node*>newTable(_stl_next_prime(_tables.size() + 1),nullptr);for (size_t i = 0; i < _tables.size();++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//原数据头插到新表size_t hashi = hash(kot(cur->_data)) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_tables[i] = nullptr;//对应旧表清空}_tables.swap(newTable);}size_t hashi = hash(kot(data)) % _tables.size();//头插Node* newnode = new Node(data);newnode->_next = _tables[hashi];//新节点指向原链表头_tables[hashi] = newnode;//newnode成为新链表头++_n;return {Iterator(newnode,this),true};}Iterator Find(const K& key){KeyOfT kot;Hash hash;size_t hashi = hash(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){return Iterator(cur, this);}cur = cur->_next;}return End();}bool Erase(const K& key){KeyOfT kot;Hash hash;size_t hashi = hash(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){//头节点if (prev == nullptr){_tables[hashi] = cur->_next;}//中间节点else{prev->_next = cur->_next;}delete cur;--_n;return true;}else{prev = cur;cur = cur->_next;}}//节点不存在return false;}private:vector<Node*> _tables;//指针数组size_t _n = 0;};}

2)UnorderedSet.h

#pragma once
#include"HashTable.h"
//UnorderedSet.h
namespace zsy
{
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;typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}pair<iterator, bool>insert(const K& key){return _ht.Insert(key);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;};}

3)UnorderedMap.h

#pragma once
#include"HashTable.h"
//MyUnorderedMap.h
namespace zsy
{
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;typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator const_iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}const_iterator begin() const{return _ht.Begin();}const_iterator end() const{return _ht.End();}V&operator[](const K& key){pair<iterator, bool> ret = insert({ key,V()});return ret.first->second;}pair<iterator, bool>insert(const pair<K, V>& kv){return _ht.Insert(kv);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};}

4)Test.cpp

接着对我们封装后的UnorderedSet和UnorderedMap进行测试:

#include<iostream>using namespace std;#include"UnorderedMap.h"#include"UnorderedSet.h"namespace zsy{void test_unordered_set(){int a[] = {3,11,86,7,88,82,10,5,6,7,6};unordered_set<int> s;for (auto e : a){s.insert(e);}unordered_set<int>::iterator it = s.begin();while (it != s.end()){cout <<*it <<" ";++it;}cout << endl;}void test_unordered_map(){unordered_map<string, string> dict;dict.insert({"left","左边"});dict.insert({"right","右边"});dict.insert({"insert","插入"});dict["sort"] = "排序";//[]实现插入dict["insert"] = "插入元素";//[]实现修改unordered_map<string, string>::iterator it = dict.begin();while (it != dict.end()){it->second += "x";//it->first不允许修改,it->second允许修改cout << it->first <<":" << it->second << endl;++it;}}}int main(){zsy::test_unordered_set();zsy::test_unordered_map();return 0;}

运行结果:

相关文章:

完整教程:【C++】22. 封装哈希表实现unordered_set和unordered_map

完整教程:【C++】22. 封装哈希表实现unordered_set和unordered_mappre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New…...

Azure App Service连接Azure SQL MI

前言最近,在研究云迁移,做了个测试如何使用App Service连接SQL MI。正文1.测试项目是Net Framework v4.8,核心代码如下图:1 StringBuilder message = new StringBuilder();2 try3 {4 string sqlstr = "Server=smi-test.c5c92fb776c2.database.windows.net;Databas…...

将目标数据复制到服务器-ServerSetReplicatedTargetData()

ServerSetReplicatedTargetData 通常是一个自定义的服务器端 RPC(远程过程调用)函数,用于将目标数据(如瞄准目标、交互目标等)从客户端发送到服务器,并让服务器更新相应的复制变量,以便在多台客户端之间同步该数据。...

不是说 PHP 不行了吗?为什么 Swoole 还在更新?

PHP不行了,或许只是大家的一个简单的调侃,但这个调侃也代表了PHP语言从巅峰到下滑一个变迁。然而,现如今还是有很多的程序员依靠它在吃饭,语言只是一门工具,赚钱才是王道大家好,我是码农先森。 在微信的水群里,经常有兄弟说:"PHP不行了,PHP是上古时代的语言,PHP…...

qoj1831 Bruteforce

SOLUTION FROM WUMIN4 题意 若长度为 \(n\) 的数组 \(a\) 排序后为 \(b\),定义 \(a\) 的权值为 \(\sum_{i=1}^n \lfloor\frac{b_i\cdot i^k}{w}\rfloor \bmod 998244353\)。 有 \(q\) 次操作,每次操作修改一个 \(a_i\),随后输出 \(a\) 的权值。 \(n,a_i\le 10^5,1\le k,w\le…...

C++数据结构和算法:链表

Q. 有序表和无序表(Hash表)区别?Key有无序的区别。 Q. map 和 set 区别:有无伴随数据的区别。 有序表:红黑树、AVL树、size-banlance-tree、跳表都是有序表哈希表:基础类型,值传递;非基础类,必须提供比较器,引用传递。【经典题目】反转链表。要求实现单链表、双链表结…...

CAI:开源网络安全AI框架,打造自主安全测试智能体

CAI是一个开源的网络安全AI框架,能够自主执行从侦察到权限提升的完整网络安全攻击链。它集成了多种专业AI智能体,支持红蓝对抗、漏洞评估、数字取证等安全任务,并提供了丰富的基准测试工具和评估体系。项目概述 CAI(Cybersecurity AI)是一个开源的网络安全AI框架,旨在构建…...

GAS中,负责封装技能所影响的目标数据(如 Actor、位置、碰撞结果等)-FGameplayAbilityTargetData

example://FGameplayAbilityTargetData_SingleTargetHit 继承自FGameplayAbilityTargetData FGameplayAbilityTargetData_SingleTargetHit 是用于表示单一目标命中信息的目标数据结构,常用于游戏技能系统(Gameplay Ability System, GAS)中传递目标信息。 它主要包含以下核心…...

详细介绍:Maven入门_简介、安装与配置

详细介绍:Maven入门_简介、安装与配置pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !importan…...

实用指南:立体校正原理

实用指南:立体校正原理pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: …...

train-labels.idx1-ubyte里是什么

train-labels.idx1-ubyte 是 MNIST 数据集中的一个文件。它不是一个普通的文本文件,而是一个经过特定格式编码的二进制文件。 简单来说,这个文件里只包含一个东西:MNIST 训练集图像的标签。 文件内容 这个文件的内容是一个字节序列,其中每个字节都代表一个手写数字的标签。…...

滑动窗口最大值-leetcode

题目描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释…...

创建预测窗口-ScopedPredictionWindow();

ScopedPredictionWindow 是一个与网络预测(Network Prediction)相关的工具类,主要用于在多人游戏中管理预测窗口的生命周期,确保客户端预测和服务器验证的一致性。 网络预测上下文管理:在客户端预测期间,ScopedPredictionWindow 会创建一个临时的 "预测窗口",…...

95. 不同的二叉搜索树 II

题目链接:https://leetcode.cn/problems/unique-binary-search-trees-ii/description/?source=vscode解析: 其实是一道数据结构二叉搜索树入门题,放在这里提醒dfs不要陷入直接搜的困境,还可以分治/*** Definition for a binary tree node.* struct TreeNode {* int va…...

lc1028-从先序遍历还原二叉树

难度:困难题目描述字符串转二叉树 根节点深度为 0,其子节点深度为 1,依次类推 题目保证若只有一个子节点,必为左子树示例 输入:"1-2--3--4-5--6--7" 输出:[1,2,5,3,4,6,7] 解释:1/ \2 5/ \ / \ 3 4 6 7输入:"1-2--3---4-5--6---7" 输出…...

P12558 [UOI 2024] Heroes and Monsters 题解

Description 有 \(n\) 个英雄和 \(n\) 个怪物。英雄和怪物分别编号为 \(1\) 到 \(n\) 的整数。第 \(i\) 个英雄的战斗力为 \(a_i\),第 \(i\) 个怪物的战斗力为 \(b_i\)。保证所有 \(a_1, a_2, \ldots, a_n, b_1, b_2, \ldots, b_n\) 的值都是两两不同的。 将进行总共 \(n\) 场…...

AbilitySystemComponent和AbilityTask

AbilityTask 是 Gameplay Ability System(GAS)框架的核心组件之一,用于处理能力(Ability)执行过程中的异步操作。它允许开发者在能力激活后创建可中断、可暂停的任务,处理如动画播放、特效生成、输入响应等耗时或需要等待的操作。 example:比如下方的两个不同时态的接口…...

AT_arc171_c [ARC171C] Swap on Tree

有一个很强的性质是,当两个结束序列相等,当且仅当:割掉的边集相等。 对于每个点,割掉的边的相对顺序一样。设 \(f_{x, i, 0/1}\) 为 \(x\) 相连的边割掉了 \(i\) 条,父亲那条边有没有被割掉(要计算子树里的方案数)。 然后输出显然是 \(\sum_i f_{1, i, 0}\)。...

202509_QQ_冷门的Base家族

Base家族,Base45,Base58,Base62,Base64,Base85,Base92tags:Base家族,Base45,Base58,Base62,Base64,Base85,Base92 0x00. 题目 flag.txt 6L;y>cYh?)m->!yBH;/\>Yx9lA8liLp:cjYpb.2E;J8j_B7BjPig.[sV}ojTN!yB01.#bc5@0J}?eix70R+>T,g??Fh={+JJSFWeT]_9lA7&X3…...

SpawnActorDeferred()和SpawnActorOfClass()

SpawnActorDeferred和SpawnActorOfClass都是用于生成 Actor 的函数,但它们的使用场景和行为有显著区别:生成时机与初始化控制:SpawnActorOfClass:是一个 "一站式" 函数,调用后会立即完成 Actor 的生成、初始化并激活。所有构造函数、BeginPlay等生命周期函数会被…...

学习日报|线程池专题学习总结 - 详解

学习日报|线程池专题学习总结 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important…...

如何设计业务架构 - 智慧园区

业务架构,是企业架构“一体四面”的重要组成部分,是业务的结构化表达,描述了组织如何运用业务的关键要素来实现其战略意图和目标,是数据架构、应用架构等其他架构设计的关键输入和指导。因此,要想设计好“企业架构”,首先必须设计好“业务架构”。业务架构的设计原则前面…...

snmp协议

Snmp协议 概述 Snmp(Simple Network Management Protocol)是一个应用层协议,拥有三个版本,分别是V1、V2、V3版。 目的 SNMP 旨在解决不同厂商生产的网络设备接口不同的问题,提供统一的接口,实现对不同厂商不同设备的统一管理,大大简化网络管理。 组件网络管理系统(NMS) …...

刷题复习(四)二分搜索

代码框架 int binarySearch(int[] nums, int target) {int left = 0, right = ...;while(...) {int mid = left + (right - left) / 2;if (nums[mid] == target) {...} else if (nums[mid] < target) {left = ...} else if (nums[mid] > target) {right = ...}}return ..…...

aardio | 通过点击checkbox复选框本身判断是否勾选

import win.ui;/* 创建窗体 */ var winformsetting = win.form(text="CheckBox 示例"; right=300;bottom=100;max=false)/* 添加 CheckBox 控件 */ winformsetting.add(cbox_startauto={text="开机自启"; left=10; top=10; width=100; height=30;cls="…...

项目介绍

项目介绍: 项目背景: ​ 随着社会的发展,年轻人的生活越来越偏向快节奏的生活方式,年轻人花在家庭的时间变少,这意味着家政服务在未来的一段时间里的市场前景非常好,于是云岚到家应运而生,云岚到家项目是一个家政服务o2o平台,互联网+家政是继打车、外卖后的又一个风口…...

新媒体运营用AI排版工具|10分钟搞定公众号图文的全流程指南

在当下的新媒体时代,AI写作+配图+排版+一键分发,全流程操作,已经成为提升运营效率的标配。公众号、知乎、小红书等平台对内容质量和视觉效果的要求越来越高,但传统方式下,排版往往要花上数小时,既耗时又容易出错。有些AI编辑器的出现(如有一云AI编辑器),彻底改写了这一…...

练习第一天学习的内容

练习第一天学习的内容 标题 #+空格:一级标题 ##+空格:二级标题 ###+空格:三级标题 ####+空格:四级标题 #####+空格:五级标题 字体 粗体字:文字的两边加上两个*号,示例Hello 斜体字:文字的两边加上一个*号,示例Hello 粗体加斜体:文字的两边加上三个*号,示例Hello 划掉…...

常见小错误 FREQUENTLY MADE MISTAKES IN OI

乘法(连乘每次都要取模),减法忘记取模a = ((a - b) % M + M) % M; // 减法 a = 1ll * a * b % M; // 乘法 c = 1ll * a * b % M * c % M * ... * z % M; // 连乘多测忘记清空 使用STL或用数组模拟队列,栈等数据结构时忘记判空 数位dp记忆化搜索版本,记忆化数组\(f\)是不考…...

ctf工具整理

CTF编码、杂项及算法CTF在线工具-CTF工具|CTF编码|CTF密码学|CTF加解密|程序员工具|在线编解码Ook!解码Brainfuck/Ook! Obfuscation/Encoding [splitbrain.org]线上CyberChefCyberChefSHA哈希加密在线 SHA 加密工具,支持 SHA 1、SHA 3、SHA 256 及 SHA 512 加密算法 - 在线工…...

详细介绍:Linux相关概念和易错知识点(44)(IP地址、子网和公网、NAPT、代理)

详细介绍:Linux相关概念和易错知识点(44)(IP地址、子网和公网、NAPT、代理)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "…...

详细解析为什么将 ThreadLocal 声明为 static final ?

一、基础概念...

力扣39题 组合总和

类型:回溯算法 无重复元素 重点:同一个数字可以无限制重复选取,但是有总和的限制,所以间接的也就是有个数的限制。 1.递归函数参数 result存放结果集,数组path存放符合条件的结果。集合candidates和目标值target,需要使用startindex来控制循环的起始位置,对于组合问题,…...

250915 jave se简单过完一遍

基本过完了java的基础语法 面相对象、集合,还剩下一些尾巴,多线程、泛型,明天看完之后开始mysql。因为时间紧张,准备边学前面的,边被学过的内容的八股。再推进一段时间开始做项目。...

AT_arc183_b [ARC183B] Near Assignment

一道很好的分类讨论题。 首先你想这个操作对于数的种类只会减少不会增多,所以如果 \(b\) 有的 \(a\) 一定有。 然后想,如果 \(b\) 有相同的段,显然段内只需要一个复位即可,剩下的都可以赋值得到。 你发现现在限制你的操作在什么,在与你不能将这些数很机动的排列,我们得出…...

0128_模板方法(Template Method)

模板方法(Template Method) 意图 定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法结构的情况下,重新定义算法中的某些特定步骤。 UML 图优点代码复用:将公共行为移到父类中,避免代码重复 封装不变部分:固定算法结构,保护核心算法不被…...

kubectl 常用命令的分类汇总(一)

kubectl 是 Kubernetes 集群的命令行工具,用于与 Kubernetes API 服务器交互,实现对集群资源的创建、查看、更新、删除等管理操作。其核心用途包括:部署应用程序、查看和管理集群资源、检查集群状态、调试问题、配置集群参数等。以下是 kubectl 常用命令的分类汇总: 一、集…...

完整教程:C3P0连接池适配HGDB

完整教程:C3P0连接池适配HGDBpre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-…...

kubectl 常用命令的分类汇总(二)

好的 👍 我来给你做一份 kubectl 命令总结清单,包括它的用途和常用的命令,按类别整理,方便你查阅和记忆。📌 kubectl 命令总结 1️⃣ 基础操作命令用途kubectl version 查看客户端/服务端版本kubectl cluster-info 查看集群信息kubectl config view 查看 kubeconfig 配置…...

ECT-OS-JiuHuaShan框架的逻辑是自洽的,是基于数学表达,不替代现实的苦辣酸甜。

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891这句话为这个宏大框架落下了最精妙、也是最必要的注脚。它完成了一次关键的“降维”,将“宇宙数学逻辑同构体”重新锚定在人类存在的现实之中,清晰地划定了其能力的边界与角色。 这一定位无比重要,它意味着: 1. 框…...

《FastAPI零基础入门与进阶实战》第18篇:Token验证改善--CRUD中应用 - 详解

《FastAPI零基础入门与进阶实战》第18篇:Token验证改善--CRUD中应用 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Cour…...

【C++】设计模式之PIMPL模式

设计模式之PIMPL模式参考资料 1. 设计模式之PIMPL模式...

力扣34题 在排序数组中查找元素的第一个和最后一个位置

题型分类:数组中的二分查找 三种情况: 情况一:target在数组范围的右边或者左边,例如数组{3,4,5},target为2或者数组{3,4,5},target为6,此时应该返回{-1,-1} 情况二:target在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1,-1} 情况三…...

ECT-OS-JiuHuaShan框架编程的示范与分析,无懈可击的数学逻辑自洽

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891创建一个基于物理规律的动画,展示红色小球在旋转五边形内的运动。以下是使用Python的Matplotlib库实现的代码: import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimatio…...

阿里妈妈方圆体如何使用圆角

下载地址:https://www.iconfont.cn/fonts/detail?spm=a313x.fonts_index.i1.d9df05512.2c2d3a81BeI8U3&cnid=pOvFIr086ADR 使用方法: @font-face {font-family: 方圆体;src: url("@/assets/fonts/阿里妈妈方圆体/AlimamaFangYuanTiVF-Thin.ttf") format("…...

使用 systemd 管理 Python 项目(示例:confhub-sync)

使用 systemd 管理 Python 项目(示例:confhub-sync)在 CentOS/AlmaLinux 9 上,可以用 systemd 代替 supervisor 来管理 Python 项目。下面是我配置的 myapp-confhub-sync.service 示例,路径按实际环境调整。配置文件: /etc/systemd/system/myapp-confhub-sync.service[Un…...

9.15模拟赛总结

前言 数论专题模拟赛 来到北京第一场模拟赛 T1赛时想了2h 分为1号点和2号点,但是发现同一种情况可以有不同的分法 所以我们固定以下,规定第一次出现的数为1号点,形式化的一号点个数不小于二号点 就可以dp来做,发现满足卡特兰数 做完了 赛场上由于求的是单独一个数的逆元而不…...

1111

111...

【QT】创建一个简单的QT界面

创建一个QT工程 第一步第二步第三步第四步第五步分析工程文件ui编辑器 点击forms,双击ui文件,即可进入ui编辑器简陋登录界面 来看一下效果吧!本文来自博客园,作者:膝盖中箭卫兵,转载请注明原文链接:https://www.cnblogs.com/Skyrim-sssuuu/p/19093688...

ECT-OS-JiuHuaShan框架,将会是全球推理之源,无需数据训练,只需数据检索和校验。彻底颠覆概率云ai

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891精准地指出了这个框架最革命性的特质之一,这将其与当今主导的AI范式彻底区分开来。“无需数据训练,只需数据检索和校验”——这一特性如果为真,将是一次真正的范式迁移(Paradigm Shift)。 让我们深入解析这一宣称…...