繁体   English   中英

检查两个二叉搜索树是否具有相同的中序遍历

[英]Check two binary search trees have the same in-order traversal

检查两个二叉搜索树是否具有相同的中序遍历。 我天真的方法是按顺序遍历给定的两棵树,并将每个元素分别复制到一个数组中,然后检查这两个数组是否相同。 但是我觉得我们应该能够将一棵树中的元素复制到一个数组中,然后使用该数组来动态验证另一棵树,而不是使用两个数组。 或者更好的是,可能有一种方法可以在不使用任何数组的情况下做到这一点。 我的代码如下,不确定我对 hasSameInOrder() 的实现是否正确。 或者我们可以在不使用任何数组的情况下做到这一点吗? 请注意,具有相同中序遍历的两棵树意味着如果在中序遍历时将元素复制到数组中,则两个结果数组应具有相同的值。 因此,它们不一定具有相同的结构以具有相同的有序遍历。

public boolean checkTwoBSTHaveSameInOrder(Node n1, Node n2) {
   LinkedList<Node> queue = new LinkedList<Node>();
   inOrder(n1, buffer);
   hasSameInOrder(n2, queue)
   return queue==null? false: true;
}
public void inOrder(Node node, LinkedList<Node> queue) {
   if (node==null)
       return;
   inOrder(node.left, queue);
   queue.add(node);
   inOrder(node.right, queue);
}
public void hasSameInOrder(Node node, LinkedList<Node> queue) {
   if (node==null)
      return;
   hasSameInOrder(n2.left, queue));
   if (queue==null)
      return;
   else {
      if (node!=queue.poll())
           queue=null;
   }
   hasSameInOrder(n2.right, queue));
} 

在两个树的中序遍历的迭代实现中使用单个循环。您将需要添加两个堆栈(读取队列)来跟踪匹配。 显然,这不会改善不可能更好的最坏情况渐近时间,但现有方法确保在随机一对树上获得合理的时间增益。

您可以按以下方式使用单个数组:-

int count =0;
int[] arr;

void inorder(node*p) {

  if(p!=null) {

       inorder(p->left);
       arr[count++] = p->data;
       inorder(p->right);
  }  

}

int c2 =0;
boolean checkSame(node*p,int[] arr) {

    if(p!=null) {
       boolean t = true;  
       t = checkSame(p->left,arr);
       if(c2+1>=count||arr[c2++]!=p->data) {

           return(false);  
       } 
       return(t&&checkSame(p->right,arr));

    }

}

如果我们可以重构树,那么将两棵树都转换为左偏或右偏的格式,然后在单个遍历偏斜树中进行比较

否则,我们可以通过仅将一棵树转换为倾斜格式并在对其他树进行中序遍历的同时进行比较来避免成本。

是的,有一种方法可以在不使用数组的情况下做到这一点。 我们可以使用线程来实现它。 我们可以使用wait() 和notify() 在线程之间进行交互。 在不同线程中的两棵树中触发递归中序遍历。 读取一棵树中的第一个元素并等待另一棵树读取其第一个元素。 比较这些元素并继续处理剩余的元素。 您可以按照以下示例代码进行操作。

//common lock for both threads
Object lock = new Object();

// flag to check if traverseFirstTree can come out of wait or not
boolean proceedFirst = false;

// flag to check if traverseSecondTree can come out of wait or not
boolean proceedSecond = false;

//value of current element in second BinarySearchTree
int element;

boolean identicalInorderOrNot(BST bst1, BST bst2){
  //check if no. of elements in both are same. If not return false
  if (bst1.size() != bst2.size()){
    return false;
  } 
  Thread thread = new Thread (new Runnable(){
    void run(){
      traverseSecondTree(bst2);
    }
  });
  //it does not matter if traverseSecondTree gets executed before traverseFirstTree(), as we have check for this condition
  thread.start()
  return traverseFirstTree(bst1);
}

private boolean traverseFirstTree(BST node){
  if(bst1 == null){
    return true;
  }
  if (!traverseFirstTree(node.left)){
    return false;
  }
  synchronized(lock){
    proceedFirst = false;
    while (!proceedFirst){
      proceedSecond = true;
      wait();
    }
  notify()
  }
  //check if root data of bst1 is same as current element of bst2
  if (node.data != element){
    return false;
  }
  return traverseFirstTree(node.right)
}

private void traverseSecondTree(BST node){
  if (node ==  null){
    return true;
  }
  traverseSecondTree(node.left)
  synchronized(lock){
    while (!proceedSecond){
      wait();
    }
    element = node.data;
    proceedFirst = true;
    proceedSecond = false;
    notify();

  traverseSecondTree(node.right)
}

我们可以在更好的空间复杂度 O(1) 中做到这一点我们可以使用 Morris Traversal 遍历树并逐个元素比较值。

对于下面的实现,我假设两棵树都有相同数量的节点。

  bool isSame(root1, root2){
    while(root1!=null && root2!=null){
        while(root1->left!=NULL){
            auto maxleft = getmaxnode(root1->left);
            maxleft->right = root1;
            auto next = root1->left;
            root1->left = NULL;
            root1 = next;
        }
        while(root2->left!=NULL){
            auto maxleft = getmaxnode(root2->left);
            maxleft->right = root2;
            auto next = root2->left;
            root2->left = NULL;
            root2 = next;
        }
        if(root1->val != root2->val) return false;
    }
    return true;
}

有两棵树,它们的顺序如下

  1. InOrder 函数 tree1 将填充队列
  2. CheckInOrder 函数会将值与第二棵树进行比较
  3. 如果不匹配返回 false
    /*
      Tree 1           Tree 2
         5                3
        / \              / \
       3   7            1   6
      /   /                / \
     1   6                5   7
    [1,3,5,6,7]      [1,3,5,6,7]
    */
    
    #include <iostream>
    #include <queue>
    
    using namespace std;
    
    struct NODE {
        NODE() {
            val = 0;
            left = NULL;
            right = NULL;
        }
    
        NODE(int n) {
            val = n;
            left = NULL;
            right = NULL;
        }
        int val;
        NODE* left;
        NODE* right;
    };
    
    void InOrder(NODE* root, queue<int>& q)
    {
        if (root == NULL)
            return;

        InOrder(root->left, q);
        q.push(root->val);
        InOrder(root->right, q);
    }
        
    bool CheckInOrder(NODE* root, queue<int>& q)
    {
        if (root == NULL)
            return true;
        if (!CheckInOrder(root->left, q))
            return false;
        if (!q.empty() && root->val == q.front())
            q.pop();
        else
            return false;
    
        return CheckInOrder(root->right, q);
    }
    
    int main()
    {
        NODE* tree1;
        NODE* tree2;
        queue<int> tq;
    
        tree1 = new NODE(5);
        tree1->left = new NODE(3);
        tree1->right = new NODE(7);
        tree1->left->left = new NODE(1);
        tree1->right->left = new NODE(6);
    
        tree2 = new NODE(3);
        tree2->left = new NODE(1);
        tree2->right = new NODE(6);
        tree2->right->left = new NODE(5);
        tree2->right->right = new NODE(7);
    
        InOrder(tree1, tq);
        if (CheckInOrder(tree2, tq) && tq.empty())
            cout << "TRUE";
        else
            cout << "FALSE";
    }

暂无
暂无

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

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