📜  交换一个BST的两个节点,更正BST

📅  最后修改于: 2021-05-24 21:41:38             🧑  作者: Mango

交换二叉搜索树(BST)的两个节点。修复(或纠正)BST。

Input Tree:
         10
        /  \
       5    8
      / \
     2   20

In the above tree, nodes 20 and 8 must be swapped to fix the tree.  
Following is the output tree
         10
        /  \
       5    20
      / \
     2   8

BST的有序遍历会生成一个排序数组。因此,一种简单的方法是将输入树的有序遍历存储在辅助数组中。排序辅助数组。最后,将辅助数组元素重新插入BST,并保持BST的结构不变。该方法的时间复杂度为O(nLogn),所需的辅助空间为O(n)。
我们可以在O(n)时间内解决此问题,并且只需遍历给定的BST即可。由于BST的有序遍历始终是一个有序数组,因此可以将问题简化为交换有序数组中两个元素的问题。我们需要处理两种情况:
1.交换的节点在BST的顺序遍历中不相邻。

For example, Nodes 5 and 25 are swapped in {3 5 7 8 10 15 20 25}. 
 The inorder traversal of the given tree is 3 25 7 8 10 15 20 5 

如果我们仔细观察,在有序遍历期间,我们发现节点7小于先前访问的节点25。这里保存了节点25(先前的节点)的上下文。同样,我们发现节点5小于前一个节点20。这次,我们保存了节点5(当前节点)的上下文。最后,交换两个节点的值。
2.交换的节点在BST的顺序遍历中相邻。

For example, Nodes 7 and 8 are swapped in {3 5 7 8 10 15 20 25}. 
  The inorder traversal of the given tree is 3 5 8 7 10 15 20 25 

与情况#1不同,此处仅存在一个点,该点的节点值小于先前的节点值。例如,节点7小于节点8。
怎么解决?我们将保持三个指针,第一,中间和最后。当我们找到当前节点值小于前一个节点值的第一个点时,我们用前一个节点更新第一个点,并用当前节点更新中间的点。当我们找到当前节点值小于先前节点值的第二点时,将使用当前节点更新最后一个点。在#2的情况下,我们将永远找不到第二点。因此,最后一个指针将不会更新。处理后,如果最后一个节点值为null,则两个BST的交换节点相邻
以下是给定代码的实现。

C++
// Two nodes in the BST's swapped, correct the BST.
#include 
#include 
  
/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct node
{
    int data;
    struct node *left, *right;
};
  
// A utility function to swap two integers
void swap( int* a, int* b )
{
    int t = *a;
    *a = *b;
    *b = t;
}
  
/* Helper function that allocates a new node with the
   given data and NULL left and right pointers. */
struct node* newNode(int data)
{
    struct node* node = (struct node *)malloc(sizeof(struct node));
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    return(node);
}
  
// This function does inorder traversal to find out the two swapped nodes.
// It sets three pointers, first, middle and last.  If the swapped nodes are
// adjacent to each other, then first and middle contain the resultant nodes
// Else, first and last contain the resultant nodes
void correctBSTUtil( struct node* root, struct node** first,
                     struct node** middle, struct node** last,
                     struct node** prev )
{
    if( root )
    {
        // Recur for the left subtree
        correctBSTUtil( root->left, first, middle, last, prev );
  
        // If this node is smaller than the previous node, it's violating
        // the BST rule.
        if (*prev && root->data < (*prev)->data)
        {
            // If this is first violation, mark these two nodes as
            // 'first' and 'middle'
            if ( !*first )
            {
                *first = *prev;
                *middle = root;
            }
  
            // If this is second violation, mark this node as last
            else
                *last = root;
        }
  
        // Mark this node as previous
        *prev = root;
  
        // Recur for the right subtree
        correctBSTUtil( root->right, first, middle, last, prev );
    }
}
  
// A function to fix a given BST where two nodes are swapped.  This
// function uses correctBSTUtil() to find out two nodes and swaps the
// nodes to fix the BST
void correctBST( struct node* root )
{
    // Initialize pointers needed for correctBSTUtil()
    struct node *first, *middle, *last, *prev;
    first = middle = last = prev = NULL;
  
    // Set the poiters to find out two nodes
    correctBSTUtil( root, &first, &middle, &last, &prev );
  
    // Fix (or correct) the tree
    if( first && last )
        swap( &(first->data), &(last->data) );
    else if( first && middle ) // Adjacent nodes swapped
        swap( &(first->data), &(middle->data) );
  
    // else nodes have not been swapped, passed tree is really BST.
}
  
/* A utility function to print Inoder traversal */
void printInorder(struct node* node)
{
    if (node == NULL)
        return;
    printInorder(node->left);
    printf("%d ", node->data);
    printInorder(node->right);
}
  
/* Driver program to test above functions*/
int main()
{
    /*   6
        /  \
       10    2
      / \   / \
     1   3 7  12
     10 and 2 are swapped
    */
  
    struct node *root = newNode(6);
    root->left        = newNode(10);
    root->right       = newNode(2);
    root->left->left  = newNode(1);
    root->left->right = newNode(3);
    root->right->right = newNode(12);
    root->right->left = newNode(7);
  
    printf("Inorder Traversal of the original tree \n");
    printInorder(root);
  
    correctBST(root);
  
    printf("\nInorder Traversal of the fixed tree \n");
    printInorder(root);
  
    return 0;
}


Java
// Java program to correct the BST 
// if two nodes are swapped
import java.util.*;
import java.lang.*;
import java.io.*;
  
class Node {
  
    int data;
    Node left, right;
  
    Node(int d) {
        data = d;
        left = right = null;
    }
}
  
class BinaryTree
{
    Node first, middle, last, prev;
      
    // This function does inorder traversal
    // to find out the two swapped nodes.
    // It sets three pointers, first, middle
    // and last. If the swapped nodes are
    // adjacent to each other, then first 
    // and middle contain the resultant nodes
    // Else, first and last contain the 
    // resultant nodes
    void correctBSTUtil( Node root)
    {
        if( root != null )
        {
            // Recur for the left subtree
            correctBSTUtil( root.left);
  
            // If this node is smaller than
            // the previous node, it's 
            // violating the BST rule.
            if (prev != null && root.data <
                                prev.data)
            {
                // If this is first violation,
                // mark these two nodes as
                // 'first' and 'middle'
                if (first == null)
                {
                    first = prev;
                    middle = root;
                }
  
                // If this is second violation,
                // mark this node as last
                else
                    last = root;
            }
  
            // Mark this node as previous
            prev = root;
  
            // Recur for the right subtree
            correctBSTUtil( root.right);
        }
    }
  
    // A function to fix a given BST where 
    // two nodes are swapped. This function 
    // uses correctBSTUtil() to find out 
    // two nodes and swaps the nodes to 
    // fix the BST
    void correctBST( Node root )
    {
        // Initialize pointers needed 
        // for correctBSTUtil()
        first = middle = last = prev = null;
  
        // Set the poiters to find out 
        // two nodes
        correctBSTUtil( root );
  
        // Fix (or correct) the tree
        if( first != null && last != null )
        {
            int temp = first.data;
            first.data = last.data;
            last.data = temp; 
        }
        // Adjacent nodes swapped
        else if( first != null && middle !=
                                    null ) 
        {
            int temp = first.data;
            first.data = middle.data;
            middle.data = temp;
        }
  
        // else nodes have not been swapped,
        // passed tree is really BST.
    }
  
    /* A utility function to print 
     Inoder traversal */
    void printInorder(Node node)
    {
        if (node == null)
            return;
        printInorder(node.left);
        System.out.print(" " + node.data);
        printInorder(node.right);
    }
  
  
    // Driver program to test above functions
    public static void main (String[] args) 
    {
        /*   6
            / \
           10  2
          / \ / \
         1  3 7 12
          
        10 and 2 are swapped
        */
  
        Node root = new Node(6);
        root.left = new Node(10);
        root.right = new Node(2);
        root.left.left = new Node(1);
        root.left.right = new Node(3);
        root.right.right = new Node(12);
        root.right.left = new Node(7);
  
        System.out.println("Inorder Traversal"+
                        " of the original tree");
        BinaryTree tree = new BinaryTree();
        tree.printInorder(root);
  
        tree.correctBST(root);
  
        System.out.println("\nInorder Traversal"+
                          " of the fixed tree");
        tree.printInorder(root);
    }
}
// This code is contributed by Chhavi


Python3
# Python3 program to correct the BST  
# if two nodes are swapped 
class Node: 
      
    # Constructor to create a new node 
    def __init__(self, data):
          
        self.key = data 
        self.left = None
        self.right = None
  
# Utility function to track the nodes
# that we have to swap
def correctBstUtil(root, first, middle,
                   last, prev):
                         
    if(root):
          
        # Recur for the left sub tree
        correctBstUtil(root.left, first,
                       middle, last, prev)
                         
        # If this is the first violation, mark these 
        # two nodes as 'first and 'middle'
        if(prev[0] and root.key < prev[0].key):
            if(not first[0]):
                first[0] = prev[0]
                middle[0] = root
            else:
                  
                # If this is the second violation,
                # mark this node as last
                last[0] = root
                  
        prev[0] = root
          
        # Recur for the right subtree
        correctBstUtil(root.right, first, 
                       middle, last, prev)
      
# A function to fix a given BST where 
# two nodes are swapped. This function
# uses correctBSTUtil() to find out two
# nodes and swaps the nodes to fix the BST 
def correctBst(root):
      
    # Followed four lines just for forming
    # an array with only index 0 filled 
    # with None and we will update it accordingly.
    # we made it null so that we can fill 
    # node data in them.
    first = [None]
    middle = [None]
    last = [None]
    prev = [None]
      
    # Setting arrays (having zero index only) 
    # for capturing the requird node
    correctBstUtil(root, first, middle,
                   last, prev)
  
    # Fixing the two nodes
    if(first[0] and last[0]):
          
        # Swapping for first and last key values
        first[0].key, last[0].key = (last[0].key, 
                                    first[0].key)
  
    elif(first[0] and middle[0]):
      
        # Swapping for first and middle key values
        first[0].key, middle[0].key = (middle[0].key,
                                        first[0].key)
      
    # else tree will be fine
  
# Function to print inorder
# traversal of tree
def PrintInorder(root):
      
    if(root):
        PrintInorder(root.left)
        print(root.key, end = " ")
        PrintInorder(root.right)
          
    else:
        return
  
# Driver code
  
#      6
#     /   \
#   10    2
#  / \   / \
# 1   3 7   12
  
# Following 7 lines are for tree formation
root = Node(6) 
root.left = Node(10) 
root.right = Node(2) 
root.left.left = Node(1) 
root.left.right = Node(3) 
root.right.left = Node(7) 
root.right.right = Node(12) 
  
# Printing inorder traversal of normal tree
print("inorder traversal of noraml tree")
PrintInorder(root)
print("")
  
# Function call to do the task
correctBst(root)
  
# Printing inorder for corrected Bst tree
print("")
print("inorder for corrected BST")
  
PrintInorder(root)
  
# This code is contributed by rajutkarshai


C#
// C# program to correct the BST 
// if two nodes are swapped
using System;
class Node{
  
public int data;
public Node left, right;
public Node(int d) 
{
  data = d;
  left = right = null;
}
}
  
class BinaryTree
{
  Node first, middle, 
       last, prev;
  
// This function does inorder traversal
// to find out the two swapped nodes.
// It sets three pointers, first, middle
// and last. If the swapped nodes are
// adjacent to each other, then first 
// and middle contain the resultant nodes
// Else, first and last contain the 
// resultant nodes
void correctBSTUtil( Node root)
{
  if( root != null )
  {
    // Recur for the 
    // left subtree
    correctBSTUtil(root.left);
  
    // If this node is smaller than
    // the previous node, it's 
    // violating the BST rule.
    if (prev != null && root.data <
        prev.data)
    {
      // If this is first violation,
      // mark these two nodes as
      // 'first' and 'middle'
      if (first == null)
      {
        first = prev;
        middle = root;
      }
  
      // If this is second violation,
      // mark this node as last
      else
        last = root;
    }
  
    // Mark this node 
    // as previous
    prev = root;
  
    // Recur for the
    // right subtree
    correctBSTUtil(root.right);
  }
}
  
// A function to fix a given BST where 
// two nodes are swapped. This function 
// uses correctBSTUtil() to find out 
// two nodes and swaps the nodes to 
// fix the BST
void correctBST( Node root )
{
  // Initialize pointers needed 
  // for correctBSTUtil()
  first = middle = last = 
          prev = null;
  
  // Set the poiters to 
  // find out two nodes
  correctBSTUtil(root);
  
  // Fix (or correct) 
  // the tree
  if(first != null && 
     last != null)
  {
    int temp = first.data;
    first.data = last.data;
    last.data = temp; 
  }
    
  // Adjacent nodes swapped
  else if(first != null && 
          middle != null) 
  {
    int temp = first.data;
    first.data = middle.data;
    middle.data = temp;
  }
  
  // else nodes have not been 
  // swapped, passed tree is 
  // really BST.
}
  
// A utility function to print 
// Inoder traversal 
void printInorder(Node node)
{
  if (node == null)
    return;
  printInorder(node.left);
  Console.Write(" " + node.data);
  printInorder(node.right);
}
  
// Driver code
public static void Main(String[] args) 
{
  /*         6
            / \
           10  2
          / \ / \
         1  3 7 12
  
        10 and 2 are swapped
        */
  
  Node root = new Node(6);
  root.left = new Node(10);
  root.right = new Node(2);
  root.left.left = new Node(1);
  root.left.right = new Node(3);
  root.right.right = new Node(12);
  root.right.left = new Node(7);
  
  Console.WriteLine("Inorder Traversal" +
                    " of the original tree");
  BinaryTree tree = new BinaryTree();
  tree.printInorder(root);
  tree.correctBST(root);
  Console.WriteLine("\nInorder Traversal" +
                    " of the fixed tree");
  tree.printInorder(root);
}
}
  
// This code is contributed by gauravrajput1


输出:

Inorder Traversal of the original tree
1 10 3 6 7 2 12
Inorder Traversal of the fixed tree
1 2 3 6 7 10 12