Quel est l'algorithme de base pour tester si un arbre est symétrique. Puisqu'il s'agit d'un arbre binaire, je suppose que ce serait une définition récursive de la sorte
La question formelle est ci-dessous:
Un arbre binaire est une image miroir de lui-même si ses sous-arbres gauche et droit sont des images miroir identiques, c’est-à-dire si l’arbre binaire est symétrique.
1
/ \
2 2
VRAI
1
/ \
2 2
\
3
FALSE
1
/ \
2 2
/ \ / \
4 3 3 4
VRAI
1
/ \
2 2
/ \ / \
3 4 3 4
FALSE
1
/ \
2 2
/ \
3 3
VRAI
Dans un langage de programmation choisi, définissez une structure BTree class/C et une méthode associée pour vérifier si l’arborescence est une image miroir. Pour les langages à typage statique, vous pouvez supposer que les valeurs de nœud sont toutes des entiers.
Class/structure definition
BTree {
BTree left;
BTree right;
int value;
}
Supposons que l'appelant suit la racine de l'arborescence et que la fonction isMirror () y soit invoquée.
De même, si vous définissez une classe, veillez à fournir un constructeur sans argument et des méthodes getter/setter si les éléments de données ne sont pas accessibles au public.
Pourquoi ne pas appeler mirrorEquals (root.left, root.right) sur la fonction suivante: -
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);
}
En gros, comparez le sous-arbre gauche et le sous-arbre droit inversé, en dessinant une ligne d'inversion imaginaire sur la racine.
Solution 1 - Récursivement:
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);
}
Solution 2 - Itérativement:
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;
}
La solution récursive de @gvijay est très claire et voici une solution itérative.
Examinez chaque rangée de l'arbre de haut en bas et vérifiez si les valeurs correspondent à un palindrome. S'ils le sont tous, alors, oui, c'est un miroir. Vous devrez implémenter un algorithme pour visiter chaque ligne et inclure des valeurs NULL pour les arbres fragmentés. En pseudocode:
boolean isMirror(BTree tree) {
foreach (List<Integer> row : tree.rows() {
if (row != row.reverse()) return false;
}
return true;
}
L'astuce consiste à concevoir un algorithme permettant d'itérer les lignes d'un arbre en tenant compte du fait que les arbres clairsemés doivent avoir des valeurs NULL en tant que substituants. Cette implémentation Java semble correcte:
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;
}
}
Solutions récursives et itératives en Java en utilisant les approches discutées ci-dessus
Récursif
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;
}
Itératif utilisant LinkedList comme Queue
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;
}
Cas de test
@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));
}
Nœud d'arbre class
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;
}
}
Voici une solution C++ par gvijay
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 );
}
MODIFIER
Comme il a été souligné dans les commentaires, ma première version de l’algorithme a échoué pour certaines entrées. Je ne vais pas réinventer la roue, je vais juste fournir une réponse Python en utilisant l'algorithme correct @gvijay. Tout d'abord, une représentation de l'arbre binaire:
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))
J'ai testé le code ci-dessus en utilisant tous les exemples d'arbres de la question et les arbres qui renvoyaient des résultats incorrects, comme indiqué dans les commentaires. Maintenant, les résultats sont corrects pour tous les cas:
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
Si quelqu'un a besoin d'une version Swift, en voici une.
Une autre approche consiste simplement à inverser l’un des sous-arbres et à comparer les deux sous-arbres résultants d’une manière simple.
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")
Voici la solution en ce qui concerne 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;
}
classe publique 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;
}
}
Je pensais ajouter une solution en Python que certaines personnes trouveraient plus facile à comprendre que d’autres approches. L'idée est:
+1
à la valeur renvoyée par l'enfant de gauche.-1
à la valeur renvoyée par le bon enfant.l+r
au parentDonc, si l+r == 0
pour un noeud de l’arbre, le sous-arbre ancré à ce noeud est symétrique. Par conséquent, toute l’arbre n’est symétrique que si l+r == 0
à la racine.
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
en utilisant python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def helper(root1, root2):
if not root1 and not root2: return True
if not root1 or not root2: return False
if root1.val != root2.val: return False
if helper(root1.left, root2.right): return helper(root1.right, root2.left)
return False
return helper(root, root)
Approche légèrement différente.
Que diriez-vous de faire une traversée en ordre de l’arbre binaire en stockant tout le contenu dans une structure de données comme une chaîne/tableau.
Une fois le parcours terminé, vérifiez si les éléments de votre tableau forment un palindrome . Pas aussi efficace en termes d'espace (la récursivité prend O (log (n)), cette méthode indique O(n)) travailler aussi bien.
Solution itérative utilisant une approche légèrement différente en python. Utilisez queue1 pour stocker les enfants laissés dans l'ordre de gauche à droite et queue2 pour stocker les enfants de droite dans l'ordre de droite à gauche et effectuez une comparaison pour l'égalité.
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