算法导论 总结索引 | 第三部分 第十二章:二叉搜索树

1、搜索树数据结构 支持 许多动态集合操作,包括 SEARCH、MINIMUM、MAXIMUM、PREDECESSOR、SUCCESSOR、INSERT 和 DELETE 等。使用搜索树 既可以作为一个字典 又可以作为一个优先队列

2、二叉搜索树上的基本操作 所花费的时间 与这棵树的高度成正比。对于有n个结点的 一棵完全的二叉搜索树来说,这些操作的最坏运行时间为 Θ(lgn),如果 这棵树是一条n个结点组成的线性链,那么 同样的操作 就要花费 Θ(n) 的最坏运行时间

1、什么是二叉搜索树

1、除了key和卫星数据之外,每个结点 还包含属性left、night和p,它们分别指向结点的左孩子、右孩子和双亲。根结点是树中唯一父指针为NIL的结点

对任何结点,其左子树中的关键字最大 不超过 x.key,其右子树中的关键字最小 不低于x.key。不同的二叉搜索树 可以代表同一组值的集合

2、中序遍历 就可以 从大到小输出 一棵二叉树T中的 所有元素

INORDER-TREE-WALK(x)if x != NILINORDER-TREE-WALK(x.left)print x.keyINORDER-TREE-WALK(x.night)

3、如果x是一棵 有n个结点子树的根,那么调用INORDER-TREE-WALK(x) 需要 Θ(n) 时间

证明:要访问 这棵子树的全部n个结点,所以有 T(n) = Ω(n),下面要证明 T(n) = O(n)
首先有 T(0) = c
当调用 INORDER-TREE-WALK作用在 一个结点x上,x结点左子树 有k个结点 且其右子树有 n - k - 1个结点,时间由 T(n) <= T(k) + T(n - k - 1) +d 的限界其中 常数d > 0。反映了执行的时间的上界,
使用 替换法,通过 证明 T(n) <= (c + d)n + c,可以证得 T(n) = O(n)。对于 n = 0,有 (c + d)*0 + c = c = T(0)。对于 n > 0,有
定理证明
4、二叉搜索树性质与最小堆性质之间 有什么不同?能使用最小堆性质在 O(n) 时间内 按序输出一棵有n个结点树的关键字吗
最小堆性质:设x是最小堆中的一个结点。如果y是x子树中的一个结点,那么y.key≥x.key
二叉搜索树性质:设x是二叉搜索树中的一个结点。如果y是x左子树中的一个结点,那么y.key≤x.key。如果y是x右子树中的一个结点,那么y.key≥x.key

不能使用最小堆性质在时间 O(n) 内按序输出一棵有n个结点树的关键字
证明:假设能使用最小堆性质在时间 O(n) 内按序输出一棵有n个结点树的关键字,这也意味着给定一个最小堆,就能在时间 O(n) 内对其所有结点的关键字进行排序,但堆排序的时间复杂度是 O(lgn) ,所以假设不成立

5、执行 中序追历的非递归算法
一种容易的方法是 使用栈作为辅助数据结构;另一种较复杂但比较简洁的做法是不使用栈,但要假设能测试两个指针是否相等

 使用栈
INORDER-TREE-WALK-ITERATION-WITH-STACK(x)let S be a new stackp = xwhile p ≠ NIL or !STACK-EMPTY(S)if p ≠ NILPUSH(S, p)p = p.leftelse p = POP(S)print p.keyp = p.right不使用栈
INORDER-TREE-WALK-ITERATION-WITHOUT-STACK(x)cur = xprev = NILwhile cur ≠ NILif cur.left == NILprint cur.keycur = cur.rightelse prev = cur.leftwhile prev.right ≠ NIL and prev.right ≠ curprev = prev.rightif prev.right == NILprev.right = curcur = cur.leftelse prev.right = NILprint cur.keycur = cur.right

1)不使用栈 中序遍历
如果当前节点的左孩子为空,则输出当前节点并将当前节点的右孩子作为“新的当前节点”

如果当前节点的左孩子不为空,在当前节点的左子树中 找到当前节点在中序遍历下的前驱节点

a) 如果前驱节点的右孩子为空,那么将 当前节点设置为前驱节点的右孩子。把当前节点的左孩子设置为“新的当前节点”
b) 如果前驱节点的右孩子为当前节点,将前驱节点的右孩子重新设为空(即恢复树的形状)。然后输出当前节点,并将当前节点的右孩子设置为“新的当前节点”

void inorderMorrisTraversal(TreeNode *root) {TreeNode *cur = root, *prev = NULL;while (cur != NULL){if (cur->left == NULL)         {printf("%d ", cur->val);cur = cur->right;}else{// find predecessorprev = cur->left;while (prev->right != NULL && prev->right != cur)prev = prev->right;if (prev->right == NULL)   {prev->right = cur;cur = cur->left;}else                      {prev->right = NULL;printf("%d ", cur->val);cur = cur->right;}}}}

要使用O(1)空间进行遍历,最大的难点在于,遍历到子节点的时候 怎样重新返回到父节点(假设节点中没有指向父节点的p指针),由于不能用栈作为辅助空间。为了解决这个问题,Morris方法用到了 线索二叉树的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱 和 后继节点,只需要利用叶子节点中的左右空指针 指向某种顺序遍历下的前驱节点 或 后继节点 就可以了
线索二叉树是一种特殊的二叉树,它通过利用节点的空指针域存储线索,以便在不需要递归或使用栈的情况下实现对二叉树的快速遍历。线索二叉树包括前序线索二叉树、中序线索二叉树、后序线索二叉树等

2)不使用栈 前序遍历(线索二叉树)
与中序遍历相似,代码上只有一行不同,不同就在于输出的顺序

如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点

如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点 在中序遍历下的前驱节点

a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。输出当前节点(在这里输出,这是与中序遍历唯一一点不同)。当前节点更新为当前节点的左孩子
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空。当前节点更新为当前节点的右孩子

void preorderMorrisTraversal(TreeNode *root) {TreeNode *cur = root, *prev = NULL;while (cur != NULL){if (cur->left == NULL){printf("%d ", cur->val);cur = cur->right;}else{prev = cur->left;while (prev->right != NULL && prev->right != cur)prev = prev->right;if (prev->right == NULL){printf("%d ", cur->val);  // the only difference with inorder-traversalprev->right = cur;cur = cur->left;}else{prev->right = NULL;cur = cur->right;}}}}

3)不使用栈 后序遍历
Morris 后序遍历的步骤(适配后序遍历)
建立临时节点:建立一个临时节点 temp,令 temp.left 指向根节点

遍历节点:初始化 cur 指向 temp

左子树处理:
如果 cur.left 不为空,找到 cur 的左子树中的最右节点(即左子树的前驱节点)
如果前驱节点的右指针为空(即 prev.right == NULL),令 prev.right = cur,然后 cur = cur.left 继续处理左子树
如果前驱节点的右指针指向 cur(形成了一个环路,说明左子树已处理完成),则需要断开环路(prev.right = NULL),处理右子树之前,按逆序打印从 cur.left 到这个前驱之间的所有节点,再令 cur = cur.right

右子树处理:
当 cur.left 为空时,直接移动到 cur.right。
结束遍历:当 cur 为空时,结束遍历

逆序打印
逆序打印是后序遍历中使用 Morris 遍历时特有的一个步骤。从当前节点的左子节点出发到最右子节点的路径上的所有节点需要逆序打印,这模拟了后序遍历中“左右根”的顺序
这种方法避免了使用栈,但通过修改树的结构(临时修改右指针)来保存必要的信息。遍历完成后,树的结构被还原到其原始状态

 void reverse(TreeNode *from, TreeNode *to) // reverse the tree nodes 'from' -> 'to'.{if (from == to)return;TreeNode *x = from, *y = from->right, *z;while (true){z = y->right;y->right = x;x = y;y = z;if (x == to)break;}}void printReverse(TreeNode* from, TreeNode *to) // print the reversed tree nodes 'from' -> 'to'.{reverse(from, to);TreeNode *p = to;while (true){printf("%d ", p->val);if (p == from)break;p = p->right;}reverse(to, from);}void postorderMorrisTraversal(TreeNode *root) {TreeNode dump(0);dump.left = root;TreeNode *cur = &dump, *prev = NULL;while (cur){if (cur->left == NULL){cur = cur->right;}else{prev = cur->left;while (prev->right != NULL && prev->right != cur)prev = prev->right;if (prev->right == NULL){prev->right = cur;cur = cur->left;}else{printReverse(cur->left, prev);  // call printprev->right = NULL;cur = cur->right;}}}}

对于一棵有个结点的树,请设计在 O(n) 时间内完成的先序遍历算法 和 后序遍历算法(上面的总结)

PREORDER-TREE-WALK(x)if x ≠ NILprint x.keyPREORDER-TREE-WALK-RECURSIVE(x.left)PREORDER-TREE-WALK-RECURSIVE(x.right)PREORDER-TREE-WALK-WITH-STACK(x)let S be a new stackp = xwhile p ≠ NIL or !STACK-EMPTY(S)if p ≠ NILprint p.keyPUSH(S, p)p = p.leftelse p = POP(S)p = p.rightPREORDER-TREE-WALK-WITHOUT-STACK(x)cur = xprev = NILwhile cur ≠ NILif cur.left == NILcur = cur.rightelse prev = cur.leftwhile prev.right ≠ NIL and prev.right ≠ curprev = prev.rightif prev.right == NILprint cur.keyprev.right = curcur = cur.leftelse prev.right = NILcur = cur.right
POSTORDER-TREE-WALK(x)if x ≠ NILPREORDER-TREE-WALK-RECURSIVE(x.left)PREORDER-TREE-WALK-RECURSIVE(x.right)print x.keyPOSTORDER-TREE-WALK-WITH-STACK(x)let S be a new stackp = xwhile p ≠ NIL or !STACK-EMPTY(S)if p ≠ NILp.visited = 1PUSH(S, p)p = p.leftelse p = POP(S)if p.visited == 1p.visited = p.visited + 1PUSH(S, p)p = p.rightelseif p.visited == 2print p.keyp = NILPRINT-REVERSE(from, to)if from != toPRINT-REVERSE(from.right, to)print from.keyPOSTORDER-TREE-WALK-WITHOUT-STACK(x)dump.left = xcur = dumpprev = NILwhile cur ≠ NILif cur.left == NILcur = cur.rightelse prev = cur.leftwhile prev.right ≠ NIL and prev.right ≠ curprev = prev.rightif prev.right == NILprev.right = curcur = cur.leftelse PRINT-REVERSE(cur.left, prev)prev.right = NILcur = cur.right

6、证明任何基于比较的算法从n个元素的任意序列中构造一棵二叉搜索树,其最坏情况下需要Ω(n lgn)
证明:
在这里插入图片描述
在这里插入图片描述

2、查询二叉搜索树

1、查找:输入一个指向树根的指针 和 一个关键字k,如果 这个结点存在,TREE-SEARCH 返回一个指向关键字为k的 结点指针;否则返回NIL

TREE-SEARCH(x.k)
if x == NIL or k == x.keyreturn x
if k < x.keyreturn TREE-SEARCH(x.left, k)
else return TREE-SEARCH(x.right, k)

从树根 开始递归期间遇到的结点 就形成了 一条向下的简单路径,所以 TREE-SEARCH 的运行时间为 O(h),其中 h 是这棵树的高度

采用 while 循环 来展开递归,用一种 迭代方式重写这个过程,效率更高

ITERATIVE-TREE-SEARCH(x.k)while x != NIL and k != x.keyif k < x.keyx = x.leftelse x = x.rightreturn x

2、最大关键字元素和最小关键字元素

TREE-MINIMUM(x)while x.left != NILx = x.leftreturn x

TREE-MAXIMUM的伪代码是对称的

TREE-MAXIMUM(x)while x.right != NILx = x.rightreturn x

这个过程 在一棵高度为h的树上 均能在 O(h) 时间内执行完

3、后继和前驱
按中序顺序的次序 查找他的后继,则 一个结点x的后继 是大于 x.key的最小关键字的结点

TREE-SUCCESSOR(x)if x.right != NILreturn TREE-MINIMUM(x.right)y = x.pwhile y != NIL and x == y.right // 还是右子树的关系,要找到左子树就停了x = yy = y.preturn y

如果 结点x的右子树非空,那么x的后继结点 恰是x右子树中的 最左节点
右子树结点为空
如果结点x(13)的右子树为空 并有一个后继y(15),那么 y就是x的有左孩子的 最底层祖先,而且 它也是x的一个祖先。为了找到y,只需简单地从x开始 沿树而上 直到 遇到一个双亲有左孩子的结点

该过程 或者遵从一条简单路径 沿树而上 或者 遵从简单路径 沿树而下

求前驱跟后继代码对称

TREE-PREDECESSOR(x)if x.left ≠ NILreturn TREE-MAXIMUM(x.left)y = x.pwhile y ≠ NIL and x == y.leftx = yy = y.preturn y

4、在一棵高度为h的二叉搜索树上,动态集合上的操作 SEARCH、MINIMUM、MAXIMUM、SUCCESSOR和PREDECESSOR可以在 O(h) 时间内完成

5、考虑一棵二叉搜索树T,其关键字 互不相同。证明:如果T中 一个结点x的右子树为空,且x有一个后继y,那么 y一定的最底层祖先,并且其左孩子 也是x的祖先
(注意到,每个结点都是它自己的祖先)
证明:因为T中所有的关键字互不相同,所以y是大于x.key的最小关键字的结点。

  1. 如果y不是x的最底层祖先,则y的左孩子的关键字大于x.key小于y.key,此时y不是大于x.key的最小关键字的结点,与条件矛盾,所以y是x的最底层祖先。
  2. 如果y的左孩子不是x的祖先,因为每个结点都是它自己的祖先,则x是y的右子树中的一个结点,此时y的关键字小于x.key,与条件矛盾,所以y的左孩子也是x的祖先。

6、用另一种方法 实现n个结点的二叉搜索树的中序遍历:TREE-MINIMUM找到这棵树中的最小元素,然后再调用 n-1 次的TREE-SUCCESSOR 证明 该算法的运行时间为 Θ(n)
证明:根据算法可知,每条边被遍历了两次,第一次向下,第二次向上。因为二叉搜索树中有 n 个结点,也即有 n-1 条边,共访问了 2(n-1) 次,所以该算法的运行时间为 Θ(n)

7、在一棵高度为h的二叉搜索树中,不论从哪个结点开始,k次连续的TREE-SUCCESSOR调用所需时间为 O(k + h)
证明:在一棵高度为h的树上,TREE-SUCCESSOR的运行时间为 O(h),因为该过程 或者遵从一条简单路径沿树向上 或者遵从简单路径沿树向下。根据6,k次连续的TREE-SUCCESSOR调用的运行时间是 O(k)。结合这两者可得,在一棵高度为h的二叉搜索树中,不论从哪个结点开始,k次连续的TREE-SUCCESSOR调用所需时间为 O(k + h)

8、设T是一棵二叉搜索树,其关键字 互不相同,设x是一个叶结点,y为其父结点。证明:y.key 或者是 T树中大于x.key的最小关键字,或者 是T树中小于x.key的最大关键字
证明:因为T是一棵二叉搜索树,其关键字互不相同,又因为x是一个叶结点(没有左右孩子的),y为其父结点,所以y为x的前驱或后继

  1. 当x是y的左孩子时,y是x的后继,所以y.key是T树中大于x.key的最小关键字
  2. 当x是y的右孩子时,y是x的前驱,所以y.key是T树中小于x.key的最大关键字

因此,y.key或者是T树中大于x.key的最小关键字,或者是T树中小于x.key的最大关键字

3、插入和删除

1、插入一个新结点带来的树修改 要相对简单些,删除的处理 有些复杂
插入:将一个新值v插入到 一棵二叉搜索树中,以结点z作为输入,其中 z.key = v,z.left = NIL,z.right = NIL,只在叶子结点插入

TREE-INSERT(T, z)y = NILx = T.rootwhile x != NIL // 到叶子结点插入y = xif z.key < x.keyx = x.leftelse x = x.rightz.p = yif y == NILT.root = z // 树T为空elseif z.key < y.keyy.left = zelse y.right = z 
RECURSIVE-TREE-INSERT(x, z)y = xif z.key < x.keyx = x.leftelse x = x.rightif x ≠ NILRECURSIVE-TREE-INSERT(x, z)else z.p = yif y == NILT.root = z    // tree T was emptyelseif z.key < y.keyy.left = zelse y.right = z

2、删除:

  • 如果 z没有孩子结点,那么 只是简单地将他删除,并修改它的父结点,用 NIL 作为孩子来替换z
  • 如果 z只有一个孩子,那么 将这个孩子 提升到 树中z的位置上,并修改z的父结点,用z的孩子 来替换z
  • 如果 z有两个孩子,那么找z的后继y(一定在z的右子树中),并 让y占据树中z的位置。z的原来右子树部分 变为 y的新的右子树,并且 z的左子树 成为y的新的左子树。还与 y是否为z的右孩子相关

如果 z有两个孩子:
如果y是z的右孩子,用y替换z,并仅留下 y的右孩子(如c)
否则,位于z的右子树中 但并不是z的右孩子。先用 y的右孩子替换y,然后 再用y替换z(看起来做了旋转)(如d)
删除
定义 一个子过程 TRANSPLANT,它是用 另一棵子树 替换 一棵子树并成为 其双亲的孩子结点

TRANSPLANT(T, u, v)if u.p == NILT.root = velseif u == u.p.leftu.p.left = velse u.p.right = vif v != NILv.p = u.p

u是其双亲的左孩子 或 右孩子。TRANSPLANT 并没有处理 v.left 和 v.right 的更新;这些更新 由TRANSPLANT的调用者来完成

TREE-DELETE(T, x)if z.left == NILTRANSPLANT(T, z, z.right)elseif z.right == NILTRANSPLANT(T, z, z.left)else y = TREE-MINIMUM(z.right) // y是后继,第5行if y.p != zTRANSPLANT(T, y, y.right)y.right = z.righty.right.p = yTRANSPLANT(T, z, y)y.left = z.lefty.left.p = y

第5行查找结点y,它是z的后继。因为z的右子树非空,这样后继 一定是这个子树中 具有最小关键字的结点
因为y已经是最小的,所以 不会有左孩子。将y移出它的原来位置 进行拼接,并替换树中的z
如果 y是z的右孩子,那么就用 y替换z并成为z的双亲的一个孩子,用z的左孩子 替换y的右孩子
如果 y不是z的右孩子,用y的右孩子 替换y并成为y的双亲的一个孩子,然后 将z的左孩子 替换为 y的左孩子(旋转过程,把没有左孩子的y提上去),最后三行:用y替换z 并成为z的双亲的一个孩子,再用z的左孩子 替换为y的左孩子

除了 第5行调用 TREE-MINIMUM 之外,TREE-DELETE 的每一行,包括调用 TRANSPLANT ,都只花费 常数时间。因此,在一棵高度为h的树上,TREE-DELETE 的运行时间为 O(h)

3、在一棵高度为h的二叉搜索树上,实现动态集合操作INSERT 和 DELETE的运行时间 均为 O(h)

4、删除操作不可交换(可交换的含义是,先删除x再删除y留下的结果树 与 先删除y再删除x 留下的结果树完全一样)。反例如下:删除操作不可交换
也证明了 同样的序列(不同顺序删除后 最后的序列都是一样的)可以对应 不同的二叉搜索树

5、假设 为每个结点换一种设计,将属性x.p(双亲)替换为x.succ(后继)。给出使用这种表示法的二叉搜索树T上SEARCH、INSERT和DELETE操作的伪代码。这些伪代码应在O(h)时间内执行完,其中h为树T的高度
应该设计一个返回某个结点的双亲的子过程

TREE-SEARCH(x, k) // 不变if x == NIL or k == x.keyreturn xif k < x.keyreturn TREE-SEARCH(x.left, k)else return TREE-SEARCH(x.right, k)TREE-INSERT(T, z)y = NILx = T.rootwhile x ≠ NILy = x // y是x的父结点if z.key < x.keyx = x.leftelse x = x.rightif y == NILT.root = zelseif z.key < y.keyy.left = zz.succ = yelse y.right = zz.succ = y.succy.succ = zPARENT(x)z = x.succ // z是y的父结点y = z.leftwhile y ≠ xz = yy = y.rightreturn zTRANSPLANT(T, u, v)p = PARENT(u)if p == NILT.root = velseif u == p.leftp.left = vv.succ = pelse p.right = vp.succ = vTREE-DELETE(T, z)if z.left == NILTRANSPLANT(T, z, z.right)elseif z.right == NILTRANSPLANT(T, z, z.left)else y = TREE-MINIMUM(z.right)if z ≠ PARENT(y)TRANSPLANT(T, y, y.right)y.right = z.righty.succ = z.rightTRANSPLANT(T, z, y)y.left = z.lefty.left.succ = y

6、当 TREE-DELETE 中的结点z有两个孩子时,选择结点y为它的前驱,而不是 后继。如果这样做,对TREE-DELETE应该做些什么必要的修改?一些人提出了一个公平策略,为前驱和后继赋予相等的优先级,这样得到了较好的实验性能。如何对TREE-DELETE进行修改来实现这样一种公平策略(用随机数把前驱 / 后继删除 结合起来)

TREE-DELETE(T, z)if z.left == NILTRANSPLANT(T, z, z.right)elseif z.right == NILTRANSPLANT(T, z, z.left)else y = TREE-MAXIMUM(z.left) // else才有区别if y.p ≠ zTRANSPLANT(T, y, y.left) // left和right反的y.left = z.lefty.left.p = yTRANSPLANT(T, z, y)y.right = z.righty.right.p = y
TREE-DELETE(T, z)if z.left == NILTRANSPLANT(T, z, z.right)elseif z.right == NILTRANSPLANT(T, z, z.left)elseif RANDOM(1, 2) == 1y = TREE-MINIMUM(z.right)if y.p ≠ zTRANSPLANT(T, y, y.right)y.right = z.righty.right.p = yTRANSPLANT(T, z, y)y.left = z.lefty.left.p = yelse y = TREE-MAXIMUM(z.left)if y.p ≠ zTRANSPLANT(T, y, y.left)y.left = z.lefty.left.p = yTRANSPLANT(T, z, y)y.right = z.righty.rignt.p = y

4、随机构建二叉搜索树

1、随着 元素的插入和删除,二叉搜索树的高度 是变化的。例如,如果个关键字 按严格递增的次序被插入,则这棵树 一定是高度为 n-1 的一条链

定义n个关键字 的一棵初始的空树中 而生成的树,这里输入关键字的 n! 个排列中的每个 都是等可能地出现

2、一棵 有n个不同关键字的 随机构建二叉搜索树的期望高度为 O(lg n)
证明:从定义三个随机变量开始,用 Xn 表示一棵 有n个不同关键字的 随即构建二叉树的高度,并定义 指数高度 Yn = 2Xn

选择 一个关键字作为 树根,并设 Rn为一个随机变量,表示 这个关键字在n个关键字排好序后 应占据的位置
如果 Rn = i,那么 根的左子树是一棵 有i - 1个关键字的 随机构建二叉搜索树,右子树 是一棵有 n - i 个关键字的 随机构建二叉搜索树
因为 二叉树的高度 比根的两棵子树较高的 那棵子树大1,因此 二叉树的指数高度是 根的两棵子树较高的 那棵子树的2倍。如果 Rn = i,则有
在这里插入图片描述
设 Yi = 1,1个结点的树的指数高度是 20=1,定义 Y0 = 0
定义 指示器随机变量 Zn,1,Zn,2,…,Zn,n,其中 Zn,i = I{Rn = i}。因为 Rn 对集合 {1, 2, …,n} 中的任何元素 都是等可能的(选择单个元素的位置,而不是整个序列)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
12.3证明12.3证明
有了 E[Yn] 界,但 最终的目标是 要得到 E[Xn] 的界,因为 f(x) = 2x是凸的,使用 Jensen不等式

得到 E[Xn] = O(lgn)
1)Jensen不等式
Jensen不等式
2)凸函数
凸函数
3)判断凸函数的方法
判断凸函数

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

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

相关文章

汽车热辐射、热传导、热对流模拟加速老化太阳光模拟器系统

汽车整车结构复杂&#xff0c;材料种类繁多&#xff0c;在使用过程中会面临各种严酷气候环境的考验&#xff0c;不可避免会出现零部件材料老化、腐蚀等不良现象&#xff0c;从而影响汽车的外观、功能&#xff0c;甚至产生安全隐患。因此&#xff0c;分析汽车零部件材料老化腐蚀…

深入剖析Tomcat(五) 剖析Servlet容器并实现一个简易Context与Wrapper容器

上一章介绍了Tomcat的默认连接器&#xff0c;后续程序都会使用默认连接器。前面有讲过Catalina容器的两大块内容就是连接器与Servlet容器。不同于第二章的自定义丐版Servlet容器&#xff0c;这一章就来探讨下Catalina中的真正的Servlet容器究竟长啥样。 四种容器 在Catalina中…

音视频入门基础:像素格式专题(1)——RGB简介

一、像素格式简介 像素格式&#xff08;pixel format&#xff09;指像素色彩按分量的大小和排列。这种格式以每个像素所使用的总位数以及用于存储像素色彩的红、绿、蓝和 alpha 分量的位数指定。在音视频领域&#xff0c;常用的像素格式包括RGB格式和YUV格式&#xff0c;本文…

【海博】雅思该怎么练?

文章目录 前言 备考计划 模拟考试 参考资料 前言 见《【海博】浅析海博深造》 见《【海博】雅思和托福该考哪个&#xff1f;》 见《【海博】雅思该怎么考&#xff1f;》 见《【海博】雅思考什么&#xff1f;》 备考计划 第一周确定你的目标考试分数。 做一套雅思模拟试题&…

npm install报错

总结&#xff1a;没有安装visual studio 2017以上带有C桌面开发的版本 #开始试错 #报错总信息mingw_x64_win版本 百度网盘链接: link 提取码&#xff1a;3uou #尝试用mingw配置个C编译器&#xff0c;并配置环境变量&#xff0c;失败 #只认可使用VS!GIthub原址: 链接: link 上…

python公务用车医院校园企业车辆管理系统

本 Python版本&#xff1a;python3.7 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask都有,都支持 后端&#xff1a;python 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 公务用车管理智慧云服务监管平台有管理员和用户…

java中的字节流和File类

目录 正文&#xff1a; 1.File类 1.1概述 1.2常用方法 2.FileInputStream 2.1概述 2.2常用方法 3.FileOutputStream 3.1概述 3.2常用方法 总结&#xff1a; 正文&#xff1a; 1.File类 1.1概述 File类是Java中用来表示文件或目录的类&#xff0c;它提供了一系列方…

【项目学习01_2024.05.02_Day04】

学习笔记 4 课程分类查询4.1需求分析4.2 接口定义4.3 接口开发4.3.1 树型表查询4.3.2 开发Mapper 4 课程分类查询 4.1需求分析 有课程分类的需求 course_category课程分类表的结构 这张表是一个树型结构&#xff0c;通过父结点id将各元素组成一个树。 利用mybatis-plus-gen…

Sass语法---sass的安装和引用

什么是Sass Sass&#xff08;英文全称&#xff1a;Syntactically Awesome Stylesheets&#xff09; Sass 是一个 CSS 预处理器。 Sass 是 CSS 扩展语言&#xff0c;可以帮助我们减少 CSS 重复的代码&#xff0c;节省开发时间。 Sass 完全兼容所有版本的 CSS。 Sass 扩展了…

centos7安装真的Redmine-5.1.2+ruby-3.0.0

下载redmine-5.1.2.tar.gz&#xff0c;上传到/usr/local/目录下 cd /usr/local/ tar -zxf redmine-5.1.2.tar.gz cd redmine-5.1.2 cp config/database.yml.example config/database.yml 配置数据连接 #编辑配置文件 vi config/database.yml #修改后的内容如下 product…

【介绍下Apache的安装与目录结构】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Vitis HLS 学习笔记--MAXI手动控制突发传输

目录 1. 简介 2. MAXI 突发传输详解 2.1 突发传输的前置条件 2.2 hls::burst_maxi 详解 2.2.1 基本知识 2.2.2 hls::burst_maxi 构造函数 2.2.3 hls::burst_maxi 读取方法 2.2.4 hls::burst_maxi 写入方法 2.3 示例一 2.4 示例二 3. 总结 1. 简介 这篇文章探讨了在…

Python版本管理工具-pyenv

Pyenv是一个Python版本管理工具。 Pyenv允许用户在同一台机器上安装多个版本的Python&#xff0c;并能够轻松切换使用这些版本。 一、安装 Mac下直接使用Homebrew安装 # 更新 Homebrew 的软件列表 brew update # 安装pyenv brew install pyenv# 验证是否安装成功 pyenv -v# …

解锁工业场景下的时序因果发现,清华阿里巴巴伯克利联合提出RealTCD框架:通过大语言模型提升发现质量!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; LLM-Enhanced Causal Discovery in Temporal Domain from Interventional Data 引言&#xff1a;AI在信息技术运营中的革命性应用 在现代信息技术运营&#…

远程链接linux

远程连接 ssh 远程登录操作&#xff0c;ssh会对用用户进行身份信息的验证&#xff0c;会对两台主机之间发通信数据进行加密 安装 ssh 远程登录的服务端 yum install -y openssh-server启动 ssh 服务 systemctl start ssh.service 关闭 ssh 服务 systemctl stop ssh.service …

java发送请求2次开发-get请求json

因为你请求参数不为空&#xff0c;接口都会把这个参数带上 所以借鉴HttpPost类 继承这个类&#xff0c; 这个类是可以带消息的 httpgetwithentity&#xff0c;httpget请求带上消息 复写 构造方法复制过来进行使用 二次开发类让其get请求时可以发送json

基于大爆炸优化算法的PID控制器参数寻优matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于大爆炸优化算法的PID控制器参数寻优matlab仿真。对比优化前后的PID控制输出。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a .....................…

测试腾讯云的高防CC抵御了攻击

网站需要安装防止CC攻击&#xff0c;因为CC攻击是一种常见的网络攻击&#xff0c;它会对网站造成严重的影响。 CC攻击&#xff08;Cybercrime Control&#xff09;是指向网站发起大量虚假请求的攻击&#xff0c;目的是使网站的资源耗尽&#xff0c;无法正常运行。CC攻击与DDoS…

python-pytorch官方示例Generating Names with a Character-Level RNN的部分理解0.5.03

pytorch官方示例Generating Names with a Character-Level RNN的部分理解 模型结构功能关键技术模型输入模型输出预测实现 模型结构 功能 输入一个类别名和一个英文字符&#xff0c;就可以自动生成这个类别&#xff0c;且以英文字符开始的姓名 关键技术 将字符进行one-hot编…

通过符号程序搜索提升prompt工程

原文地址&#xff1a;supercharging-prompt-engineering-via-symbolic-program-search 通过自动探索​​大量提示变体来找到更好的提示 2024 年 4 月 22 日 众所周知&#xff0c;LLMs的成功在很大程度上仍然取决于我们用正确的指导和例子来提示他们的能力。随着新一代LLMs变得越…