这道题给出一个乱序的搜索二叉树,并且已知里面有两个元素被交换了,要求把这个二叉树恢复成正确的二叉树。
如果正确的二叉树是:4,2,7,1,3,6,8. 如果中序遍历这棵树,则得到的一定是一个有序序列:1,2,3,4,6,7,8.
假如中序遍历得到的结果是:1,4,3,2,6,7,8. 本应该是递增的序列,出现了4->3,3->2这两对递减的节点。那么应该交换4和2
假如中序遍历得到的结果是:1,3,2,4,6,7,8. 本应该是递增的序列,出现了3->2一对递减的节点。那么应该交换2和3
所以这里需要三个指针,first,second分别表示第一个和最后一个错乱位置的节点,pre指向当前节点的中序遍历的前一个节点。这里用传统的中序遍历递归来做,不过再应该输出节点值的地方,换成了判断pre和当前节点值的大小,如果pre的大,若first为空,则将first指向pre指的节点,把second指向当前节点。这样中序遍历完整个树,若first和second都存在,则交换它们的节点值即可。
这种方法的空间复杂度是O(n)。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode *pre;
TreeNode *first;
TreeNode *second;
void recoverTree(TreeNode* root) {
inorder(root);
if(first != NULL && second != NULL)
swap(first->val, second->val);
}
void inorder(TreeNode* root){
if(root == NULL) return;
inorder(root->left);
if(pre == NULL) pre = root;
else {
if(root->val < pre->val){
if(!first) first = pre;
second = root;
}
pre = root;
}
inorder(root->right);
}
};
这道题要求是空间复杂度O(1),且二叉树的形状不能被破坏,所以最好用Morris遍历:
http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html
Morris方法用到了线索二叉树(threaded binary tree)的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱(predecessor)和后继节点(successor),只需要利用叶子节点中的左右空指针指向某种顺序遍历下的前驱节点或后继节点就可以了。
中序遍历步骤:
1. 如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。
2. 如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。
a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。
3. 重复以上1、2直到当前节点为空。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode* first = NULL, *second = NULL, *parent = NULL;
TreeNode *cur, *pre;
cur = root;
while(cur){
if(!cur->left){
if(parent && parent->val > cur->val){
if(!first) first = parent;
second = cur;
}
parent = cur;
cur = cur->right;
}else{
pre = cur->left;
while(pre->right && pre->right != cur)
pre = pre->right;
if(!pre->right){
pre->right = cur;
cur = cur->left;
}else{
pre->right = NULL;
if(parent->val > cur->val){
if(!first) first = parent;
second = cur;
}
parent = cur;
cur = cur->right;
}
}
}
if(first && second)
swap(first->val, second->val);
}
};