是否总是可以使用树旋转将一个 BST 转换为另一个 BST?

2023-12-26

给定一组值,可能有许多不同的可能的二叉搜索树可以由这些值形成。例如,对于值 1、2 和 3,我们可以根据这些值得出五个 BST:

1      1      2      3      3
 \      \    / \    /      /
  2      3  1   3  1      2
   \    /           \    /
    3  2             2  1

许多基于平衡二叉搜索树的数据结构都使用树轮换 http://en.wikipedia.org/wiki/Tree_rotation作为重塑 BST 的原语,而不破坏所需的二叉搜索树不变量。树旋转可用于将节点拉到其父节点上方,如下所示:

                rotate
         u      right           v
        / \     ----->         / \
       v   C                  A   u
      / \       <-----           / \
     A   B      rotate          B   C
                 left

给定一个包含一组值的 BST,是否总是可以将该 BST 转换为同一组值的任意其他 BST?例如,我们是否可以仅通过使用树旋转将上述五个 BST 中的任何一个转换为任何其他 BST?


您问题的答案取决于 BST 中是否允许具有相同的值,但这些值可能彼此不同。例如,如果您的 BST 存储键/值对,则并不总是可以将这些键/值对的一个 BST 转换为相同键/值对的不同 BST。

原因是无论执行多少次树旋转,BST 中节点的中序遍历都保持不变。因此,如果节点的中序遍历结果不同,则不可能从一种 BST 转换为另一种 BST。作为一个非常简单的情况,假设您有一个 BST,其中包含数字 1 的两个副本,每个副本都用不同的值(例如 A 或 B)进行注释。在这种情况下,无法使用树旋转将这两棵树相互转换:

       1:a            1:b
         \             \
         1:b           1:a

您可以通过暴力强制您可以通过旋转创建的(非常小!)可能的树集来检查这一点。然而,只要注意到第一棵树的中序遍历给出 1:a, 1:b,第二棵树的中序遍历给出 1:b, 1:a。因此,任何旋转次数都不足以在树之间进行转换。

另一方面,如果所有值都不同,则始终可以通过应用正确的树旋转次数在两个 BST 之间进行转换。我将使用节点数量的归纳论证来证明这一点。

作为一种简单的基本情况,如果树中没有节点,则只有一个可能的 BST 保存这些节点:空树。因此,总是可以在两棵包含零个节点的树之间进行转换,因为起始树和结束树必须始终相同。

对于归纳步​​骤,我们假设对于具有相同值的 0, 1, 2, .., n 节点的任何两个 BST,总是可以使用旋转从一个 BST 转换为另一个。我们将证明,给定由相同的 n + 1 个值组成的任意两个 BST,总是可以将第一棵树转换为第二棵树。

为此,我们首先要进行一个关键的观察。给定 BST 中的任何节点,始终可以应用树旋转来将该节点拉到树的根。为此,我们可以应用以下算法:

while (target node is not the root) {
    if (node is a left child) {
        apply a right rotation to the node and its parent;
    } else {
        apply a left rotation to the node and its parent;
    }
}

这样做的原因是,每当一个节点与其父节点一起旋转时,它的高度就会增加一。因此,在对上述形式进行足够多次旋转后,我们可以将根到达树的顶部。

现在,这为我们提供了一种非常简单的递归算法,我们可以使用旋转将任何一个 BST 重塑为另一个 BST。想法如下。首先,查看第二棵树的根节点。在第一棵树中找到该节点(这非常简单,因为它是 BST!),然后使用上面的算法将其拉到树的根部。至此,我们已经将第一棵树变成了具有以下属性的树:

  1. 第一棵树的根节点是第二棵树的根节点。
  2. 第一棵树的右子树包含与第二棵树的右子树相同的节点,但可能具有不同的形状。
  3. 第一棵树的左子树包含与第二棵树的左子树相同的节点,但可能具有不同的形状。

因此,我们可以递归地应用相同的算法,使左子树与第二棵树的左子树具有相同的形状,并使右子树与第二棵树的右子树具有相同的形状。由于这些左子树和右子树的每个节点必须严格不超过 n 个,根据我们的归纳假设,我们知道总是可以做到这一点,因此算法将按预期工作。

总而言之,该算法的工作原理如下:

  1. 如果两棵树都是空的,我们就完成了。
  2. 在第一棵树中找到第二棵树的根节点。
  3. 应用旋转将该节点带到根节点。
  4. 递归地重塑第一棵树的左子树,使其具有与第二棵树的左子树相同的形状。
  5. 递归地重塑第一棵树的右子树,使其具有与第二棵树的右子树相同的形状。

To analyze the runtime of this algorithm, note that applying steps 1 - 3 requires at most O(h) steps, where h is the height of the first tree. Every node will be brought up to the root of some subtree exactly once, so we do this a total of O(n) times. Since the height of an n-node tree is never greater than O(n), this means that the algorithm takes at most O(n2) time to complete. It's possible that it will do a lot better (for example, if the two trees already have the same shape, then this runs in time O(n)), but this gives a nice worst-case bound.

希望这可以帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否总是可以使用树旋转将一个 BST 转换为另一个 BST? 的相关文章

  • Rust 中删除单链表中的节点

    我是 Rust 新手 想用 Rust 编写链表来获得乐趣 我对如何删除链表中的节点感到困惑 这是我的简单代码 derive Debug struct Node v usize next Option
  • Java:如何实现通用二叉搜索树?

    到目前为止 我一直在编写一个 Node 类 class Node private value private Node left private Node right public int getValue return value pub
  • 聚类算法采用哪种编程结构

    我正在尝试实现以下 分裂 聚类算法 下面是该算法的简短形式 完整的描述可用here https dl dropboxusercontent com u 540963 diana pdf 从样本 x i 1 n 开始 将其视为由 n 个数据点
  • 查找预排序数组中给定值的最低索引

    嘿 我在采访中遇到了这个问题 想知道解决它的最佳方法是什么 假设给定一个已经排序的数组 并且您想要找到某个值 x 的最低索引 这是我想出的 python 伪代码 我只是想知道是否有更好的方法来实现它 def findLowestIndex
  • STL 哈希函数

    STL 是否有公开公开的可用哈希函数 我知道有一些使用哈希值的非标准实现 例如boost hash map 并且MSVC8实现了hash map hash set 等的版本 但有没有哈希函数C 98 STL 中定义的 如果不是 可靠哈希函数
  • 排序数组最快的搜索方法是什么?

    正在回答另一个问题 https stackoverflow com questions 4752028 whats wrong with this interpolation search implementation 4752042 47
  • 如何有效地从连续字符串中提取文字单词? [复制]

    这个问题在这里已经有答案了 可能的重复 如何将没有空格的文本拆分为单词列表 https stackoverflow com questions 8870261 how to split text without spaces into li
  • 证明链表是循环的最快方法?在Python中[重复]

    这个问题在这里已经有答案了 有人可以让我知道证明链表包含循环的最佳方法吗 我正在使用一种带有两个指针的算法 一个指针缓慢移动一步 一个指针移动两步较快 class Node object def init self value next N
  • HashMap元素的顺序可以重现吗?

    首先 我想澄清的是 我永远不会使用 HashMap 来做需要某种数据结构顺序的事情 并且这个问题是出于我对 Java HashMap 实现的内部细节的好奇而提出的 您可以阅读java 文档上Object http docs oracle c
  • 迭代格雷码更改位置的有效方法

    有多种迭代方式n 位格雷码 https en wikipedia org wiki Gray code Constructing an n bit Gray code 有些比其他更有效率 但是 我实际上并不需要格雷码 而是想迭代格雷码列表中
  • 检测360度转弯算法

    我成功检测到手机绕轴的 0 360 度旋转 滚动 但现在我很难设计一种有效的算法来检测一整圈 我的工作但我认为不像我想要的那样优雅和有效的算法是 private boolean detectRoll private boolean chec
  • 执行快速 GPS 查找的数据结构?

    我有一个文本文件 UTF 8 约 50K 行 其中包含城市名称和 GPS 坐标 示例行 San Pedro locality 3367 5968 Argentina Buenos Aires San Pedro Talagante loca
  • 将矩形均匀分布在另一个矩形内所需的算法

    我正在寻找一种算法 可以帮助在较大的矩形内分配不同大小的矩形 同时最大限度地减少重叠 我研究过装箱算法 但它们似乎最小化了矩形之间的空间量 在我的例子中 所有被包装的物品都将是正方形 我想我想最大化所有正方形和外部矩形边界之间的距离 这是我
  • 矩阵行列式算法 C++

    我是编程新手 我一直在寻找一种找到矩阵行列式的方法 我在网上找到了这段代码 但我很难理解这里的算法 我对递归的基础没有问题 但继续和主循环我很难理解 非常感谢任何可以向我解释该算法的人 int determ int a MAX MAX in
  • 计算数组中共线的三元组的数量

    我被问到这个面试问题 C 算法 但不知道如何解决 给定一个包含 N 个不同点的笛卡尔坐标的数组 Arr N 计算三元组 Arr P Arr Q Arr R 的数量 使得 P 有任何想法吗 我可以为此使用什么算法 以下内容可能没有优化 但其复
  • 使用线段树求矩形并集的面积

    我试图了解可用于计算一组轴对齐矩形的并集面积的算法 我遵循的解决方案在这里 http tryalgo org en geometry 2016 06 25 union of rectangles http tryalgo org en ge
  • 绘制一个图,其中顶点之间的距离对应于边权重

    当我给他一个加权图和边权重顶点之间的点到顶点之间的距离 就像是 public ArrayOfCoordinatesForVertices super hyper algorithm weighted graph return foo 这通常
  • 哪种 C# 模型将序列化为具有动态属性名称的 JSON 对象,每个属性名称都有一个值列表列表?

    当我使用 Newtonsoft Json 序列化时 C 中的什么数据结构 集合会给我这样的结果 其中属性名称 data point1 是动态的并在运行时定义吗 data data point1 string string string st
  • 在 F# 中计算排列

    受此启发question https stackoverflow com questions 283561 extracting leaf paths from n ary tree in f and answer https stacko
  • 实施黑名单的最有效方法

    我开发了一个 Ip 过滤器 并猜测我如何使用任何类型的 esque 数据结构开发一个非常高效且快速的黑名单过滤器 我想做的很简单 每个传入 传出连接我都必须检查被阻止的 IP 列表 IP是分散的 内存使用应该是线性的 不依赖于阻止列表的数量

随机推荐

  • Microsoft SQL Server 2008 主键的含义

    主键的概念对于SQL Server数据库引擎有什么意义 我的意思不是在 ID 列上创建的聚集 非聚集索引 我的意思是约束对象 主键 存在与否有什么关系吗 备择方案 更改表添加主键聚集 更改表创建聚集索引 这有什么不同吗 一般来说 KEY 是
  • Python - Pyodbc 连接错误

    我正在尝试使用Python3 4连接到SQL Server数据库 这是适合我的代码 cnxn pyodbc connect DRIVER ODBC Driver 13 for SQL Server SERVER DESKTOP GDM2HQ
  • CSS 媒体查询有多慢?

    当我组织 CSS 时 我喜欢将相关样式保留在一起 页眉样式位于一个部分 页脚样式全部位于同一位置 等等 抱歉 OOCSS 拥护者 我最近一直在尝试针对较小 较大屏幕的媒体查询 为了与我的组织方案保持一致 我必须为代码的每个部分所针对的每个屏
  • 在 Win32 控制台应用程序中使用 ShutdownBlockRequestCreate

    阻止在 Windows 7 上运行的 Win32 控制台应用程序提前终止的正确方法是什么 Vista 推出后 有关方式发生了变化应用程序关闭 http msdn microsoft com en us library ms700677 28
  • R 中指定列数的矩阵的 rowsum

    我正在尝试获取 R 矩阵中某一行的列总和 但是 我不希望对整行进行求和 而只对指定数量的列进行求和 即在本例中对角线上方的所有列进行求和 我尝试过 sum 和 rowSums 函数 但它们要么给我奇怪的结果 要么给我错误消息 为了进行说明
  • 使用 jQuery / JavaScript 进行组合键

    我很好奇我如何使用我在这个问题底部编写的以下 jQuery 插件代码来实现关键组合 到目前为止 它的工作原理是它允许用户简单地通过执行正常的 jQuery 语法来创建按键命令 并为按键命令提供一个事件 如下所示 window jkey a
  • A延伸B;类型“Pick> & B”不可分配给类型“A”.ts(2322)

    这是错误还是我误解了打字稿的内容 示例代码如下 type Omit
  • JSP 模板可以在 Java 中使用吗?

    我对 JSP 还很陌生 到目前为止 处理流程似乎是首先运行 Java 然后填充 JSP 模板 我想知道是否有一种方法可以从 Java 内部使用 JSP 模板 我的意思是 假设我在类路径上有一个简单的 SimpleDiv jsp 模板 如下所
  • 使用 mocha 运行时,仍然收到 babel-plugin-syntax-dynamic-import 动态导入的语法错误

    所有 babel 模块 插件均位于最新版本的 babel v6 上 Mocha 版本为 v4 0 1 Setup babelrc presets stage 3 env targets browsers last 2 versions no
  • 如何在 WhatsApp 中一次性向多个号码发送消息?

    我正在尝试使用 Flutter 通过 WhatsApp 向多个电话号码发送消息 sendMessage async var number 201020402642 201030666895 var baseUrl https api wha
  • 动态链接和 jQuery Lightbox 问题:在 lightbox 中加载图像...完全难住了!

    我有一个可以动态创建照片库链接的功能 当单击缩略图时 该函数还会生成更大的图像作为 div 的背景图像 我想做的是第三个事件 如果用户单击 div 中的放大图像 jQuery Fancybox 会加载 div 中显示的图像的更大版本 问题是
  • 在 Android 上运行 docker

    在 Android 4 4 KitKat 中 Google 正在将 Linux 内核升级到 3 8 版 这是 Docker 所需的内核版本 我不知道 AUFS 部分 但有没有办法通过此更新在 Android 上运行 docker 容器 根据
  • 如何在 Rust 中指定链接器路径?

    我正在尝试将 Rust 程序与库声音库 http libsound io 我使用的是 Windows 并且可以下载 GCC 二进制文件 如果我将它放在与我的项目相同的文件夹中 我可以像这样链接它 link name libsoundio 1
  • C# 十六进制字符串到字节图像和过滤

    我需要一些帮助将十六进制字符串转换为图像 做了一些研究 我想到了这段代码 private byte HexString2Bytes string hexString int bytesCount hexString Length 2 byt
  • 使用 OAuth 和 PowerShell 更新 Azure DevOps Wiki 页面

    我正在尝试通过在 Azure DevOps 发布管道中创建新页面来自动创建发行说明使用其 Rest API 的 Azure DevOps wiki https learn microsoft com fr fr rest api azure
  • Flutter-图像选择器包:通过删除操作依次显示图像

    在我的 Flutter pr 项目中 我使用图像选择器 https pub dev packages image picker插件用于从 Android 移动图库中选择图像或使用相机捕获图像并逐个显示它们 并在每张图像下方显示删除图标 点击
  • 如何与 hadoop 2.x 并行运行 MapReduce 任务?

    我希望我的地图和减少任务并行运行 然而 尽管尝试了所有的技巧 它们仍然按顺序运行 我读自如何在 Elastic MapReduce 上的 Hadoop 2 4 0 中设置每个节点并发运行任务的精确最大数量 https stackoverfl
  • 错误:尝试添加已有父级的 SKNode

    我正在使用 Swift 3 和 SpriteKit 做一个游戏 我试图声明一个全局变量来在 GameScene 类的其余部分中使用它 但我不能 我做了什么 class GameScene SKScene let personaje SKSp
  • 如何在 Perl 中递归读取目录?

    我想递归地读出一个目录 以使用 Template Toolkit 打印 HTML 页面中的数据结构 但我一直在思考如何以易于阅读的形式保存路径和文件 我的想法是这样开始的 sub list dirs my rootPath my paths
  • 是否总是可以使用树旋转将一个 BST 转换为另一个 BST?

    给定一组值 可能有许多不同的可能的二叉搜索树可以由这些值形成 例如 对于值 1 2 和 3 我们可以根据这些值得出五个 BST 1 1 2 3 3 2 3 1 3 1 2 3 2 2 1 许多基于平衡二叉搜索树的数据结构都使用树轮换 htt