恢復一棵二叉查找樹

二叉搜索樹中有兩個節點的值被相互交換,還原一個正常的二叉搜索樹。

二叉搜索樹,中序遍歷,每次遍歷的值都會比上次遍歷的值小。根據中序遍歷的這個性質可以找到值錯誤的節點,用first表示上一次遍歷的節點,用second表示當前遍歷的節點,但是我們不能確定到底哪一個纔是錯誤的節點,繼續遍歷,如果接下來沒有發現錯誤的節點,則交換上次發現的兩個錯誤節點即可。如果接下來又發現了錯誤的節點,則說明現在遍歷的節點和first節點是錯誤節點,交換兩個節點的值。代碼如下:

public void recoverTree(TreeNode root) {
    //use inorder traversal to detect incorrect node

    inOrder(root);

    int temp = first.val;
    first.val = second.val;
    second.val = temp;
}

TreeNode prev = null;
TreeNode first = null;
TreeNode second = null;

public void inOrder(TreeNode root){
    if(root == null) return;
    //search left tree
    inOrder(root.left);

    //in inorder traversal of BST, prev should always have smaller value than current value
    if(prev != null && prev.val >= root.val){
        //incorrect smaller node is always found as prev node
        if(first == null) first = prev;
      //incorrect larger node is always found as curr(root) node
        second = root;
    }


    //update prev node
    prev = root;

    //search right tree
    inOrder(root.right);
}

基於morris中序遍歷的恢復。O(1)的空間。

public void recoverTree(TreeNode root) {
    //Morris-traversal

    TreeNode first = null;
    TreeNode second = null;

    TreeNode pred = null; //rightmost node in left tree
    TreeNode prev = null; 

    TreeNode curr = root;

    while(curr != null){
        //for each node, we compare it with prev node as we did in in-order-traversal
        if(prev != null && curr.val <= prev.val){
            if(first == null) first = prev;
            second = curr;
        }

        if(curr.left != null){
            //got left tree, then let's locate its rightmost node in left tree
            pred = curr.left;
            //we may have visited the left tree before, and connect the rightmost node with curr node (root node)
            while(pred.right != null && pred.right != curr){
                pred = pred.right;
            }

            if(pred.right == curr){
                //if this left tree has been visited before, then we are done with it
                //cut the connection with currNode and start visit curr's right tree
                pred.right = null;
                prev = curr;
                curr = curr.right;
            }else{
                //if this left tree has not been visited before, then we create a back edge from rightmost node
                // to curr node, so we can return to the start point after done the left tree
                pred.right = curr;
                curr = curr.left;
            }

        }else{
            //no left tree, then just visit its right tree
            prev = curr;
            curr = curr.right;
        }
    }

    int temp = first.val;
    first.val = second.val;
    second.val = temp;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章