van Emde Boas树实现

发布时间:2026/11/4 21:20:25

van Emde Boas树实现 VanEmdeBoas树的详细介绍见算法导论第三版这里只给出实现C代码:#include iostream #include memory #include vector #include deque #include stack #include random #include ctime using namespace std; struct VanEmdeBoasTreeNode //vEB树节点定义 { enum NodeType { SUMMARY, CLUSTER } node_type; //节点类型 unsigned int global_size; //注意这里存储的是实际全域大小关于底数2的对数不是全域大小本身 unsigned long long* min nullptr; //节点最大值不存在为nullptr unsigned long long* max nullptr; //节点最小值,不存在为nullptr VanEmdeBoasTreeNode* summary nullptr; //当前节点的summary节点指针 vectorVanEmdeBoasTreeNode* cluster; //cluster子节点指针 VanEmdeBoasTreeNode(unsigned int g, NodeType node_type) :global_size(g), node_type(node_type) {} ~VanEmdeBoasTreeNode() { delete min; delete max; } }; unsigned long long low(VanEmdeBoasTreeNode* node, unsigned long long x) //调用这三个函数时总是假定node的全域大小大于等于2,即node不是叶节点,low,high,index函数的详细定义见算法导论,这里使用移位运算加快求值速度 { unsigned int g node-cluster[0]-global_size; unsigned long long full 0xffffffffffffffff; full full (64U - g); return x full; } unsigned long long high(VanEmdeBoasTreeNode* node, unsigned long long x) { unsigned int g node-cluster[0]-global_size; return x g; } unsigned long long index(VanEmdeBoasTreeNode* node, unsigned long long low, unsigned long long high) { unsigned int g node-cluster[0]-global_size; high high g; return high | low; } struct StackNode { VanEmdeBoasTreeNode* cur; unsigned long long high; StackNode(VanEmdeBoasTreeNode* c, unsigned long long h) :cur(c), high(h) {} }; class VanEmdeBoasTree { public: enum class StyleOfCreatTree { BFS, DFS }; //建树方式深度优先或广度优先 VanEmdeBoasTree(StyleOfCreatTree how_building_tree, unsigned int g); //g为全域大小为实际全域大小关于底数2的对数 shared_ptrunsigned long long min() { if (isEmpty()) return nullptr; return make_sharedunsigned long long(*root-min); } //返回最小值 shared_ptrunsigned long long max() { if (isEmpty()) return nullptr; return make_sharedunsigned long long(*root-max); } //返回最大值 bool remove(unsigned long long x) { if (beyondGlobalSize(x)) return false; return removeValue(root, x); } //删除值 bool insert(unsigned long long x) { if (beyondGlobalSize(x)) return false; return insertValue(root, x); } //插入值 bool contain(unsigned long long x) { if (beyondGlobalSize(x)) return false; return containValue(root, x); } //判断值是否存在 bool isEmpty() { return root-min nullptr; } //判断vEB树是否为空 shared_ptrunsigned long long pre(unsigned long long x) { if (beyondGlobalSize(x)) return nullptr; return findPrecessor(root, x); } //返回x前驱 shared_ptrunsigned long long suc(unsigned long long x) { if (beyondGlobalSize(x)) return nullptr; return findSuccessor(root, x); } //返回x后继 void printValueInTreeFromSmallToLarge(); //从小到大打印vEB树中所有值 void printValueInTreeFromLargeToSmall(); //从大到小打印vEB树中所有值 ~VanEmdeBoasTree(); //销毁vEB树 private: bool beyondGlobalSize(unsigned long long x); //判断x是否超出实际全域大小 bool removeValue(VanEmdeBoasTreeNode* root, unsigned long long x); bool insertValue(VanEmdeBoasTreeNode* root, unsigned long long x); bool containValue(VanEmdeBoasTreeNode* root, unsigned long long x); shared_ptrunsigned long long findPrecessor(VanEmdeBoasTreeNode* root, unsigned long long x); shared_ptrunsigned long long findSuccessor(VanEmdeBoasTreeNode* root, unsigned long long x); StyleOfCreatTree style_of_build_tree StyleOfCreatTree::DFS; //建树方式 VanEmdeBoasTreeNode* root nullptr; //vEB树根节点 }; void VanEmdeBoasTree::printValueInTreeFromLargeToSmall() { cout 从大到小打印树中值 endl; shared_ptrunsigned long long p max(); if (p nullptr) { cout NULL; cout endl; return; } while (p ! nullptr) { cout *p ; p pre(*p); } cout endl; } void VanEmdeBoasTree::printValueInTreeFromSmallToLarge() { cout 从小到大打印树中值 endl; shared_ptrunsigned long long p min(); if (p nullptr) { cout NULL; cout endl; return; } while (p ! nullptr) { cout *p ; p suc(*p); } cout endl; } bool VanEmdeBoasTree::beyondGlobalSize(unsigned long long x) { unsigned int g root-global_size; unsigned long long t 0xffffffffffffffff; t t (64U - g); if (0 x x t) { return false; } else { return true; } } bool VanEmdeBoasTree::containValue(VanEmdeBoasTreeNode* root, unsigned long long x) { VanEmdeBoasTreeNode* cur root; unsigned long long cur_value x; while (true) { if (cur-min nullptr) return false; if (cur_value *cur-min) return true; if (*cur-min *cur-max) return false; if (cur-summary nullptr) return true; if (cur_value *cur-min || cur_value *cur-max) return false; if (cur_value *cur-max) return true; VanEmdeBoasTreeNode* temp cur-cluster[high(cur, cur_value)]; //下降到下一层递归搜索 cur_value low(cur, cur_value); cur temp; } } bool VanEmdeBoasTree::insertValue(VanEmdeBoasTreeNode* root, unsigned long long x) //在以root为根的vEB树中插入x,true插入成功,false插入失败 { stackStackNode work_stack; VanEmdeBoasTreeNode* cur root; unsigned long long cur_value x; while (true) { if (cur-min nullptr) break; if (cur_value *cur-min) return false; if (*cur-min *cur-max) break; if (cur-summary nullptr) return false; if (cur_value *cur-min) //应当在当前节点插入比最小值更小的值,此时用当前值更新最小值并把原先的最小值调整为要插入值 { unsigned long long temp *cur-min; *cur-min cur_value; cur_value temp; } work_stack.push(StackNode(cur, high(cur, cur_value))); //继续向下一层寻找插入位置 VanEmdeBoasTreeNode* temp cur-cluster[high(cur, cur_value)]; cur_value low(cur, cur_value); cur temp; } if (cur-min nullptr) //在找到的插入位置插入 { cur-min new unsigned long long(cur_value); cur-max new unsigned long long(cur_value); } else if (*cur-min *cur-max) { if (cur_value *cur-min) { *cur-min cur_value; if (cur-summary ! nullptr) { unsigned long long high_pos high(cur, *cur-max); unsigned long long value low(cur, *cur-max); cur-cluster[high_pos]-max new unsigned long long(value); cur-cluster[high_pos]-min new unsigned long long(value); insertValue(cur-summary, high_pos); } } else { *cur-max cur_value; if (cur-summary ! nullptr) { unsigned long long high_pos high(cur, cur_value); unsigned long long value low(cur, cur_value); cur-cluster[high_pos]-max new unsigned long long(value); cur-cluster[high_pos]-min new unsigned long long(value); insertValue(cur-summary, high_pos); } } } while (work_stack.empty() false) //自底向上调整summary和max值 { cur work_stack.top().cur; unsigned long long high work_stack.top().high; work_stack.pop(); cur_value index(cur, cur_value, high); if (*cur-cluster[high]-min *cur-cluster[high]-max) insertValue(cur-summary, high); if (cur_value *cur-max) //如果当前层节点max值没有因插入而改变则无需继续向上调整直接退出 return true; *cur-max cur_value; } return true; } bool VanEmdeBoasTree::removeValue(VanEmdeBoasTreeNode* root, unsigned long long x) //在以root为根的vEB树中删除x,成功返回true,失败返回false { stackStackNode work_stack; VanEmdeBoasTreeNode* cur root; unsigned long long cur_value x; while (true) //从根节点向下搜索找到叶节点或只含有单一值的分支节点且x在其中即退出否则返回false { if (cur-summary nullptr) { if (cur-min nullptr) return false; if (*cur-min *cur-max) { if (cur_value *cur-min) break; return false; } break; } else { if (cur-min nullptr) return false; if (cur_value *cur-min) { if (*cur-min *cur-max) break; unsigned long long t *cur-summary-min; //这里相当关键如果在一个包含两个或两个以上值的分支节点找到x且x恰为分支节点最小值 cur_value *cur-cluster[t]-min; //则应用x在该节点的后继替换最小值,同时更改当前搜索值为替换后的新值,然后下降到x在当前节点的后继所在的当前节点的子vEB树继续搜索 *cur-min index(cur, cur_value, t); work_stack.push(StackNode(cur, t)); cur cur-cluster[t]; continue; } if (*cur-min *cur-max) return false; if (cur_value *cur-min || cur_value *cur-max) return false; work_stack.push(StackNode(cur, high(cur, cur_value))); VanEmdeBoasTreeNode* temp cur-cluster[high(cur, cur_value)]; cur_value low(cur, cur_value); cur temp; } } unsigned long long high 0; bool first_cycle true; while (true) { if (first_cycle) { if (cur-summary nullptr) //在叶节点删除 { if (*cur-min *cur-max) { cur-min nullptr; cur-max nullptr; } else { if (cur_value *cur-min) *cur-min *cur-max; else *cur-max *cur-min; } } else { cur-min nullptr; //在只含有单一值的分支节点删除 cur-max nullptr; } first_cycle false; } else { cur_value index(cur, cur_value, high); if (cur_value *cur-min) //回溯到最小值被其后继替换的最后一个节点 { if (cur_value *cur-max || cur-cluster[high]-min nullptr) removeValue(cur-summary, high); return true; //更新该节点的summary后当前节点最大值和删除前相同保持不变并且当前节点对应vEB树非空故无需向根节点调整直接返回 } if (cur_value ! *cur-max) { //这种情况说明从当前节点cluster数组high元素对应子树删除cur_value后,当前节点的原最大值没有被删除且现在的最大值就是原最大值所以无需更新最大值,当然high元素对应子树被删除值后可能为空所以需要在summary中递归删除 if (cur-cluster[high]-min nullptr) removeValue(cur-summary, high); return true; //上述操作结束后注意到当前节点删除cur_value后不为空故直接返回无需向根节点调整 } if (cur-cluster[high]-max ! nullptr) //回溯到此时的分支节点之前的搜索过程中一定没有用某节点的最小值的后继替换最小值 *cur-max index(cur, *cur-cluster[high]-max, high); //此外一定从搜索结束时找到的叶节点或只含有单一值的分支节点中实际删除给定值后回溯到了当前分支节点,判断条件cur_value *cur-max通过后一定 else //从当前节点的cluster数组的high元素对应的vEB树中删除了该vEB树的最大值cur_value,且high元素之后的元素对应的vEB子树为空,这样必须用 { shared_ptrunsigned long long temp findPrecessor(cur-summary, high); //当前节点的被删除的最大值的前驱更新当前节点最大值 if (temp ! nullptr) *cur-max index(cur, *cur-cluster[*temp]-max, *temp); else *cur-max *cur-min; removeValue(cur-summary, high); } } if (work_stack.empty() true) return true; cur work_stack.top().cur; high work_stack.top().high; work_stack.pop(); } } shared_ptrunsigned long long VanEmdeBoasTree::findSuccessor(VanEmdeBoasTreeNode* root, unsigned long long x) //在以root为根的vEB树中寻找x的后继,失败返回nullptr,否则返回后继值 { stackStackNode work_stack; VanEmdeBoasTreeNode* cur root; unsigned long long cur_value x; while (true) { if (cur-min nullptr || cur_value *cur-max) { if (work_stack.empty()) return nullptr; cur work_stack.top().cur; shared_ptrunsigned long long temp findSuccessor(cur-summary, work_stack.top().high); cur_value index(cur, *cur-cluster[*temp]-min, *temp); work_stack.pop(); } else { if (cur-summary nullptr) { cur_value *cur-max; } else if (cur_value *cur-min) { cur_value *cur-min; } else if (cur_value *cur-min) { unsigned long long h_min *cur-summary-min; cur_value index(cur, *cur-cluster[h_min]-min, h_min); } else { work_stack.push(StackNode(cur, high(cur, cur_value))); VanEmdeBoasTreeNode* temp cur-cluster[high(cur, cur_value)]; cur_value low(cur, cur_value); cur temp; continue; } } break;//令查找到x的叶节点或x等于其最小值的分支节点为循环开始时的当前节点,如果在当前节点能够找到x的后继则逐级向上返回到根节点并在根结单处最终还原出x的后继 //如果当前节点无法找到x的后继则回溯至父节点在父节点的summary中查找当前节点对应vEB树在父节点cluster中的对应下标的后继如果找到该后继在父节点cluster中对应子树的最小值即 } //为x后继然后逐级向上返回在根节点还原后继否则回溯至祖先节点继续利用祖先节点的summary查找x后继处理过程和上述相同如果最终在根节点处仍未发现x后继则查找失败返回nullptr unsigned long long high; while (!work_stack.empty()) { cur work_stack.top().cur; high work_stack.top().high; work_stack.pop(); cur_value index(cur, cur_value, high); } return make_sharedunsigned long long(cur_value); } shared_ptrunsigned long long VanEmdeBoasTree::findPrecessor(VanEmdeBoasTreeNode* root, unsigned long long x) //在以root为根的vEB树中寻找x的前驱,失败返回nullptr,否则返回前驱值过程和查找后继对称 { stackStackNode work_stack; VanEmdeBoasTreeNode* cur root; unsigned long long cur_value x; while (true) { if (cur-min nullptr || cur_value *cur-min) { if (work_stack.empty()) return nullptr; cur work_stack.top().cur; shared_ptrunsigned long long temp findPrecessor(cur-summary, work_stack.top().high); if (temp nullptr) { cur_value *cur-min; } else { cur_value index(cur, *cur-cluster[*temp]-max, *temp); } work_stack.pop(); } else { if (cur-summary nullptr) { cur_value *cur-min; } else if (cur_value *cur-max) { cur_value *cur-max; } else { work_stack.push(StackNode(cur, high(cur, cur_value))); VanEmdeBoasTreeNode* temp cur-cluster[high(cur, cur_value)]; cur_value low(cur, cur_value); cur temp; continue; } } break; } unsigned long long high; while (!work_stack.empty()) { cur work_stack.top().cur; high work_stack.top().high; work_stack.pop(); cur_value index(cur, cur_value, high); } return make_sharedunsigned long long(cur_value); } VanEmdeBoasTree::~VanEmdeBoasTree() { stackVanEmdeBoasTreeNode* work_stack; //深度优先销毁vEB树 bool trace_back_flag true; work_stack.push(root); while (work_stack.empty() false) { if (trace_back_flag) { if (work_stack.top()-global_size 1) { work_stack.push(work_stack.top()-summary); } else { delete work_stack.top(); work_stack.pop(); trace_back_flag false; } } else { if (work_stack.top()-cluster.empty() false) { VanEmdeBoasTreeNode* temp work_stack.top(); work_stack.push(work_stack.top()-cluster.back()); temp-cluster.pop_back(); trace_back_flag true; } else { delete work_stack.top(); work_stack.pop(); } } } } VanEmdeBoasTree::VanEmdeBoasTree(StyleOfCreatTree how_building_tree, unsigned int g) { if (g 0 || g 64) { cout ERROR:全域大小超出允许范围 endl; exit(-1); } style_of_build_tree how_building_tree; root new VanEmdeBoasTreeNode(g, VanEmdeBoasTreeNode::NodeType::CLUSTER); //BFS方式构建vEB树 if (style_of_build_tree StyleOfCreatTree::BFS) { dequeVanEmdeBoasTreeNode* work_queue; work_queue.push_back(root); while (work_queue.empty() false) { VanEmdeBoasTreeNode* cur work_queue.front(); work_queue.pop_front(); if (cur-global_size 1) { unsigned int k cur-global_size 1; unsigned long long global 0; if ((cur-global_size 1) 0) { cur-summary new VanEmdeBoasTreeNode(k, VanEmdeBoasTreeNode::NodeType::SUMMARY); global 1U k; } else { cur-summary new VanEmdeBoasTreeNode(k 1, VanEmdeBoasTreeNode::NodeType::SUMMARY); global 1U (k 1); } work_queue.push_back(cur-summary); for (size_t i 1; i global; i) { cur-cluster.push_back(new VanEmdeBoasTreeNode(k, VanEmdeBoasTreeNode::NodeType::CLUSTER)); work_queue.push_back(cur-cluster.back()); } } } } else { struct StackNode { VanEmdeBoasTreeNode* cur; unsigned int down_sqrt; unsigned long long cluster_size; StackNode(VanEmdeBoasTreeNode* c) :cur(c) {} }; stackStackNode work_stack; bool trace_back_flag true; work_stack.push(StackNode(root)); while (work_stack.empty() false) //DFS方式构建vEB树 { if (trace_back_flag) { if (work_stack.top().cur-global_size 1) { unsigned int k work_stack.top().cur-global_size 1; size_t global 0; if ((work_stack.top().cur-global_size 1) 0) { work_stack.top().cur-summary new VanEmdeBoasTreeNode(k, VanEmdeBoasTreeNode::NodeType::SUMMARY); work_stack.top().cluster_size 1U k; } else { work_stack.top().cur-summary new VanEmdeBoasTreeNode(k 1, VanEmdeBoasTreeNode::NodeType::SUMMARY); work_stack.top().cluster_size 1U (k 1); } work_stack.top().down_sqrt k; work_stack.push(StackNode(work_stack.top().cur-summary)); } else { work_stack.pop(); trace_back_flag false; } } else { if (work_stack.top().cur-cluster.size() work_stack.top().cluster_size) { work_stack.top().cur-cluster.push_back(new VanEmdeBoasTreeNode(work_stack.top().down_sqrt, VanEmdeBoasTreeNode::NodeType::CLUSTER)); work_stack.push(work_stack.top().cur-cluster.back()); trace_back_flag true; } else { work_stack.pop(); } } } } } int main() { unsigned int global 4; VanEmdeBoasTree obj(VanEmdeBoasTree::StyleOfCreatTree::DFS, global); vectorunsigned long long input; unsigned long long j 1ULL global; for (unsigned long long i 1; i j; i) { input.push_back(i - 1); } shuffle(input.begin(), input.end(), default_random_engine(time(nullptr))); for (const unsigned long long i : input) { cout 插入 i endl; if (obj.insert(i)) { cout 插入成功 endl; obj.printValueInTreeFromSmallToLarge(); obj.printValueInTreeFromLargeToSmall(); } else { cout 插入失败 endl; } } obj.printValueInTreeFromLargeToSmall(); obj.printValueInTreeFromSmallToLarge(); for (const unsigned long long i : input) { cout 删除 i endl; if (obj.remove(i)) { cout 删除成功 endl; obj.printValueInTreeFromSmallToLarge(); obj.printValueInTreeFromLargeToSmall(); } else { cout 删除失败 endl; } } if (obj.isEmpty()) { cout 树空 endl; } return 0; }
延伸阅读

更多相关文章

2026/11/3 22:59:40

成本管理培训课程这样讲:从成本分类到降本增效的落地指南

简介:本课程PPT聚焦MFG/PRO系统中的成本管理,适合制造型企业的财务、成本核算及ERP运维人员,帮助理解成本构成,并掌握标准成本法、移动平均法等落地计算方式。课件重点讲解总帐成本集与当前成本集的适用场景,覆盖物料成…

2026/11/1 15:26:08

Fluent官方教程实战:网格划分、求解设置与UDF疑难全解析

简介:《Ansys Fluent Tutorial Guide 2022 R1》是Ansys官方于2022年1月发布的Fluent教程文档,面向需要开展流体力学、传热、燃烧等仿真分析的工程师和科研人员,也适合CFD初学者系统入门。正文从Ansys Fluent用户界面与项目管理流程开始&#…

2026/11/2 21:14:58

Ansys Fluent教程怎么啃?三遍法+五个高频坑实战指南

简介:《Ansys Fluent Tutorial Guide 2022 R1》是Ansys官方发布的Fluent教程文档,面向CFD初学者、高校学生与需要系统提升的工程技术人员,用于学习流体、传热、燃烧等场景的仿真分析方法。资源为单个PDF文件,共1个文档&#xff0c…

2026/11/5 16:26:13

Rust原来很简单二:所有权系统

Part 2 核心篇 —— 所有权系统 本篇覆盖 第 6 ~ 10 章:所有权、借用与引用、生命周期、字符串与切片、内存模型。 ⚠️ 这是全书最重要的一篇。 把它吃透,Rust 从此“很简单”;跳过它,你会处处碰壁。请慢下来,动手敲每一段代码。 第 6 章 所有权:Rust 的第一性原理 6…

2026/11/5 15:00:49

基于Hadoop+Spark的民宿智能推荐系统设计与实现

1. 项目概述:大数据时代的民宿智能推荐这个毕业设计项目融合了当前大数据领域最主流的技术栈,构建了一个完整的民宿推荐系统解决方案。作为一名长期从事大数据系统开发的工程师,我认为这个选题非常贴合实际应用场景——随着旅游业的复苏和共享…

2026/11/5 14:10:30

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配RS485,解决远距离温度监控难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 13:55:19

GD32E10x官方例程入门:从GPIO点灯到串口调试

简介:这份GD32E10x系列官方例程面向嵌入式硬件与单片机开发者,基于ARM Cortex-M3内核,汇集兆易创新GD32E10x的示例代码,适合工业控制、消费电子、通信设备等场景的学习、验证与二次开发。压缩包共935个文件,约11.16MB&…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑