STL源码剖析:Hashtable
hashtable 概述
哈希表是一种数据结构,它提供了快速的数据插入、删除和查找功能。它通过使用哈希函数将键(key)映射到表中的一个位置来实现这一点,这个位置称为哈希值或索引。哈希表使得这些操作的平均时间复杂度为常数时间,即O(1)。
哈希表使用哈希函数将键映射到一个固定大小的数组上。
碰撞
两个不同的键通过哈希函数得到了相同的索引。由于哈希表的大小是有限的,而键的数量可能非常多,所以碰撞是不可避免的。
(1)线性探测:当发生碰撞时,线性探测会在哈希表中按线性顺序搜索下一个空闲位置。
(2)二次探测:与线性探测类似,但是搜索下一个空闲位置时,使用的是二次函数而不是线性函数。
(3)开链:每个哈希表的槽位不直接存储元素,而是存储一个链表。当发生碰撞时,新元素会被添加到对应槽位的链表中。
hashtable实现
hash_table node
template <class Value>
struct hashtable_node
{_hashtable_node* next; Value val;
};
hashtable 的迭代器
// 定义哈希表迭代器模板结构体
template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc
>
struct hashtable_iterator {// 使用typedef定义相关类型别名,以简化代码typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> hashtable_type;typedef hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> iterator_type;typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> const_iterator_type;typedef __hashtable_node<Value> node_type;typedef std::forward_iterator_tag iterator_category;typedef Value value_type;typedef ptrdiff_t difference_type;typedef std::size_t size_type;typedef Value& reference;typedef Value* pointer;// 成员变量node_type* cur; // 当前节点指针hashtable_type* ht; // 指向哈希表的指针// 构造函数hashtable_iterator(node_type* n = nullptr, hashtable_type* tab = nullptr) : cur(n), ht(tab) {}// 解引用操作符,返回当前节点的值reference operator*() const { return cur->val; }// 成员访问操作符,返回当前节点值的指针pointer operator->() const { return &(operator*()); }// 前置++iterator_type& operator++() {// 此处应有逻辑来移动迭代器到下一个节点// ...return *this;}// 后置++iterator_type operator++(int) {iterator_type temp = *this;++(*this); // 使用前置++来实现return temp;}// 相等比较操作符bool operator==(const iterator_type& it) const { return cur == it.cur; }// 不等比较操作符bool operator!=(const iterator_type& it) const { return !(*this == it); }
};
hashtable的数据结构
#include <vector> // For std::vector
#include <cstddef> // For size_t// 定义哈希表类模板
template <class Value,class Key,class HashFcn,class ExtractKey,class EqualKey,class Alloc = Alloc // 注意:这里应该是具体的分配器类名,例如 std::allocator
>
class hashtable {
public:// 为模板型别参数重新定义一个名称typedef HashFcn hasher;typedef EqualKey key_equal;typedef size_t size_type;
private:// 以下三者都是 function objectshasher hash; // 哈希函数对象key_equal equalg; // 键值比较函数对象ExtractKey get_key; // 键提取函数对象typedef hashtable_node<Value> node; // 节点类型定义typedef simple_alloc<node, Alloc> node_allocator; // 节点分配器定义std::vector<node*, Alloc> buckets; // 桶数组,使用 vector 完成size_type num_elements; // 元素数量
public:// 构造函数hashtable():num_elements(0){}// bucket 个数即 buckets vector 的大小size_type bucket_count() const { return buckets.size(); }// 其他成员函数声明...
};// 注意:hashtable_node, simple_alloc 需要被定义
// 注意:Alloc 应该是一个具体的分配器类,例如 std::allocator
虽然开链法(separate chaining)并不要求表格大小必须为质数,但 SGI STL 仍然以质数来设计表格大小,并且先将28 个质数(逐渐呈现大约两倍的关系)计算好,以备随时访问,同时提供一个函数,用来查询在这 28 个质数之中,"最接近某数并大于某数"的质数。
hashtable 的构造,插入,内存分配,拷贝和回收
hashtable类中定义了一个node_allocator类型
typedef simple_alloc<node, Alloc> node_allocator;
node* new_node(const value_type& obj) {node* n = node_allocator::allocate();n->next = 0;STL_TRY{construct(&n->val, obj); return n;}STL_UNWIND(node_allocator::deallocate(n));
}
void delete_node(node* n) {destroy(&n->val);node_allocator::deallocate(n);
}
new_node
函数分配内存并构造一个新节点,若构造失败则释放内存。
delete_node
函数销毁节点的值并释放内存。
哈希表构造
hashtable<int, int, hash<int>, identity<int>, equal_to<int>, alloc>
iht(50, hash<int>(), equal_to<int>());
创建一个哈希表iht
,初始容量为50,使用默认的哈希函数和比较函数。
初始化桶
void initialize_buckets(size_type n) {const size_type n_buckets = next_size(n);buckets.reserve(n_buckets);buckets.insert(buckets.end(), n_buckets, (node*)0);num_elements = 0;
}
initialize_buckets
函数根据给定的大小n
计算下一个质数作为桶的数量,并初始化桶为null
指针。
插入元素 和 重建 hash table
pair<iterator, bool> insert_unique(const value_type& obj) {resize(num_elements + 1);return insert_unique_noresize(obj);
}
insert_unique
调用resize
检查是否需要扩展哈希表的容量。
void resize(size_type num_elements_hi) {const size_type old_n = buckets.size();if (num_elements_hint > old_n) {const size_type n = next_size(num_elements_hint);if (n > old_n) {vector<node*, A> tmp(n, (node*)0);STL_TRY {for (size_type bucket = 0; bucket < old_n; ++bucket) {node* first = buckets[bucket];while (first) {size_type new_bucket = bkt_num(first->val, n);buckets[bucket] = first->next;first->next = tmp[new_bucket];tmp[new_bucket] = first;first = buckets[bucket];}}}buckets.swap(tmp);}}
}
resize
函数决定是否需要扩展哈希表,如果当前元素数量超过桶的数量,则重新配置桶并将现有节点转移到新桶中。
插入不重建
template<class V, class K, class HF, class Ex, class Eq, class A>
typename hashtable<V, K, HF, Ex, Eq, A>::iterator
hashtable<V, K, HF, Ex, Eq, A>::insert_equal_noresize(const value_type& obj) {const size_type n = bkt_num(obj); // 确定 obj 应位于 #n 桶node* first = buckets[n]; // 指向桶对应的链表头部
//遍历链表,查找重复的键值for(node* cur = first;cur;cur=cur->next) {if (equals(get_key(cur->val), get_key(obj))) {// 如果找到重复键值,插入新节点node* tmp = new_node(obj); // 产生新节点tmp->next = cur->next; // 新节点指向当前节点的下一个节点cur->next = tmp; // 将新节点插入到当前节点后面++num_elements; // 节点个数累加1return iterator(tmp, this); // 返回指向新节点的迭代器}}
//若没有找到重复的键值,插入到链表头部node* tmp = new_node(obj); // 产生新节点tmp->next = first; // 新节点指向当前链表的头部buckets[n] = tmp; // 更新桶指向新节点++num_elements; // 节点个数累加1return iterator(tmp, this); // 返回指向新节点的迭代器
}
bkt_num
函数的功能
bkt_num
系列函数负责将元素映射到哈希表的桶中,确保即使是无法直接对哈希表大小进行模运算的类型(如const char*
),也能正确处理。
版本 1:接受实值和桶的数量
size_type bkt_num(const value_type& obj, size_t n) const {return bkt_num_key(get_key(obj), n); // 调用版本 4
}
接收一个元素值和桶的数量,首先提取键值(get_key
),然后调用bkt_num_key
来计算桶的位置。
版本 2:只接受实值
size_type bkt_num(const value_type& obj) const {return bkt_num_key(get_key(obj)); // 调用版本 3
}
只接受元素值,调用bkt_num_key
,不需要提供桶的数量,默认为当前桶的大小。
版本 3: 只接受键值
size_type bkt_num_key(const key_type& key) const {return bkt_num_key(key, buckets.size()); // 调用版本 4
}
版本 4: 接受键值和桶的数量
size_type bkt_num_key(const key_type& key,size_t n) const {return hash(key)%n;//调用哈希函数并取模
}
最基础的版本,接受键值和桶的数量,通过哈希函数计算出键值的哈希值,并对桶的数量进行取模运算,得出最终的桶索引。
哈希表的复制(copy_from)和整体删除(clear)
由于哈希表由向量和链表组成,这两个操作都涉及内存管理。
整体删除 clear
遍历每个桶,逐个删除桶中的所有节点,确保调用delete_node
来释放内存。最后将桶的内容设置为null
指针,并将节点总数设置为0。注意向量buckets
本身并没有释放空间,只是清空了其内容。
template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::clear() {// 针对每一个 bucketfor (size_type i = 0; i < buckets.size(); ++i) {node* cur = buckets[i];// 删除 bucket list 中的每一个节点while (cur != 0) {node* next = cur->next;delete_node(cur); // 删除当前节点cur = next; // 移动到下一个节点}// 令 bucket 内容为 null 指针buckets[i] = 0;}num_elements = 0; // 令总节点个数为0// 注意,buckets vector 并未释放掉空间,仍保有原来大小
}
复制 copy_from
复制另一个哈希表的内容。首先清空当前哈希表的buckets
向量。预留空间以匹配目标哈希表ht
的桶数量。向buckets
中插入null
指针,初始化每个桶。使用STL_TRY
块来处理复制过程,确保在发生异常时能够安全清理。遍历目标哈希表的每个桶,将节点的值复制到新创建的节点中,保持链表结构。最后,更新当前哈希表的节点总数为目标哈希表的节点数量。
template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::copy_from(const hashtable& ht) {// 先清除己方的 buckets vectorbuckets.clear(); // 清空当前哈希表的内容// 为己方的 buckets vector 保留空间,使与对方相同buckets.reserve(ht.buckets.size());// 插入 n 个 null 指针buckets.insert(buckets.end(), ht.buckets.size(), (node*)0);STL_TRY {// 针对 buckets vectorfor (size_type i = 0; i < ht.buckets.size(); ++i) {if (const node* cur = ht.buckets[i]) {node* copy = new_node(cur->val); // 复制第一个节点buckets[i] = copy; // 设置当前桶的头节点// 针对同一个 bucket list 复制每一个节点for (node* next = cur->next; next; cur = next, next = cur->next) {copy->next = new_node(next->val); // 复制后续节点copy = copy->next; // 移动到新节点}}}}num_elements = ht.num_elements; // 重新登录节点个数STL_UNWIND(clear()); // 异常时清理资源
}
hashtable 运用实例
// file: hashtable-test.cpp
// 注意:客户端程序不能直接包含 <stl_hashtable.h>,
// 应该包含有用到 hashtable 的容器头文件,例如 <hash_set.h> 或 <hash_map.h>
#include <hash_set> // for hashtable
#include <iostream>
using namespace std;
int main() {// 创建哈希表// <value, key, hash-func, extract-key, equal-key, allocator>// 注意:哈希表没有默认构造函数hashtable<int, int, hash<int>, identity<int>, equal_to<int>, alloc> iht(50, hash<int>(), equal_to<int>());// 输出哈希表的信息cout << iht.size() << endl; // 输出当前元素数量,初始为0cout << iht.bucket_count() << endl; // 输出桶数量,应该是53(第一个质数)cout << iht.max_bucket_count() << endl; // 输出最大桶数量,4294967291// 插入元素iht.insert_unique(59);iht.insert_unique(63);iht.insert_unique(108);iht.insert_unique(2);iht.insert_unique(53);iht.insert_unique(55);// 输出当前元素数量cout << iht.size() << endl; // 应为6// 声明一个哈希表迭代器hashtable<int, int, hash<int>, identity<int>, equal_to<int>, alloc>::iterator ite = iht.begin();// 以迭代器遍历哈希表,输出所有节点的值for (int i = 0; i < iht.size(); ++i, ++ite) {cout << *ite << ' '; // 输出所有节点的值}cout << endl;// 遍历所有桶,输出每个桶的节点个数for (int i = 0; i < iht.bucket_count(); ++i) {int n = iht.elems_in_bucket(i);if (n != 0) {cout << "bucket [" << i << "] has " << n << " elems." << endl;}}// 测试表格重建(rehashing)for (int i = 0; i <= 47; i++) {iht.insert_equal(i); // 插入54个元素}// 输出节点数量和新的桶数量cout << iht.size() << endl; // 应为54cout << iht.bucket_count() << endl; // 应为97// 再次遍历所有桶,输出节点个数for (int i = 0; i < iht.bucket_count(); ++i) {int n = iht.elems_in_bucket(i);if (n != 0) {cout << "bucket [" << i << "] has " << n << " elems." << endl;}}// 再次以迭代器遍历哈希表,输出所有节点的值ite = iht.begin();for (int i = 0; i < iht.size(); ++i, ++ite) {cout << *ite << ';'; // 输出所有节点的值}cout << endl;// 查找元素cout << *(iht.find(2)) << endl; // 查找并输出值为2的节点cout << iht.count(2) << endl; // 输出值为2的节点个数return 0;
}
find
函数 和 count
函数
find
函数
函数用于查找具有特定键值的元素,并返回一个迭代器指向该元素。首先,通过bkt_num_key(key)
确定该元素应位于哪个桶(bucket
)。接着从该桶的头节点开始循环遍历链表,使用equals
函数比较每个节点的键值与目标键值。一旦找到匹配的键值,循环结束,返回一个指向该节点的迭代器。如果未找到匹配,返回的迭代器将指向空。
count
函数:
函数用于计算特定键值在哈希表中的出现次数。同样地,首先通过bkt_num_key(key)
确定该元素应位于哪个桶。然后,从该桶的头节点开始,循环遍历链表。对于每个节点,使用equals
函数判断键值是否与目标键值相同。如果匹配,result
计数器加1。最后返回result
,即该键值的总出现次数。
//查找元素的迭代器
iterator find(const key_type& key) {size_type n = bkt_num_key(key); // 首先找到元素应该落在哪一个桶内node* first;// 从桶的头部开始,依次比较每个元素的键值for (first = buckets[n]; first && !equals(get_key(first->val), key); first = first->next) {// 循环直到找到匹配的键值,或到达链表末尾}return iterator(first, this); // 返回迭代器,指向找到的节点或为空
}
//计算特定键值的出现次数
size_type count(const key_type& key) const {const size_type n = bkt_num_key(key); // 首先找到元素应该落在哪一个桶内size_type result = 0;// 从桶的头部开始,依次比较每个元素的键值for (const node* cur = buckets[n]; cur; cur = cur->next) {if (equals(get_key(cur->val), key)) {++result; // 如果找到匹配,累加计数}}return result; // 返回特定键值的出现次数
}
hash functions
//hash function 基础定义
template <class Key> struct hash { };
//字符串的哈希计算函数
inline size_t stl_hash_string(const char* s) {unsigned long h = 0;for (; *s; ++s) {h = 5 * h + *s; // 计算哈希值}return size_t(h);
}
//针对不同类型的哈希函数实现,对于char*类型的哈希函数
STL_TEMPLATE_NULL struct hash<char*> {size_t operator()(const char* s) const { return stl_hash_string(s); }
};
//对于 const char* 类型的哈希函数
STL_TEMPLATE_NULL struct hash<const char*> {size_t operator()(const char* s) const { return stl_hash_string(s); }
};
//对于单字符类型的哈希函数
STL_TEMPLATE_NULL struct hash<char> {size_t operator()(char x) const { return x; }
};
//对于无符号字符类型的哈希函数
STL_TEMPLATE_NULL struct hash<unsigned char> {size_t operator()(unsigned char x) const { return x; }
};
//对于有符号字符类型的哈希函数
STL_TEMPLATE_NULL struct hash<signed char> {size_t operator()(signed char x) const { return x; }
};
//对于短整型的哈希函数
STL_TEMPLATE_NULL struct hash<short> {size_t operator()(short x) const { return x; }
};
//对于无符号短整型的哈希函数
STL_TEMPLATE_NULL struct hash<unsigned short> {size_t operator()(unsigned short x) const { return x; }
};
//对于整型的哈希函数
STL_TEMPLATE_NULL struct hash<int> {size_t operator()(int x) const { return x; }
};
//对于无符号整型的哈希函数
STL_TEMPLATE_NULL struct hash<unsigned int> {size_t operator()(unsigned int x) const { return x; }
};
//对于长整型的哈希函数
STL_TEMPLATE_NULL struct hash<long> {size_t operator()(long x) const { return x; }
};
//对于无符号长整型的哈希函数
STL_TEMPLATE_NULL struct hash<unsigned long> {size_t operator()(unsigned long x) const { return x; }
};
对于整型和字符型数据,哈希函数通常直接返回原值。
对于字符串,调用 stl_hash_string
函数以计算哈希值(每位的ascii码值然后乘以5)。
SGI hashtable 无法处理上述所列各项型别以外的元素,例如string,double,float。欲处理这些型别,用户必须自行为它们定义 hash function。
相关文章:

STL源码剖析:Hashtable
hashtable 概述 哈希表是一种数据结构,它提供了快速的数据插入、删除和查找功能。它通过使用哈希函数将键(key)映射到表中的一个位置来实现这一点,这个位置称为哈希值或索引。哈希表使得这些操作的平均时间复杂度为常数时间&…...

spring-boot学习(2)
上次学习截止到拦截器 1.构建RESfun服务 PathVariable通过url路径获取url传递过来的信息 2.MyBatisPlus 第三行的mydb要改为自己的数据库名 第四,五行的账号密码改成自己的 MaooerScan告诉项目自己的这个MyBatisPlus是使用在哪里的,包名 实体类的定义…...

《案例》—— OpenCV 实现2B铅笔填涂的答题卡答案识别
文章目录 一、案例介绍二、代码解析 一、案例介绍 下面是一张使用2B铅笔填涂选项后的答题卡 使用OpenCV 中的各种方法进行真确答案识别,最终将正确填涂的答案用绿色圈出,错误的答案不圈出,用红色圈出错误题目的正确答案最终统计正确的题目数…...

新员工入职流程指南_完整入职流程解析
文章介绍了新员工入职流程的重要性、步骤及持续时间,并推荐ZohoPeople软件自动化管理入职流程,提升新员工入职体验,减少离职率,确保合规性,提升公司品牌形象。 一、新员工入职流程是怎样的? 入职流程是指一…...

mysql查看和修改默认配置
1.查看最大连接数 SELECT max_connections; 或者 SHOW VARIABLES LIKE max_connections;2.查看当前连接的客户端 SHOW PROCESSLIST;2.临时设置最大连接数 SET GLOBAL max_connections 500;3.临时设置连接客户端交互超时时间 SET GLOBAL interactive_timeout 1800;4.永久生…...

海外云手机:出海电商养号智能化方案
随着出海电商的迅猛发展,使用海外云手机进行养号已经成为越来越多商家的新选择。尤其在社交电商推广和短视频引流方面,海外云手机不仅提高了流量的精准度,还助力商家实现业务的快速增长。本文将探讨海外云手机养号相较于传统模式的优势&#…...

OpenAI Canvas用户反馈:并不如外界传言般“炸裂”,更不是“AGI的终极交互形态” | LeetTalk Daily...
“LeetTalk Daily”,每日科技前沿,由LeetTools AI精心筛选,为您带来最新鲜、最具洞察力的科技新闻。 Canvas作为一个独立的界面,通过与ChatGPT的结合来提升用户的协作能力和创作效率。尽管用户对其独立性与现有工具的整合存在不同…...

RiproV9.0主题wordpress主题免扩展可二开PJ版/WordPress博客主题Ripro全解密无后门版本
🔥🎉 全新RiPro9.0开源版发布 —— 探索无限可能🚀🌐 今天,我很高兴能与大家分享一个重磅资源——RiPro9.0开源版!这不是一个普通的版本,而是一个经过精心打磨、全面解密的力作。🔍…...

[LeetCode] 515. 在每个树行中找最大值
题目描述: 给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。 示例1: 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9]示例2: 输入: root [1,2,3] 输出: [1,3]提示: 二叉树的节点个数的范围是 [0,10…...
【分布式微服务云原生】《微服务架构大揭秘:流行框架与服务治理攻略》
标题:《微服务架构大揭秘:流行框架与服务治理攻略》 摘要:本文深入探讨了流行的微服务架构框架,包括 Spring Cloud、Docker Kubernetes、Dubbo、Service Mesh 和 Serverless 架构,详细介绍了它们的关键组件和服务治理…...

uniapp uni.uploadFile errMsg: “uploadFile:fail
uniapp 上传后一直显示加载中 1.检查前后端上传有无问题 2.检查失败信息 await uni.uploadFile({url,filePath,name,formData,header,timeout: 30000000, // 自定义上传超时时间fail: async function(err) {$util.hideAll()// 失败// err 返回 {errMsg: "uploadFile:fai…...
一个常见问题:TCP和UDP是否可以使用一个端口
TCP(传输控制协议)和UDP(用户数据报协议)做为两种被广泛使用的协议,它们在处理数据时采用不同的机制,那么有一个问题,在同一系统内,TCP和UDP的服务是否可以使用同一个端口呢…...
前端报错:‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序(node_modules下载不下来)
原因:Vue CLI 没有被正确安装,或者其安装路径没有被添加到你的系统环境变量中。 一、确认 Vue CLI 是否已安装: 打开命令行工具(例如 CMD、PowerShell、Terminal),输入以下命令来检查 Vue CLI 是否已安装…...

白日门【鬼服无限刀】win服务端+安卓客户端+教程+GM后台
演示系统:Windows Server 2012 -------------------------------------------------------------------------------------------------------------------------- 把服务端上传解压缩到服务器D盘根目录:D:\【解压完成后检查路径是否正确:D:\】 安装基础运行环境&…...
如何迅速的了解一个人
目录 社会经济背景 生活满意度 爱心和同情心 如果你想迅速地了解一个人,问他问题是最快捷的方法。不论你是相亲、工作、而试、看医生还是为孩子找个学校,事先设计好你想提出的问题,想好你究竟要搜罗对方哪一方面的信息这样做会实现许多目…...

Window和Linux远程调度kettle
在windows和linux分别安装kettle,我的是pdi-ce-8.2.0.0-342版本,在windows中配置好之后,直接放到虚拟机的目录下 在cmd窗口中到kettle根目录下执行 (carte ip 端口 ),出现如下提示即启动成功 在远程端…...
设定义结构变量
在C语言中,可以使用struct关键字来定义结构变量。结构变量是由多个不同类型的成员变量组成的数据类型,可以在一个变量中存储多个相关的数据。 定义结构变量的语法如下: struct 结构名 {数据类型 成员1;数据类型 成员2;... };例如࿰…...

SSD |(七)FTL详解(中)
文章目录 📚垃圾回收🐇垃圾回收原理🐇写放大🐇垃圾回收实现🐇垃圾回收时机 📚解除映射关系📚磨损均衡 📚垃圾回收 🐇垃圾回收原理 ✋设定一个迷你SSD空间: 假…...
Swift 协议:深入解析与高级应用
Swift 协议:深入解析与高级应用 Swift 协议是 Swift 编程语言中的一项核心特性,它提供了一种定义接口和实现多态的强大方式。本文将深入探讨 Swift 协议的概念、用法和高级应用,帮助读者更好地理解和运用这一特性。 什么是 Swift 协议&…...

API项目3:API签名认证
问题引入 我们为开发者提供了接口,却对调用者一无所知 假设我们的服务器只能允许 100 个人同时调用接口。如果有攻击者疯狂地请求这个接口,那是很危险的。一方面这可能会损害安全性,另一方面耗尽服务器性能,影响正常用户的使用。…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...