迪庆藏族自治州网站建设_网站建设公司_电商网站_seo优化
2025/12/23 13:15:31 网站建设 项目流程

:一个每条边都是桥的连通图。

二叉树:一棵有根树。每个节点的分支数量 \(\leq 2\) 个,分支称为“左子树”和“右子树”,顺序不能随意颠倒。
特别的,wikipedia 提到“很多人喜欢使用“有根二叉树”而非二叉树,以强调二叉树是有根的,但归根结底二叉树是有根的”。

二叉搜索树:一棵二叉树。每个内部节点的键大于该节点左子树中的所有键,而小于该节点右子树中的所有键。
二叉搜索树最常见的名字,Binary Search Tree,大家通常喜欢写作 BST 。有些地方也会叫做“有序二叉树”或者“排序二叉树”,指的都是同一种树。

显然,基于 BST 的定义,BST 的子树也是 BST 。

定理 1 :BST 中左链上的最左节点为最小节点。
证明
设左链上的节点为 \(root=N_0, N_1, \cdots, N_k\) ,对于 \(0 \leq i < k\), \(N_{i + 1}\)\(N_{i}\) 的左儿子,\(N_{k}\) 是左链上的最左节点。
首先有 \(N_k < N_{k - 1} < \cdots < N_{0} = root\)\(\forall\) 非左链节点 \(z\)\(\exists j, 0 \leq j \leq k\) 满足 \(z\)\(N_{j}\) 的右子树节点。
\(N_{k} \leq N_{j} < z\) ,即 BST 中左链上的最左节点是 BST 中的最小节点。
\(\square\)

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{findMinNode}(root) \\ 2: \ &\quad \textbf{while} \ root.\text{left} \neq \text{NIL} \ \textbf{do} \\ 3: \ &\quad\quad root \leftarrow cur.\text{left} \\ 4: \ &\quad \textbf{return} \ root \end{aligned} \]

定理 2 :BST 中右链上的最右节点为最大节点。
证明
设右链上的节点为 \(root=M_0, M_1, \cdots, M_l\) ,对于 \(0 \leq i < l\), \(M_{i + 1}\)\(M_{i}\) 的右儿子,\(M_{l}\) 是右链上的最右节点。
首先有 \(M_l > N_{l - 1} > \cdots > M_{0} = root\)\(\forall\) 非右链节点 \(z\)\(\exists j, 0 \leq j \leq l\) 满足 \(z\)\(M_{j}\) 的左子树节点。
\(M_{k} \geq M_{j} > z\) ,即 BST 中右链上的最右节点是 BST 中的最大节点。
\(\square\)

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{findMaxNode}(root) \\ 2: \ &\quad \textbf{while} \ root.\text{right} \neq \text{NIL} \ \textbf{do} \\ 3: \ &\quad\quad root \leftarrow root.\text{right} \\ 4: \ &\quad \textbf{return} \ root \end{aligned} \]

定理 3 :BST 的节点 \(x\) 的前驱(升序序列中该节点的前一个节点)。

  1. \(x\) 存在左子树,前驱是左子树上右链的最右节点;
  2. 否则前驱是 \(x\) 最近的将其置于右子树中的祖先 \(y\)

证明
考虑当前的根 \(root\) ,他的子树在升序序列中的区间一定为 \([1, n]\) ,令 \(L = 1, R = n\)
考虑节点 \(x\) 的排名为 \(k\) ,他在升序序列中的子树区间为 \([l, r]\) 满足 \(L \leq l \leq k \leq R\)
考虑从根到 \(x\) 的路径,每次向左走,当前节点和右子树都比左子树大,则存在一个 \(p\) 满足 \(r < p \leq R\) ,使得新子树的区间为 \([L, p - 1]\) ,更新 \(R \gets p - 1\) ;每次向右走,当前节点和左子树都比其右子树小,则存在一个 \(q\) 满足 \(L \leq q < l\) ,使得新子树的区间为 \([q + 1, R]\) ,更新 \(L \gets q + 1\)
显然非 \(x\) 的子树节点中,最大的比 \(x\) 小的节点在最后一次向右走时出现,且是离 \(x\) 最近的将其置于右子树的祖先 \(y\)

考虑如何找到 \(y\) ,自顶向下的方法是从 \(root\)\(x\) 走,更新右拐的节点,则最后一次更新的节点为 \(y\)
考虑自底向上的方法,从 \(x\) 往根节点走的路径中,若当前节点是其父亲的左儿子则 \(x\) 在其父亲的左子树中,若当前节点是其父亲的右儿子则 \(x\) 在其父节点的右子树中,于是只需向上跳到第一个节点满足其是父节点的右儿子,则其父亲为离 \(x\) 最近的将 \(x\) 置于右子树的祖先。

\(x\) 存在左子树,由于 \(x\)\(y\) 的左子树中,\(x\) 的左子树也一定比 \(y\) 小,则 \(x\) 的前驱是 \(x\) 左子树中的最大节点,即左子树上右链的最右节点。若 \(x\) 不存在左子树,则只有非 \(x\) 子树的节点可能比 \(x\) 小,则 \(x\) 的前驱是离它最近的将它置于右子树的节点 \(y\) ,即非 \(x\) 子树中最大的比 \(x\) 小的节点。
\(\square\)

如果记录 \(parent\) 节点,可以从 \(x\) 往上跳。实现形式 1:

\[\hspace{-32em}\begin{aligned} 1: \ &\text{predecessor}(x) \\ 2: \ &\quad \textbf{if} \ x.\text{left} \neq \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ \text{findMaxNode}(x.\text{left}) \\ 4: \ &\quad \textbf{else} \\ 5: \ &\quad\quad \textbf{while} \ x.\text{parent} \neq \text{NIL} \ \textbf{and} \ x = x.\text{parent}.\text{left} \ \textbf{do} \\ 6: \ &\quad\quad\quad x \gets x.\text{parent} \\ 7: \ &\quad\quad \textbf{return} \ x.\text{parent} \end{aligned} \]

如果不记录 \(parent\) 节点,则从根往 \(x\) 跳。时间复杂度同第一种实现。实现形式 2:

\[\hspace{-32em}\begin{aligned} 1: \ &\text{predecessor}(root, x, pred) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ \text{NIL} \\ 4: \ &\quad \textbf{if} \ x.\text{key} = root.\text{key} \ \textbf{then} \\ 5: \ &\quad\quad \textbf{if} \ x.\text{left} \neq \text{NIL} \ \textbf{then} \\ 6: \ &\quad\quad\quad \textbf{return} \ \text{findMaxNode}(root.\text{left}) \\ 7: \ &\quad\quad \textbf{else} \ \textbf{return} \ pred \\ 8: \ &\quad \textbf{elseif} \ x.\text{key} < root.\text{key} \ \textbf{then} \\ 9: \ &\quad\quad \textbf{return} \ \text{predecessor}(root.\textbf{left}, x, pred) \\ 10: \ &\quad \textbf{else} \ \textbf{return} \ \text{predecessor}(root.\textbf{right}, x, root) \\ \end{aligned} \]

定理 4 :BST 的节点 \(x\) 的后继(升序序列中该节点的后一个节点)。

  1. \(x\) 存在右子树,后继是右子树上左链的最左节点;
  2. 否则后继是 \(x\) 到根的右链段中最近的祖先 \(y\)

证明
考虑当前的根 \(root\) ,他的子树在升序序列中的区间一定为 \([1, n]\) ,令 \(L = 1, R = n\)
考虑节点 \(x\) 的排名为 \(k\) ,他在升序序列中的子树区间为 \([l, r]\) 满足 \(L \leq l \leq k \leq R\)
考虑从根到 \(x\) 的路径,每次向左走,当前节点和右子树都比左子树大,则存在一个 \(p\) 满足 \(r < p \leq R\) ,使得新子树的区间为 \([L, p - 1]\) ,更新 \(R \gets p - 1\) ;每次向右走,当前节点和左子树都比其右子树小,则存在一个 \(q\) 满足 \(L \leq q < l\) ,使得新子树的区间为 \([q + 1, R]\) ,更新 \(L \gets q + 1\)
显然非 \(x\) 的子树节点中,最小的比 \(x\) 大的节点在最后一次向左走时出现,且是离 \(x\) 最近的将其置于左子树的祖先 \(y\)

考虑如何找到 \(y\) ,自顶向下的方法是从 \(root\)\(x\) 走,更新左拐的节点,则最后一次更新的节点为 \(y\)
考虑自底向上的方法,从 \(x\) 往根节点走的路径中,若当前节点是其父亲的右儿子则 \(x\) 在其父亲的右子树中,若当前节点是其父亲的左儿子则 \(x\) 在其父节点的左子树中,于是只需向上跳到第一个节点满足其是父节点的左儿子,则其父亲为离 \(x\) 最近的将 \(x\) 置于左子树的祖先。

\(x\) 存在右子树,由于 \(x\)\(y\) 的右子树中,\(x\) 的右子树也一定比 \(y\) 大,则 \(x\) 的后继是 \(x\) 右子树中的最小节点,即右子树上左链的最左节点。若 \(x\) 不存在右子树,则只有非 \(x\) 子树的节点可能比 \(x\) 大,则 \(x\) 的后继是离它最近的将它置于左子树的节点 \(y\) ,即非 \(x\) 子树中最小的比 \(x\) 大的节点。

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{successor}(root, x, pred) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ \text{NIL} \\ 4: \ &\quad \textbf{if} \ x.\text{key} = root.\text{key} \ \textbf{then} \\ 5: \ &\quad\quad \textbf{if} \ x.\text{left} \neq \text{NIL} \ \textbf{then} \\ 6: \ &\quad\quad\quad \textbf{return} \ \text{findMaxNode}(root.\text{left}) \\ 7: \ &\quad\quad \textbf{else} \ \textbf{return} \ pred \\ 8: \ &\quad \textbf{elseif} \ x.\text{key} < root.\text{key} \ \textbf{then} \\ 9: \ &\quad\quad \textbf{return} \ \text{successor}(root.\textbf{left}, x, pred) \\ 10: \ &\quad \textbf{else} \ \textbf{return} \ \text{successor}(root.\textbf{right}, x, root) \\ \end{aligned} \]

定理 5 :BST 的中序遍历是二叉树的升序序列。

证明
对于节点个数为 \(1\) 的 BST ,显然成立。
否则由归纳假设,\(root\) 的左子树的中序遍历是升序序列 \(L_1\)\(root\) 的右子树的升序遍历是升序序列 \(L2\) 。由 \(L_1 < root.\text{key} < L_2\) ,则该 BST 的中序遍历 \([L_1, root.\text{key}, L_2]\) 是升序遍历。
\(\square\)

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{inorderTraversal}(root) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad \quad \textbf{return} \\ 4: \ &\quad \text{inorderTraversal}(root.\text{left}) \\ 5: \ &\quad \text{print} \ root.\text{key} \\ 6: \ &\quad \text{inorderTraversal}(root.\text{right}) \\ \end{aligned} \]

定理 6 :BST 中查询 \(target\)

  1. \(target = root.\text{key}\) 则目标节点是当前节点;
  2. \(target < root.\text{left}.\textbf{key}\) 则目标节点在左子树中;
  3. \(target > root.\text{right}.\text{key}\) 则目标节点在右子树中;
  4. 若访问到了空节点,则目标节点不存在。

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{search}(root, target) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ \text{FALSE} \\ 4: \ &\quad \textbf{if} \ target = root.\text{key} \ \textbf{then} \\ 5: \ &\quad\quad \textbf{return} \ \text{TRUE} \\ 6: \ &\quad \textbf{elseif} \ traget < root.\text{kty} \ \textbf{then} \\ 7: \ &\quad\quad \textbf{return} \ \text{search}(root.\text{left}, target) \\ 8: \ &\quad \textbf{else} \ \textbf{return} \ \text{search}(root.\text{right}, target) \\ \end{aligned} \]

定理 7 :BST 中插入 \(target\)

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{insert}(root, target) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ \text{newNode}(target) \\ 4: \ &\quad root.\text{size} \gets root.\text{size} + 1 \\ 5: \ &\quad \textbf{if} \ target = root.\text{key} \ \textbf{then} \\ 6: \ &\quad\quad root.\textbf{cnt} \gets root.\textbf{cnt} + 1 \\ 7: \ &\quad \textbf{elseif} \ target < root.\text{key} \ \textbf{then} \\ 8: \ &\quad\quad root.\text{left} \gets \text{insert}(root.\text{left}, target) \\ 9: \ &\quad \textbf{else} \\ 10: \ &\quad\quad root.\text{left} \gets \text{insert}(root.\text{right}, target) \\ 11: \ &\quad \textbf{return} \ root \\ \end{aligned} \]

定理 8 :BST 中删除 \(target\)

删除 \(target\) 之前需要先查询一遍其是否在 BST 中,否则删除失败需要回溯更新操作。

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{remove}(root, target) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ root \\ 4: \ &\quad root.\text{szie} \gets root.\text{szie} - 1 \\ 5: \ &\quad \textbf{if} \ target = root.\text{key} \ \textbf{then} \\ 6: \ &\quad\quad \textbf{if} \ root.\text{cnt} > 1 \ \textbf{then} \\ 7: \ &\quad\quad\quad root.\text{cnt} \gets root.\text{cnt} - 1 \\ 8: \ &\quad\quad \textbf{elseif} \ root.\text{left} \neq \text{NIL} \ \textbf{then} \\ 9: \ &\quad\quad\quad predecessor = \text{findMaxNode}(root.\text{left}) \\ 10: \ &\quad\quad\quad \text{swap}(root, predecessor) \\ 11: \ &\quad\quad\quad root.\text{left} = \text{remove}(root.\text{left}, predecessor.\text{key}) \\ 12: \ &\quad\quad \textbf{else} \\ 13: \ &\quad\quad\quad successor = \text{findMinNode}(root.\text{right}) \\ 14: \ &\quad\quad\quad \text{swap}(root, successor) \\ 15: \ &\quad\quad\quad root.\text{right} = \text{remove}(root.\text{right}, predecessor.\text{key}) \\ 16: \ &\quad \textbf{elseif} \ target < root.\text{key} \ \textbf{then} \\ 17: \ &\quad\quad root.\text{left} \gets \text{remove}(root.\text{left}, target) \\ 18: \ &\quad \textbf{else} \\ 19: \ &\quad\quad root.\text{right} \gets \text{remove}(root.\text{right}, target) \\ 20: \ &\quad \textbf{return} \ root \\ \end{aligned} \]

定理 9 :BST 中查询 \(target\) 的排名(排名从 1 开始)。

查询 \(target\) 的排名之前需要先查询一遍其是否在 BST 中,否则会返回错误排名。

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{SZ}(root) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ 0 \\ 4: \ &\quad \textbf{else} \ \textbf{return} \ root.\text{size} \\ \\ 1: \ &\text{queryRank}(root, target) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ 0 \\ 4: \ &\quad \textbf{if} \ target = root.\text{key} \ \textbf{then} \\ 5: \ &\quad\quad \textbf{return} \ \text{SZ}(root.\text{left}) + 1 \\ 6: \ &\quad \textbf{elseif} \ traget < root.\text{key} \ \textbf{then} \\ 7: \ &\quad\quad \textbf{return} \ \text{queryRank}(root.\text{left}, target) \\ 8: \ &\quad \textbf{else}\ \textbf{return} \ \text{SZ}(root.\text{left}) + \text{queryRank}(root.\text{right}, target) \\ \end{aligned} \]

定理 10 :BST 查询排名为 \(k\) 的节点。

实现

\[\hspace{-32em}\begin{aligned} 1: \ &\text{queryKth}(root, k) \\ 2: \ &\quad \textbf{if} \ root = \text{NIL} \ \textbf{then} \\ 3: \ &\quad\quad \textbf{return} \ NIL \\ 4: \ &\quad v \gets \text{SZ}(root.\text{left}) \\ 5: \ &\quad \textbf{if} \ k \leq v \ \textbf{then} \\ 6: \ &\quad\quad \textbf{return} \ \text{queryKth}(root.\text{ left} \\ 7: \ &\quad \textbf{elseif} \ k \leq v + root.\text{cnt} \ \textbf{then} \\ 8: \ &\quad\quad \textbf{return} \ root \\ 9: \ &\quad \textbf{else} \ \textbf{return} \ \text{queryKth}(root.\text{right}, k - v - root.\text{cnt}) \\ \end{aligned} \]

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询