恢复二叉搜索树的基础知识与原理
在讨论如何恢复二叉搜索树之前,我们需要先了解二叉搜索树(Binary Search Tree,简称BST)的一些基本概念。二叉搜索树是一种特殊的二叉树,其中每个节点都有以下性质:
- 对于任意节点
Node
,其左子树上所有节点的值都小于Node
的值。 - 其右子树上所有节点的值都大于
Node
的值。
中序遍历与二叉搜索树的性质
二叉搜索树的一个重要性质是,如果对其进行中序遍历(Inorder Traversal),即按照“左子树 -> 根节点 -> 右子树”的顺序遍历所有节点,得到的序列是升序排列的。
恢复二叉搜索树的思路
给定一棵二叉搜索树,其中恰好有两个节点的值被错误地交换了,导致整个树不再满足BST的性质。我们的任务是找出这两个节点并将其交换回来,使得树再次成为合法的二叉搜索树。
因为中序遍历能够产生一个升序排列的序列,所以我们可以通过中序遍历来检查这个序列是否有序。一旦发现不符合升序排列的部分,就可以确定是这两个节点的位置出了问题。
中序遍历中出现的错误情况分析
假设我们通过中序遍历得到了一个错误的序列。我们可以用以下思路来恢复树:
- 遍历中第一次发现逆序对时,可以确定较大的节点是第一个错误节点(
i
)。 - 遍历中第二次发现逆序对时,可以确定较小的节点是第二个错误节点(
j
)。
特别情况:有时两个错误节点可能是相邻的。在这种情况下,我们只会发现一次逆序对,这时第一个错误节点(
i
)是较大的节点,第二个错误节点(j
)是较小的节点。
- 交换这两个节点的值,就可以恢复这棵树。
举个简单的例子:
假设有这样一棵二叉搜索树:
3
/ \
1 4
/
2
正常情况下,按照中序遍历,应该得到序列 [1, 2, 3, 4]
,但由于节点值 2
和 3
被错误地交换了,实际得到的序列是 [1, 3, 2, 4]
。
步骤:
- 首先,中序遍历到
1
,没有问题。 - 接着,遍历到
3
,仍然没问题。 - 当遍历到
2
时,发现3 > 2
,这是第一个也是唯一的逆序对,确定3
是第一个错误节点(i
),2
是第二个错误节点(j
)。
此时,我们只需要交换3
和2
,恢复成正确的树结构:
2
/ \
1 4
/
3
中序遍历得到的序列为[1, 2, 3, 4]
,树恢复正常。
代码实现
下面是C++代码的实现:
class Solution {
public:
TreeNode* pre = nullptr;
TreeNode* i = nullptr;
TreeNode* j = nullptr;
void dfs(TreeNode* root) {
if (!root) return;
dfs(root->left);
if (pre && pre->val > root->val) {
if (!i) i = pre;
j = root;
}
pre = root;
dfs(root->right);
}
void recoverTree(TreeNode* root) {
dfs(root);
if (i && j) swap(i->val, j->val);
}
};
总结
这道题的关键在于理解二叉搜索树的性质和中序遍历的特性,通过检测逆序对来找到被错误交换的两个节点,进而将其恢复。这种思路能够覆盖所有可能的错误节点排列情况,并且实现起来也相对简单,是解决这类问题的有效方法。