检查二叉树是镜像还是对称

时间:2011-12-08 19:38:16

标签: algorithm language-agnostic data-structures binary-tree

测试树是否对称的基础算法是什么?因为它是一个二叉树,我认为它将是一个递归的排序

正式问题如下:

如果二进制树的左右子树是相同的镜像,即二叉树是对称的,则它是自身的镜像。 最好用几个例子来解释。

  1
 / \
2   2

TRUE

   1
  / \
 2   2
  \
   3

FALSE

     1
   /   \
  2     2
 / \   / \
4   3 3   4

TRUE

       1
     /   \
    2     2 
   / \   / \
  3   4 3   4

FALSE

       1
     /   \
    2     2
   /       \
  3         3

TRUE

在选择的编程语言中,定义BTree类/ C结构和相关方法以检查树是否为镜像。对于静态类型语言,您可以假设节点值都是整数。

Class/structure definition
BTree {
  BTree left;
  BTree right;
  int value;
}

假设调用者跟踪树的根,并在其上调用函数isMirror()。

另外,如果定义一个类,如果数据元素不可公开访问,请确保提供无参数构造函数和getter / setter方法。

16 个答案:

答案 0 :(得分:104)

如何在以下函数上调用mirrorEquals(root.left,root.right): -

boolean mirrorEquals(BTree left, BTree right) {
  if (left == null || right == null) return left == null && right == null;
  return left.value == right.value
     && mirrorEquals(left.left, right.right)
     && mirrorEquals(left.right, right.left);
}

基本上比较左子树和反右子树,在根上绘制一条假想的反转线。

答案 1 :(得分:9)

解决方案1 ​​ - 递归:

bool isMirror(BinaryTreeNode *a, BinaryTreeNode *b)
{
    return (a && b) ?  
        (a->m_nValue==b->m_nValue 
        && isMirror(a->m_pLeft,b->m_pRight) 
        && isMirror(a->m_pRight,b->m_pLeft)) :  
    (a == b);
}
bool isMirrorItselfRecursively(BinaryTreeNode *root) 
{
    if (!root)
        return true;

    return isMirror(root->m_pLeft, root->m_pRight);
}

解决方案2 - 迭代地:

bool isMirrorItselfIteratively(BinaryTreeNode *root) 
{
    /// use single queue
    if(!root) return true;
    queue<BinaryTreeNode *> q;
    q.push(root->m_pLeft);
    q.push(root->m_pRight);
    BinaryTreeNode *l, *r;
    while(!q.empty()) {
        l = q.front();
        q.pop();
        r = q.front();
        q.pop();
        if(l==NULL && r==NULL) continue;
        if(l==NULL || r==NULL || l->m_nValue!=r->m_nValue) return false;
        q.push(l->m_pLeft);
        q.push(r->m_pRight);
        q.push(l->m_pRight);
        q.push(r->m_pLeft);
    }

    return true;
}

答案 2 :(得分:5)

Java中的递归和迭代解决方案使用上面讨论的方法

递归

public Boolean isSymmetric(TreeNode root) {
    if (root == null) {
        return true;
    }

    return isSymmetricInternal(root.left, root.right);
}

private Boolean isSymmetricInternal(TreeNode leftNode,
        TreeNode rightNode) {

    boolean result = false;

    // If both null then true
    if (leftNode == null && rightNode == null) {
        result = true;
    }

    if (leftNode != null && rightNode != null) {
        result = (leftNode.data == rightNode.data)
                && isSymmetricInternal(leftNode.left, rightNode.right)
                && isSymmetricInternal(leftNode.right, rightNode.left);
    }

    return result;
}

迭代使用 LinkedList 作为队列

private Boolean isSymmetricRecursive(TreeNode root) {
    boolean result = false;

    if (root == null) {
        return= true;
    }

    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root.left);
    queue.offer(root.right);

    while (!queue.isEmpty()) {
        TreeNode left = queue.poll();
        TreeNode right = queue.poll();

        if (left == null && right == null) {

            result = true;

        }
        else if (left == null || 
                right == null || 
                left.data != right.data) {
            // It is required to set result = false here
            result = false;
            break;
        }

        else if (left != null && right != null) {
            queue.offer(left.left);
            queue.offer(right.right);

            queue.offer(left.right);
            queue.offer(right.left);
        }
    }

    return result;
}

测试用例

    @Test
public void testTree() {

    TreeNode root0 = new TreeNode(1);
    assertTrue(isSymmetric(root0));
    assertTrue(isSymmetricRecursive(root0));

    TreeNode root1 = new TreeNode(1, new TreeNode(2), new TreeNode(2));
    assertTrue(isSymmetric(root1));
    assertTrue(isSymmetricRecursive(root1));

    TreeNode root2 = new TreeNode(1,
            new TreeNode(2, null, new TreeNode(3)), new TreeNode(2));
    assertFalse(isSymmetric(root2));
    assertFalse(isSymmetricRecursive(root2));

    TreeNode root3 = new TreeNode(1, new TreeNode(2, new TreeNode(4),
            new TreeNode(3)), new TreeNode(2, new TreeNode(3),
            new TreeNode(4)));
    assertTrue(isTreeSymmetric(root3));
    assertTrue(isSymmetricRecursive(root3));

    TreeNode root4 = new TreeNode(1, new TreeNode(2, new TreeNode(3),
            new TreeNode(4)), new TreeNode(2, new TreeNode(3),
            new TreeNode(4)));
    assertFalse(isSymmetric(root4));
    assertFalse(isSymmetricRecursive(root4));
}

树节点

public class TreeNode {

int data;

public TreeNode left;
public TreeNode right;

public TreeNode(int data){
    this(data, null, null);
}

public TreeNode(int data, TreeNode left, TreeNode right)
{
    this.data = data;
    this.left = left;
    this.right = right;
}
}

答案 3 :(得分:4)

来自@gvijay的递归解决方案非常清楚,这是一个迭代解决方案。

从上到下检查树的每一行,看看这些值是否为回文。如果他们都是,那么,这是一面镜子。您需要实现一个算法来访问每一行,并为稀疏树包含空值。在伪代码中:

boolean isMirror(BTree tree) {
  foreach (List<Integer> row : tree.rows() {
    if (row != row.reverse()) return false;
  }
  return true;
}

诀窍是设计算法迭代树的行,同时考虑到稀疏树应该具有空值作为占位符。这个Java实现似乎没问题:

public static boolean isMirror(BTree root) {
  List<BTree> thisRow, nextRow;
  thisRow = Arrays.asList(root);
  while (true) {
    // Return false if this row is not a palindrome.
    for (int i=0; i<thisRow.size()/2; i++) {
      BTree x = thisRow.get(i);
      BTree y = thisRow.get(thisRow.size()-i-1);
      if ((x!=null) && (y!=null)
          && (x.value != y.value))
        return false;
      if (((x==null) && (y!=null))
          || (x!=null) && (y==null))
        return false;
    }
    // Move on to the next row.
    nextRow = new ArrayList<BTree>();
    for (BTree tree : thisRow) {
      nextRow.add((tree==null) ? null : tree.lt);
      nextRow.add((tree==null) ? null : tree.rt);
    }
    boolean allNull = true;
    for (BTree tree : nextRow) {
      if (tree != null) allNull = false;
    }
    // If the row is all empty then we're done.
    if (allNull) return true;
    thisRow = nextRow;
  }
}

答案 4 :(得分:2)

修改

正如评论中指出的那样,我的第一个算法版本对某些输入失败了。我不打算重新发明轮子,我只是使用@gvijay正确算法提供Python答案。首先,二叉树的表示:

class BTree(object):
    def __init__(self, l, r, v):
        self.left  = l
        self.right = r
        self.value = v
    def is_mirror(self):
        return self._mirror_equals(self.left, self.right)
    def _mirror_equals(self, left, right):
        if left is None or right is None:
            return left is None and right is None
        return (left.value == right.value
                and self._mirror_equals(left.left, right.right)
                and self._mirror_equals(left.right, right.left))

我使用问题中的所有样本树测试了上面的代码,这些树返回了错误的结果,如评论中所述。现在结果对所有情况都是正确的:

root1 = BTree(
    BTree(None, None, 2),
    BTree(None, None, 2),
    1)
root1.is_mirror() # True

root2 = BTree(
    BTree(None, BTree(None, None, 3), 2),
    BTree(None, None, 2),
    1)
root2.is_mirror() # False

root3 = BTree(
    BTree(
        BTree(None, None, 4),
        BTree(None, None, 3),
        2),
    BTree(
        BTree(None, None, 3),
        BTree(None, None, 4),
        2),
    1)
root3.is_mirror() # True

root4 = BTree(
    BTree(
        BTree(None, None, 3),
        BTree(None, None, 4),
        2),
    BTree(
        BTree(None, None, 3),
        BTree(None, None, 4),
        2),
    1)
root4.is_mirror() # False

root5 = BTree(
    BTree(BTree(None, None, 3), None, 2),
    BTree(None, BTree(None, None, 3), 2),
    1)
root5.is_mirror() # True

root6 = BTree(BTree(None, None, 1), None, 1)
root6.is_mirror() # False

root7 = BTree(BTree(BTree(None, None, 1), None, 2), None, 1)
root7.is_mirror() # False

答案 5 :(得分:2)

这是每个gvijay的C ++解决方案

bool isMirrorTree(BTnode* LP, BTnode* RP)
{
    if (LP == NULL || RP == NULL) // if either is null check that both are NULL
    { 
        return ( LP == NULL && RP == NULL );
    } 
    // check that data is equal and then recurse
    return LP->data == RP->data && 
           isMirrorTree( LP->left, RP->right ) && 
           isMirrorTree( LP->right, RP->left );
}

答案 6 :(得分:1)

以下是关于C-COde的解决方案

isMirror(root)
{ 
Symmetric(root->left, root->right);
}

Symmetric(root1,root2)
{
 if( (root1->left EX-NOR root2->right) && (root1->right EX-NOR root2->left) && (root1->value==root2->value) )        
//exnor operation will return true if either both present or both not present 
// a EX-NOR b =(!a && !b) || (a && b))
        {
    Symmetric(root1->left, root2->right);
    Symmetric(root1->right, root2->left);
        }    
else return false;
}

答案 7 :(得分:1)

如果有人需要Swift版本,请点击此处。

另一种方法是反转其中一个子树,并以直接的方式比较两个结果的子树。

func compareTrees(left: TreeNode?, right: TreeNode?) -> Bool {
    var res = false
    if left == nil && right == nil {return true}
    if left != nil && right != nil {
        res = left!.val == right!.val &&
              compareTrees(left!.left, right: right!.left) &&
              compareTrees(left!.right, right: right!.right)
    }
    return res
}

func invertTree(node: TreeNode?) {
    if node == nil {return}

    var tmp = node!.left
    node!.left = node!.right
    node!.right = tmp

    invertTree(node!.left)
    invertTree(node!.right)
}

// and run it as:
if root == nil {print("Y")}
invertTree(root!.right)
compareTrees(root!.left, right: root!.right) ? print("Y") : print("N")

答案 8 :(得分:0)

略有不同的方法。

如何对二进制树进行inorder遍历,将所有内容存储在某些数据结构中,如字符串/数组。

遍历完成后,检查阵列中的元素是否形成回文结构。 没有那么有效的空间(递归需要O(log(n)),这个方法传说O(n))但这也可以。

答案 9 :(得分:0)

在python中使用稍微不同的方法的迭代解决方案。使用queue1按从左到右的顺序存储左子节点,使用queue2按从右到左的顺序存储右子节点并比较相等性。

def isSymmetric(root):
    if not root:
        return True
    if not (root.left or root.right):
        return True
    q1 = collections.deque([root.left])
    q2 = collections.deque([root.right])
    while q1 and q2:
        n1 = q1.popleft()
        n2 = q2.popleft()
        if n1 is None and n2 is None:
            continue
        if (n1 is None) ^ (n2 is None):
            return False
        if n1.val != n2.val:
            return False
        q1.append(n1.left)
        q1.append(n1.right)
        q2.append(n2.right)
        q2.append(n2.left)
    if not (q1 and q2):
        return True
    return False

答案 10 :(得分:0)

公共类SymmetricTree {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    //int[] array = {1,2,2,3,4,4,3};
    /*
     *                  1
     *                 / \
     *                /   \
     *               /     \
     *              2       2
     *             / \     / \
     *            /   \   /   \
     *           3     4 4     3
     * 
     * */
    //int[] array = {1,2};
    BinaryTree bt=new BinaryTree();
    bt.data=1;
    bt.left = new BinaryTree(2);
    bt.right = new BinaryTree(2);
    bt.left.right = new BinaryTree(3);
    bt.right.right = new BinaryTree(3);
    //bt=BinaryTree.buildATree(bt, array);
    System.out.print(isSymmetric(bt));
    BinaryTree.inOrderTraversal(bt);
}
public static boolean isSymmetric(BinaryTree root){
    if(root==null)
        return true;
    return isSymmetricLR(root.left,root.right);
}
public static boolean isSymmetricLR(BinaryTree left, BinaryTree right){
    if(left == null && right == null)
        return true;
    if(left!=null && right!=null)
        return (left.data == right.data) &&
                (isSymmetricLR(left.left, right.right)) &&
                (isSymmetricLR(left.right, right.left));
    return false;
}

}

答案 11 :(得分:0)

使用python

library(bench)
A <- matrix(runif(5000 * 5000), 5000)
bench::mark("Mat2Sym" = Mat2Sym(A, FALSE, 128),
            "Matrix" = new("dspMatrix", x = A[lower.tri(A, TRUE)], Dim = dim(A),
                           uplo = "L"),
            check = FALSE)
#  expression      min     mean   median     max `itr/sec` mem_alloc  n_gc n_itr
#  <chr>      <bch:tm> <bch:tm> <bch:tm> <bch:t>     <dbl> <bch:byt> <dbl> <int>
#1 Mat2Sym      56.5ms   57.9ms     58ms  58.7ms     17.3     2.48KB     0     9
#2 Matrix      934.7ms  934.7ms    935ms 934.7ms      1.07  524.55MB     2     1

答案 12 :(得分:0)

我想在Python中添加一个解决方案,使某些人可能比其他方法更容易理解。这个想法是:

  1. +1添加到左孩子返回的值。
  2. -1添加到右子级返回的值。
  3. l+r返回给父级

因此,如果l+r == 0对于树中的任何节点,则锚定在该节点的子树是对称的。因此,仅当l+r == 0位于根目录时,整个树才对称。

def check(root):
    l = check(root.left)+1 if root.left else 0
    r = check(root.right)-1 if root.right else 0
    return l+r

def is_symmetric(root):
    return root is not None and check(root) == 0

答案 13 :(得分:0)

使用 Queue ,因为我觉得递归有点难。

bool isSymmetric(TreeNode* root) {
    queue<TreeNode*> q;
    q.push(root);
    q.push(root);
    while(q.empty()==false){
        TreeNode* a = q.front();
        q.pop();
        TreeNode* b = q.front();
        q.pop();
        if(a->val != b->val){
            return false;
        }
         if(a->left == nullptr and b->right != nullptr)
            return false;
        if(a->left != nullptr and b->right == nullptr)
            return false;
        if(a->right != nullptr and b->left == nullptr)
            return false;
        if(a->right == nullptr and b->left != nullptr)
            return false;
        if(a->left != nullptr and b->right != nullptr){
            q.push(a->left);
            q.push(b->right); 
        }
        if(a->right != nullptr and b->left != nullptr){
            q.push(a->right);
            q.push(b->left);
        }`enter code here`
    }
    return true;
}

答案 14 :(得分:0)

java 脚本解决方案怎么样

使用的算法

araay = ["10" , "2", "2", "#", "1", "1", "#"] 让我们把它分解成每一步

step 1 = ["10"]
step 2 = [ "2", "2" ]
step 3 = ["#", "1", "1", "#"]

检查除第一步以外的每一步的镜像

让我们进行第 3 步。 step 3 = ["#", "1", "1", "#"] 把它从中间分成 2 个数组

step 3 1 = ["#", "1" ]
step 3 2 = ["1", "#"]

现在反转步骤 3 2

step 3 2 = ["1", "#"]

现在检查步骤 3 2 是否等于步骤 3 1

每一步都做上面的事情

如果都是镜像,那么二叉树就是镜像

const Input = ["10" , "2", "2", "#", "1", "1", "#"];
function isEqual(a,b)
{
  // if length is not equal
  if(a.length!=b.length)
   return false;
  else
  {
  // comapring each element of array
   for(var i=0;i<a.length;i++)
   if(a[i] !== b[i]){
    return false;
   }
    return true;
  }
}

// Response 
let symetric = true ;
let stepSymetric = true ;
let mirror = true ;
// length of input 
const length = Input.length ;
// const length = 31 ;

// lets create binary tree from it

const totalSteps =
      Math.log(length + 1)/Math.log(2) ;

// check for symetric binary tree
function checkInt(n) { return parseInt(n) === n };
 symetric = checkInt(totalSteps);

//now check for mirror
let goneArrayLength = 0 ;
for (let i = 0; i < totalSteps; i++) { 
  const cStep = Math.pow(2,i);
  
  const stepArray = [];
  // console.log(goneArrayLength);
  
  // now update the step array 
  const start = goneArrayLength ;
  const end =  goneArrayLength + cStep ;
  
  for (let j = start; j < end; j++) {
    stepArray.push(Input[j])
  }
  
  console.log(stepArray);
  // Now we have each step lets find they are mirror image or not
  // check for even length
  if(stepArray.length%2 !== 0 && i !== 0){
    stepSymetric = false ;
  }
  const partitation = stepArray.length / 2 ;
  const leftArray = stepArray.slice(0,partitation);
  const rightArray = stepArray.slice(partitation , partitation * 2);
  // console.log("leftArray");
  // console.log(leftArray);
  // console.log("rightArray");
  // console.log(rightArray);
  function mirrorCheck (){
    let check = false;
    if(cStep === 1){
      return true ;
    }
    let array1 = leftArray;
    let array2 = rightArray.reverse();
    // console.log("first");
    // console.log(array1);
    // console.log("second");
    // console.log(array2);
   let equal = isEqual(array1 , array2)
   // console.log(equal);
    check = true ;
    if(!equal){
      // console.log("Noooooooooooooooo")
      check = false ;
    }
    
    return check;
  }
  let mirrorC = mirrorCheck();
  
  if(!mirrorC){
    mirror = false;
  }
  goneArrayLength = goneArrayLength + cStep ;
}
console.log(mirror + " " + symetric + " " + stepSymetric )

if(mirror && symetric && stepSymetric ){
  console.log("Mirror Image");
  
}
else{
  console.log("Not mirror image")
}
// console.log(isSymetric);
// console.log(totalSteps);

答案 15 :(得分:-1)

我不是很有经验(仅仅在公司工作一年),但在我看来,这可以通过使用S =递归来解决

例如:

MYTREECLASS B1= new MYTREECLASS();
MYTREECLASS B2= new MYTREECLASS();
B1= OriginalTree;
B2=OriginalTRee;
Boolean CHECK(MYTREECLASS, MYTREECLASS)
{
if (B1.Node = B2.Node)
then (
CHECK(B1.Left, B2.Right);
CHECK(B1.Right,B2.Left)
)
elseIf(b1.Left==null or b2.right...blah blah ,,)
return False)
else return False,

如果匹配则返回true。