简体   繁体   English

如何在二叉搜索树中找到交换节点?

[英]How to find swapped nodes in a binary search tree?

This is an interview Question.这是一道面试题。

A binary search tree is given and the values of two nodes have been swapped.给出了一个二叉搜索树并且两个节点的值已经交换。 The question is how to find both the nodes and the swapped values in a single traversal of the tree?问题是如何在树的单次遍历中找到节点和交换的值?

i have tried to solve this using below code but i am not able to stop the recursion so i am getting segmentation fault.我试图使用下面的代码解决这个问题,但我无法停止递归,所以我遇到了分段错误。 help me how to stop recursion.帮助我如何停止递归。

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdlib.h>

 /* A binary tree node has data, pointer to left child
 and a pointer to right child */
 struct node
{
 int data;
 struct node* left;
 struct node* right;
};
/* 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);
 }
void modifiedInorder(struct node *root, struct node **nextNode)
 {
    static int nextdata=INT_MAX;
    if(root)
    {       
        modifiedInorder(root->right, nextNode);
        if(root->data > nextdata)
        return;
        *nextNode = root;
        nextdata = root->data;

        modifiedInorder(root->left, nextNode);          
    }
}

void inorder(struct node *root, struct node *copyroot, struct node **prevNode)
{
    static int prevdata = INT_MIN; 
    if(root)
    {
        inorder(root->left, copyroot, prevNode);
        if(root->data < prevdata)
        {
            struct node *nextNode = NULL;
            modifiedInorder(copyroot, &nextNode);

            int data = nextNode->data;
            nextNode->data = (*prevNode)->data;
            (*prevNode)->data = data;
            return;
        }
        *prevNode = root;
        prevdata = root->data;
        inorder(root->right, copyroot, prevNode);           
    }
}

/* Given a binary tree, print its nodes in inorder*/
void printInorder(struct node* node)
{
    if (node == NULL)
        return;

    /* first recur on left child */
    printInorder(node->left);

    /* then print the data of node */
    printf("%d ", node->data);

    /* now recur on right child */
    printInorder(node->right);
}


int main()
{
    /*   4
        /  \
       2    3
      / \
     1   5
    */

    struct node *root = newNode(1);  // newNode will return a node.
    root->left        = newNode(2);
    root->right       = newNode(3);
    root->left->left  = newNode(4);
    root->left->right = newNode(5);
    printf("Inorder Traversal of the original tree\n ");
    printInorder(root);

    struct node *prevNode=NULL;
    inorder(root, root, &prevNode);

    printf("\nInorder Traversal of the fixed tree \n");
    printInorder(root);

    return 0;

}

Walk to the tree using inorder traversal.使用中序遍历走到树。 By using that you will get all the elements sorted and the one element that will be greater than the surrounding elements is swapped.通过使用它,您将对所有元素进行排序,并交换比周围元素大的一个元素。

For example consider this below binary tree例如考虑下面的二叉树

          _  20  _
         /         \
      15             30
     /   \         /   \ 
   10    17      25     33
  / |   /  \    /  \    |  \
9  16  12  18  22  26  31  34

First, we linearize this into an array and we get首先,我们将其线性化为一个数组,我们得到

9 10 16 15 12 17 18 20 22 25 26 30 31 33 34 9 10 16 15 12 17 18 20 22 25 26 30 31 33 34

Now you can notice that 16 is greater than its surrounding elements and that 12 is less than them.现在您可以注意到 16 大于其周围的元素,而 12 小于它们。 This immediately tells us that 12 and 16 were swapped.这立即告诉我们 12 和 16 交换了。

The following function validates if a tree is BST or not by recursively iterating both left and right subtrees while tightening the bounds.以下函数通过在收紧边界的同时递归迭代左右子树来验证树是否为 BST。

I believe it can be modified to achieve the above task by我相信可以通过修改它来实现上述任务

  1. Instead of returning false, return temp ie pointer to node which fails the tree from being BST.不是返回false,而是返回temp,即指向使树从BST 失败的节点的指针。
  2. There would be two such instances which gives both the swapped values.将有两个这样的实例给出两个交换值。

EDIT: We would need to distinguish between recursive function returning true vs pointer to node which is swapped编辑:我们需要区分递归函数返回 true 与指向交换节点的指针

This assumes that there are only two such values as mentioned in the problem definition这假设问题定义中提到的只有两个这样的值

bool validate_bst(tnode *temp, int min, int max)
{
        if(temp == NULL)
                return true;

        if(temp->data > min && temp->data < max)
        {
                if( validate_bst(temp->left, min, temp->data) && 
                    validate_bst(temp->right, temp->data, max) )
                        return true;
        }

        return false;
}

The main would call above api like this主要会像这样调用上面的api

   validate_bst(root, -1, 100); // Basically we pass -1 as min and 100 as max in
                                     // this instance

We can solve this in O(n) time and with a single traversal of the given BST.我们可以在 O(n) 时间内解决这个问题,并且只需遍历给定的 BST。 Since inorder traversal of BST is always a sorted array, the problem can be reduced to a problem where two elements of a sorted array are swapped.由于 BST 的中序遍历始终是排序数组,因此问题可以简化为排序数组的两个元素交换的问题。 There are two cases that we need to handle:我们需要处理两种情况:

      6 
    /  \ 
   10    2 
  / \   / \ 
 1   3 7  12 

1. The swapped nodes are not adjacent in the inorder traversal of the BST. 1.交换节点在BST的中序遍历中不相邻。

For example, Nodes 10 and 2 are swapped in {1 10 3 6 7 2 12}.例如,节点 10 和 2 在 {1 10 3 6 7 2 12} 中交换。 The inorder traversal of the given tree is 1 10 3 6 7 2 12给定树的中序遍历是 1 10 3 6 7 2 12

If we observe carefully, during inorder traversal, we find node 3 is smaller than the previous visited node 10. Here save the context of node 10 (previous node).如果仔细观察,在中序遍历过程中,我们发现节点3比上一个访问过的节点10小。这里保存节点10(上一个节点)的上下文。 Again, we find that node 2 is smaller than the previous node 7. This time, we save the context of node 2 ( current node ).再次,我们发现节点 2 比之前的节点 7 小。这一次,我们保存了节点 2(当前节点)的上下文。 Finally swap the two node's values.最后交换两个节点的值。

2. The swapped nodes are adjacent in the inorder traversal of BST. 2.交换节点在BST的中序遍历中是相邻的。

      6 
    /  \ 
   10    8 
  / \   / \ 
 1   3 7  12 

For example, Nodes 10 and 2 are swapped in {1 10 3 6 7 8 12}.例如,节点 10 和 2 在 {1 10 3 6 7 8 12} 中交换。 The inorder traversal of the given tree is 1 10 3 6 7 8 12 Unlike case #1, here only one point exists where a node value is smaller than previous node value.给定树的中序遍历是 1 10 3 6 7 8 12 与情况 #1 不同,这里只存在一个节点值小于前一个节点值的点。 eg node 10 is smaller than node 36.例如,节点 10 小于节点 36。

/**
 * 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 recoverTreeUtil(TreeNode *root, TreeNode **first, TreeNode **middle, TreeNode **last, TreeNode **prev) {
        if (root) {
            recoverTreeUtil(root->left, first, middle, last, prev);
            if (*prev && (*prev)->val > root->val) {
                if (!(*first)) {
                    *first = *prev;
                    *middle = root;
                } else *last = root;
            }
            *prev = root;
            recoverTreeUtil(root->right, first, middle, last, prev);
        }
    }
    void recoverTree(TreeNode* root) {
        TreeNode *first, *middle, *last, *prev;
        first = middle = last = prev = nullptr;
        recoverTreeUtil(root, &first, &middle, &last, &prev);
        if (first && last) swap(first->val, last->val);
        else if (first && middle) swap(first->val, middle->val);
    }
};

I found another solution to this questions on Geeksforgeeks.com ..............guys u can look into this thread for more explanation of below code http://www.geeksforgeeks.org/archives/23616我在 Geeksforgeeks.com 上找到了这个问题的另一种解决方案.........伙计们,你可以查看这个线程以获得对以下代码的更多解释http://www.geeksforgeeks.org/archives/ 23616

// Two nodes in the BST's swapped, correct the BST.
#include <stdio.h>
#include <stdlib.h>

/* 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;
}
Output:

 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
 Time Complexity: O(n)

For more test cases please refer to this link http://ideone.com/uNlPx更多测试案例请参考此链接http://ideone.com/uNlPx

My C++ Solution:我的 C++ 解决方案:

struct node *correctBST( struct node* root )
{
//add code here.
    if(!root)return root;
    struct node* r = root;
    stack<struct node*>st;
   // cout<<"1"<<endl;
    struct node* first = NULL;
    struct node* middle = NULL;
    struct node* last = NULL;
    struct node* prev = NULL; 
    while(root  || !st.empty()){
        while(root){
            st.push(root);
            root = root->left;
        }
        root = st.top();
        st.pop();
        if(prev && prev->data > root->data){
            if(!first){
                first = prev;
                middle = root;
            }
            else{
                last = root;
            }
        }
        prev = root;
        root = root->right;
    }
    if(first && last){
        swap(first->data,last->data);
    }
    else{
        swap(first->data,middle->data);
    }
    return r;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM