网站开发使用的技术青岛硅谷网站建设公司

diannao/2026/1/27 7:04:40/文章来源:
网站开发使用的技术,青岛硅谷网站建设公司,天津搜索引擎优化公司,河北省住房和建设厅网站2013-01-20 std::set/std::map #xff08;以下用 std::map 代表#xff09; 是常用的关联式容器#xff0c;也是 ADT#xff08;抽象数据类型#xff09;。也就是说#xff0c;其接口#xff08;不是 OO 意义下的 interface#xff09;不仅规定了操作的功能#xff… 2013-01-20 std::set/std::map 以下用 std::map 代表 是常用的关联式容器也是 ADT抽象数据类型。也就是说其接口不是 OO 意义下的 interface不仅规定了操作的功能还规定了操作的复杂度代价/cost。例如 set::insert(iterator first, iterator last) 在通常情况下是 O(N log N)N 是区间的长度但是如果 [first, last) 已经排好序在 key_compare 意义下那么复杂度将会是 O(N)。 尽管 C 标准没有强求 std::map 底层的数据结构但是根据其规定的时间复杂度现在所有的 STL 实现都采用平衡二叉树来实现 std::map而且用的都是红黑树。《算法导论第 2 版》第 12、13 章介绍了二叉搜索树和红黑树的原理、性质、伪代码侯捷先生的《STL 源码剖析》第 5 章详细剖析了 SGI STL 的对应实现。本文对 STL 中红黑树rb_tree的实现问了几个稍微深入一点的问题并给出了我的理解。本文剖析的是 G 4.7 自带的这一份 STL 实现及其特定行为与《STL 源码剖析》的版本略有区别。为了便于阅读文中的变量名和 class 名都略有改写例如 _Rb_tree_node 改为 rb_tree_node。本文不谈红黑树的平衡算法在我看来这属于“旁枝末节”见陈硕《谈一谈网络编程学习经验》对此的定义因此也就不关心节点的具体颜色了。 数据结构回顾 先回顾一下数据结构教材上讲的二叉搜索树的结构节点Node一般有三个数据成员left、right、data树Tree有一到两个成员root 和 node_count。 用 Python 表示 class Node:def __init__(self, data):self.left Noneself.right Noneself.data dataclass Tree:def __init__(self):self.root Noneself.node_count 0而实际上 STL rb_tree 的结构比这个要略微复杂一些我整理的代码见 https://gist.github.com/4574621#file-tree-structure-cc 。 节点 Node 有 5 个成员除了 left、right、data还有 color 和 parent。 C实现位于bits/stl_tree.h /*** Non-template code**/enum rb_tree_color { kRed, kBlack };struct rb_tree_node_base {rb_tree_color color_;rb_tree_node_base* parent_;rb_tree_node_base* left_;rb_tree_node_base* right_; };/*** template code**/templatetypename Value struct rb_tree_node : public rb_tree_node_base {Value value_field_; };见下图。 color 的存在很好理解红黑树每个节点非红即黑需要保存其颜色颜色只需要 1-bit 数据一种节省内存的优化措施是把颜色嵌入到某个指针的最高位或最低位Linux 内核里的 rbtree 是嵌入到 parent 的最低位parent 的存在使得非递归遍历成为可能后面还将再谈到这一点。 树 Tree 有更多的成员它包含一个完整的 rb_tree_node_basecolor/parent/left/right还有 node_count 和 key_compare 这两个额外的成员。 这里省略了一些默认模板参数如 key_compare 和 allocator。 templatetypename Key, typename Value // key_compare and allocator class rb_tree {public:typedef std::lessKey key_compare;typedef rb_tree_iteratorValue iterator;protected:struct rb_tree_impl // : public node_allocator{key_compare key_compare_;rb_tree_node_base header_;size_t node_count_;};rb_tree_impl impl_; };templatetypename Key, typename T // key_compare and allocator class map {public:typedef std::pairconst Key, T value_type;private:typedef rb_treeKey, value_type rep_type;rep_type tree_; };见下图。这是一颗空树其中阴影部分是 padding bytes因为 key_compare 通常是 empty class。allocator 在哪里 rb_tree 中的 header 不是 rb_tree_node 类型而是 rb_tree_node_base因此 rb_tree 的 size 是 6 * sizeof(void*)与模板类型参数无关。在 32-bit 上是 24 字节在 64-bit 上是 48 字节很容易用代码验证这一点。另外容易验证 std::set 和 std::map 的 sizeof() 是一样的。 注意 rb_tree 中的 header 不是 root 节点其 left 和 right 成员也不是指向左右子节点而是指向最左边节点left_most和最右边节点right_most后面将会介绍原因是为了满足时间复杂度。header.parent 指向 root 节点root.parent 指向 headerheader 固定是红色root 固定是黑色。在插入一个节点后数据结构如下图。 继续插入两个节点假设分别位于 root 的左右两侧那么得到的数据结构如下图所示parent 指针没有全画出来因为其指向很明显注意 header.left 指向最左侧节点header.right 指向最右侧节点。 迭代器 rb_tree 的 iterator 的数据结构很简单只包含一个 rb_tree_node_base 指针但是其/--操作却不见得简单具体实现函数不在头文件中而在 libstdc 库文件中。 // defined in library, not in header rb_tree_node_base* rb_tree_increment(rb_tree_node_base* node); // others: decrement, reblance, etc.templatetypename Value struct rb_tree_node : public rb_tree_node_base {Value value_field_; };templatetypename Value struct rb_tree_iterator {Value operator*() const{return static_castrb_tree_nodeValue*(node_)-value_field_;}rb_tree_iterator operator(){node_ rb_tree_increment(node_);return *this;}rb_tree_node_base* node_; };end() 始终指向 header 节点begin() 指向第一个节点如果有的话。因此对于空树begin() 和 end() 都指向 header 节点。对于 1 个元素的树迭代器的指向如下。 对于前面 3 个元素的树迭代器的指向如下。 思考对 std::setint::end() 做 dereference 会得到什么按标准这属于undefined behaviour不过但试无妨。 rb_tree 的 iterator 的递增递减操作并不简单。考虑下面这棵树假设迭代器 iter 指向绿色节点3那么 iter 之后它应该指向灰色节点 4再 iter 之后它应该指向黄色节点 5这两步递增都各走过了 2 个指针。 对于一颗更大的树下图假设迭代器 iter 指向绿色节点7那么 iter 之后它应该指向灰色节点 8再 iter 之后它应该指向黄色节点 9这两步递增都各走过了 3 个指针。 由此可见rb_tree 的迭代器的每次递增或递减不能保证是常数时间最坏情况下可能是对数时间即与树的深度成正比。那么用 begin()/end() 迭代遍历一棵树还是不是 O(N)换言之迭代器的递增或递减是否是分摊后的amortized常数时间 另外注意到当 iter 指向最右边节点的时候7 或 15iter 应该指向 header 节点即 end()这一步是 O(log N)。同理对 end() 做--复杂度也是 O(log N)后面会用到这一事实。 rb_tree 迭代器的递增递减操作的实现也不是那么一目了然。要想从头到尾遍历一颗二叉树前序、中序、后序教材上给出的办法是用递归或者用 stack 模拟递归性质一样比如https://gist.github.com/4574621#file-tree-traversal-py  Python: def printTree(node):if node:printTree(node.left)print node.dataprintTree(node.right)如果考虑通用性可以把函数作为参数进去然后通过回调的方式来访问每个节点代码如下。Java XML 的 SAX 解析方式也是这样。 Python: def visit(node, func):if node:printTree(node.left)func(node.data)printTree(node.right)要想使用更方便在调用方用 for 循环就能从头到尾遍历 tree那似乎就不那么容易了。在 Python 这种支持 coroutine 的语言中可以用 yield 关键字配合递归来实现代码如下与前面的实现没有多大区别。 在 Python 3.3 中还可以用 yield from这里用 Python 2.x 的写法。 def travel(root):if root.left:for x in travel(root.left):yield xyield root.dataif root.right:for y in travel(root.right):yield y调用方for y in travel(root):print y但是在 C 中要想做到最后这种 StAX 的遍历方式那么迭代器的实现就麻烦多了见《STL 源码剖析》第 5.2.4 节的详细分析。这也是 node 中 parent 指针存在的原因因为递增操作时如果当前节点没有右子节点就需要先回到父节点再接着找。 空间复杂度 每个 rb_tree_node 直接包含了 value_type其大小是 4 * sizeof(void*) sizeof(value_type)。在实际分配内存的时候还要 round up 到 allocator/malloc 的对齐字节数通常 32-bit 是 8 字节64-bit 是 16 字节。因此 setint每个节点是 24 字节或 48 字节100 万个元素的 setint 在 x86-64 上将占用 48M 内存。说明用 setint 来排序整数是很不明智的行为无论从时间上还是空间上。 考虑 malloc 对齐的影响setint64_t 和 setint32_t 占用相同的空间setint 和 mapint, int 占用相同的空间无论 32-bit 还是 64-bit 均如此。 几个为什么 对于 rb_tree 的数据结构我们有几个问题 1. 为什么 rb_tree 没有包含 allocator 成员 2. 为什么 iterator 可以 pass-by-value 3. 为什么 header 要有 left 成员并指向 left most 节点 4. 为什么 header 要有 right 成员并指向 right most 节点 5. 为什么 header 要有 color 成员并且固定是红色 6. 为什么要分为 rb_tree_node 和 rb_tree_node_base 两层结构引入 node 基类的目的是什么 7. 为什么 iterator 的递增递减是分摊amortized常数时间 8. 为什么 muduo 网络库的 Poller 要用 std::mapint, Channel* 来管理文件描述符 我认为在面试的时候能把上面前 7 个问题答得头头是道足以说明对 STL 的 map/set 掌握得很好。下面一一解答。 为什么 rb_tree 没有包含 allocator 成员 因为默认的 allocator 是 empty class 没有数据成员也没有虚表指针vptr为了节约 rb_tree 对象的大小STL 在实现中用了 empty base class optimization。具体做法是 std::map 以 rb_tree 为成员rb_tree 以 rb_tree_impl 为成员而 rb_tree_impl 继承自 allocator这样如果 allocator 是 empty class那么 rb_tree_impl 的大小就跟没有基类时一样。其他 STL 容器也使用了相同的优化措施因此 std::vector 对象是 3 个 wordsstd::list 对象是 2 个 words。boost 的 compressed_pair 也使用了相同的优化。 我认为对于默认的 key_compare应该也可以实施同样的优化这样每个 rb_tree 只需要 5 个 words而不是 6 个。 为什么 iterator 可以 pass-by-value 读过《Effective C》的想必记得其中有个条款是 Prefer pass-by-reference-to-const to pass-by-value即对象尽量以 const reference 方式传参。这个条款同时指出对于内置类型、STL 迭代器和 STL 仿函数pass-by-value 也是可以的一般没有性能损失。 在 x86-64 上对于 rb_tree iterator 这种只有一个 pointer member 且没有自定义 copy-ctor 的 classpass-by-value 是可以通过寄存器进行的例如函数的头 4 个参数by-value 返回对象算一个参数就像传递普通 int 和指针那样。因此实际上可能比 pass-by-const-reference 略快因为callee 减少了一次 deference。 同样的道理muduo 中的 Date class 和 Timestamp class 也是明确设计来 pass-by-value 的它们都只有一个 int/long 成员按值拷贝不比 pass reference 慢。如果不分青红皂白一律对 object 使用 pass-by-const-reference固然算不上什么错误不免稍微显得知其然不知其所以然罢了。 为什么 header 要有 left 成员并指向 left most 节点 原因很简单让 begin() 函数是 O(1)。假如 header 中只有 parent 没有 leftbegin() 将会是 O(log N)因为要从 root 出发走 log N 步才能到达 left most。现在 begin() 只需要用 header.left 构造 iterator 并返回即可。 为什么 header 要有 right 成员并指向 right most 节点 这个问题不是那么显而易见。end() 是 O(1)因为直接用 header 的地址构造 iterator 即可不必使用 right most 节点。在源码中有这么一段注释 bits/stl_tree.h// Red-black tree class, designed for use in implementing STL// associative containers (set, multiset, map, and multimap). The// insertion and deletion algorithms are based on those in Cormen,// Leiserson, and Rivest, Introduction to Algorithms (MIT Press,// 1990), except that//// (1) the header cell is maintained with links not only to the root// but also to the leftmost node of the tree, to enable constant// time begin(), and to the rightmost node of the tree, to enable// linear time performance when used with the generic set algorithms// (set_union, etc.)//// (2) when a node being deleted has two children its successor node// is relinked into its place, rather than copied, so that the only// iterators invalidated are those referring to the deleted node.这句话的意思是说如果按大小顺序插入元素那么将会是线性时间而非 O(N log N)。即下面这段代码的运行时间与 N 成正比 // 在 end() 按大小顺序插入元素std::setint s;const int N 1000 * 1000for (int i 0; i N; i)s.insert(s.end(), i);在 rb_tree 的实现中insert(value) 一个元素通常的复杂度是 O(log N)。不过insert(hint, value) 除了可以直接传 value_type还可以再传一个 iterator 作为 hint如果实际的插入点恰好位于 hint 左右那么分摊后的复杂度是 O(1)。对于这里的情况既然每次都在 end() 插入而且插入的元素又都比 *(end()-1) 大那么 insert() 是 O(1)。在具体实现中如果 hint 等于 end()而且 value 比 right most 元素大那么直接在 right most 的右子节点插入新元素即可。这里 header.right 的意义在于让我们能在常数时间取到 right most 节点的元素从而保证 insert() 的复杂度而不需要从 root 出发走 log N 步到达 right most。具体的运行时间测试见 https://gist.github.com/4574621#file-tree-bench-cc 测试结果如下纵坐标是每个元素的耗时微秒其中最上面的红线是普通 insert(value)下面的蓝线和黑线是 insert(end(), value)确实可以大致看出 O(log N) 和 O(1) 关系。具体的证明见《算法导论第 2 版》第 17 章中的思考题 17-4。 但是根据测试结果前面引用的那段注释其实是错的std::inserter() 与 set_union() 配合并不能实现 O(N) 复杂度。原因是 std::inserter_iterator 会在每次插入之后做一次 iter而这时 iter 正好指向 right most 节点其操作是 O(log N) 复杂度前面提到过 end() 的递减是 O(log N)这里反过来也是一样。于是把整个算法拖慢到了 O(N log N)。要想 set_union() 是线性复杂度我们需要自己写 inserter见上面代码中的 end_inserter 和 at_inserter此处不再赘言。 为什么 header 要有 color 成员并且固定是红色 这是一个实现技巧对 iterator 做递减时如果此刻 iterator 指向 end()那么应该走到 right most 节点。既然 iterator 只有一个数据成员要想判断当前是否指向 end()就只好判断 (node_-color_ kRed node_-parent_-parent_ node_) 了。 为什么要分为 rb_tree_node 和 rb_tree_node_base 两层结构引入 node 基类的目的是什么 这是为了把迭代器的递增递减、树的重新平衡等复杂函数从头文件移到库文件中减少模板引起的代码膨胀setint 和 setstring 可以共享这些的 rb_tree 基础函数也稍微加快编译速度。引入 rb_tree_node_base 基类之后这些操作就可以以基类指针与模板参数类型无关为参数因此函数定义不必放在在头文件中。这也是我们在头文件里看不到 iterator 的 /-- 的具体实现的原因它们位于 libstdc 的库文件源码中。注意这里的基类不是为了 OOP而纯粹是一种实现技巧。 为什么 iterator 的递增递减是分摊amortized常数时间 严格的证明需要用到分摊分析amortized analysis一来我不会二来写出来也没多少人看这里我用一点归纳的办法来说明这一点。考虑一种特殊情况对前面图中的满二叉树perfect binary tree从头到尾遍历计算迭代器一共走过多少步即 follow 多少次指针然后除以节点数 N就能得到平均每次递增需要走多少步。既然红黑树是平衡的那么这个数字跟实际的步数也相差不远。 对于深度为 1 的满二叉树有 1 个元素从 begin() 到 end() 需要走 1 步即从 root 到 header。 对于深度为 2 的满二叉树有 3 个元素从 begin() 到 end() 需要走 4 步即 1-2-3-header其中从 3 到 header 是两步 对于深度为 3 的满二叉树有 7 个元素从 begin() 到 end() 需要走 11 步即先遍历左子树4 步、走 2 步到达右子树的最左节点遍历右子树4 步最后走 1 步到达 end()4 2 4 1 11。 对于深度为 4 的满二叉树有 15 个元素从 begin() 到 end() 需要走 26 步。即先遍历左子树11 步、走 3 步到达右子树的最左节点遍历右子树11 步最后走 1 步到达 end()11 3 11 1 26。 后面的几个数字依次是 57、120、247 对于深度为 n 的满二叉树有 2^n - 1 个元素从 begin() 到 end() 需要走 f(n) 步。那么 f(n) 2*f(n-1) n。 然后用递推关系求出 f(n) sum(i * 2 ^ (n-i)) 2^(n1) - n - 2这个等式可以用归纳法证明。即对于深度为 n 的满二叉树从头到尾遍历的步数小于 2^(n1) - 2而元素个数是 2^n - 1二者一除得到平均每个元素需要 2 步。因此可以说 rb_tree 的迭代器的递增递减是分摊后的常数时间。 似乎还有更简单的证明方法在从头到尾遍历的过程中每条边edge最多来回各走一遍一棵树有 N 个节点那么有 N-1 条边最多走 2*(N-1)1 步也就是说平均每个节点需要 2 步跟上面的结果相同。 说一点题外话。 为什么 muduo 网络库的 Poller 要用 std::mapint, Channel* 来管理文件描述符 muduo 在正常使用的时候会用 EPollPoller是对 epoll(4) 的简单封装其中用 std::mapint, Channel* channels_ 来保存 fd 到 Channel 对象的映射。我这里没有用数组而是用 std::map原因有几点 epoll_ctl() 是 O(lg N)因为内核中用红黑树来管理 fd。因此用户态用数组管理 fd 并不能降低时间复杂度反而有可能增加内存使用用 hash 倒是不错。不过考虑系统调用开销map vs. vector 的实际速度差别不明显。题外话总是遇到有人说 epoll 是 O(1) 云云其实 epoll_wait() 是 O(N)N 是活动fd的数目。poll 和 select 也都是 O(N)不过 N 的意义不同。仔细算下来恐怕只有 epoll_create() 是 O(1) 的。也有人想把 epoll 改为数组但是被否决了因为这是开历史倒车https://lkml.org/lkml/2008/1/8/205 。channels_ 只在 Channel 创建和销毁的时候才会被访问其他时候修改关注的读写事件都是位于 assert() 中用于 Debug 模式断言。而 Channel 的创建和销毁本身就伴随着 socket 的创建和销毁涉及系统调用channels_ 操作所占的比重极小。因此优化 channels_ 属于优化 nop是无意义的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/87699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大唐工作室 网站制作怎样建网站教程

下载文件,得到一个gif 打开,发现真的闪的好快啊 gif分解网站:https://tu.sioe.cn/gj/fenjie/ GIF动态图片分解 逐个截屏下来 再逐个通过CQR.exe扫描,得到 SYC{F1aSh_so_f4sT}

影楼网站设计网站投资设计

Transformer架构自从2017年被提出以来,已经在自然语言处理(NLP)和其他领域成为了一种革命性的模型结构。它不仅在各种NLP任务中取得了突破性的表现,也被扩展应用于图像处理、音频处理等领域。理解Transformer架构及其顶层应用的基…

阿里巴巴网站建设初衷网站技术部门架构

PHP浮点比较大小的方法本文实例讲述了PHP浮点比较大小的方法。分享给大家供大家参考,具体如下:/*** 浮点数一般是不能用来比较大小的,但是我们可以用一种变通的的方式* 用var_dump输出浮点是看不出效果的,可以用serialize查看* 1.round 2.浮点…

做鲜花的网站有哪些咸阳北京网站建设

Analysis:文本分析是把全文本转换一系列单词的过程,也叫分词。Analysis是通过Analyzer(分词器)来实现的。 1.Analyzer组成 注意:在ES中默认使用标准分词器:StandardAnalyzer。特点是:中文是单字分词,英文是…

优秀企业网站欣赏店名设计网络直播平台搭建

这段代码非常令人困惑.流程不合逻辑,异常处理很糟糕.像if(p! path)和if(cookys! cookies)之类的对象引用比较没有任何意义.要比较对象的内容,您需要使用equals()方法.到目前为止,我知道您希望在同一个域上的一堆后续Jsoup请求中维护cookie.在这种情况下,…

做路线图的网站商城首页设计

假设我们想控制线程如何被分配到处理器核心,或者选择我们想分配数据的位置,那么numactl命令就适合此类任务。在这篇文章中,我们讨论了如何使用numactl命令执行此类操作。 目录: 介绍语法命令总结参考文献 简介 现代处理器采用…

中山网站建设哪家便宜公司做网站需要注意些什么

一.定位 1.static 默认属性。块级元素→矩形框,行级元素→行框 2.fixed 类似于absolute,但包含块是视窗本身 3.relative 原本所占的空间仍保留 4.absolute 生成一个块级框,变成块级元素。float也是 二.层级关系 z-index

网页和网站区别陵园网站建设价格

PHP个人发卡网源码,支持MA支付对接,扫码自动发货。源码介绍个人发卡网源码,支持码支付对接,扫码自动发货.自适应网页,可为商品设置优惠套餐,后台管理功能丰富。前台发卡页面有点粗糙,已开源的可…

分销系统搭建seo优化几个关键词

转载于:https://blog.51cto.com/8382359/1342246

房产中介网站源码网站开发与服务合同范本

原文地址:http://www.cnblogs.com/joyeecheung/p/3757915.html 相关随笔: 点击打开链接 Hadoop-1.0.4集群搭建笔记用python hadoop streaming 编写分布式程序(二) -- 在集群上运行与监控用python hadoop streaming 编写分布式程…

iis7发布网站教程乐清市做淘宝网站公司

版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/nwsuaf2009012882/article/details/32703597 SQL Server 2008 数据库主键自增插入显示值 前几天在工作的时候遇到在删除数据库中表的数据的时候。删除之后,又一次…

建设部网站 干部学院 一级注册建筑师培训 2014年广西网站建设产品优化

GL/gl.h:No such file or directory原因 缺少libgl相关库引起 解决办法: yum -y install libglade2-devel yum -y install libglade2-help yum -y install libglvnd-devel

房地产最新信息宁夏网站seo

你是否曾经想过自己也能编写一个代理服务器,掌握网络冲浪的主动权?现在,有了Go语言,这个梦想不再遥不可及!让我们一起踏上这段探险之旅,用Go语言编写一个自定义的HTTP代理,开启网络奇幻之旅&…

html网站开发语言优秀企业网站设计欣赏

不少数站长在使用WordPress博客或者搬家时,需要把WordPress文章中的图片路径进行替换来解决图片不显示的问题。总结一下WP图片路径批量替换的过程,方便有此类需求的站长们学习。什么情况下批量替换图片路径1、更换了网站域名有许多网站建设初期都随便选择…

教育网站如何做经营舟山网站制作公司

因为UNIX系统经常承当着关键任务,所以它经常是***者***的首选目标。于是检测***、保护系统安全是管理员的最为重要的任务之一。那么,在没有其它工具帮助的情况下,如何去判断系统当前的安全性?如何去发现***呢?下面给大家介绍一些常…

外贸没有公司 如何做企业网站?网站制作系统哪个好

AI魔幻巨制电影《权力的游戏:重生之战》 《冰与火之歌》龙妈雪诺后裔是谁?你相信龙族的力量可以改变维斯特洛大陆的命运吗? 在《权力的游戏:重生之战》中,维斯特洛大陆再次陷入混乱之中,但这一次的混乱并非…

北京网站设计制作网络推广专员职责

文章目录 简介spaCy特性: 系统环境与版本安装应用示例参考文献 简介 spaCy spaCy 是一个 Python 和 CPython 的 NLP 自然语言文本处理库。因此它是一个非常快的库。它建立在最新的研究基础上,从设计的第一天起就被用于实际产品中。 spaCy 自带预训练的…

10元网站备案哪个域名注册网站好

私有继承 在C中,私有继承是一种继承方式,它定义了一个私有派生类,也称为派生类。私有继承意味着派生类继承了基类的所有成员,但这些成员在派生类中是私有的,对外部不可见。 要进行私有继承请使用private关键字&#…

最便宜做网站的方法兰州网站制作服务电话

目录 (1)备份某个数据库下的固定某些表 (2)对单个或多个库进行完全备份 (3)对所有库进行完全备份(建立all.sql文件) (1)备份某个数据库下的固定某些表 目标&#xff…

网站后台更新后主页不显示怎么查网站icp备案

Leetcod540 有序数组中的单一元素 1.题目描述 2.解题思路 同样是二分搜索,利用当i为偶数时候,数组中单独元素左侧的所有i位置与i1位置的数字相同,而单独元素右侧的所有i位置与i1位置元素不同的特性,来进行二分搜索 3.算法思路 …