2 arbres binaires sont égaux ou non

voix
7

Possible en double:
déterminer si deux arbres binaires sont égaux

Vous avez une interview hier, une question m'a, la voici:

La description

Il y a 2 binary trees, vérifier si elles sont égales.

Ils sont égaux si et seulement si tree1->child == tree2->child, et un arbre de gauche et à droite children can be swapped with each other.

Par exemple:

    5     6
   / \   / \           they are equal.
   1 2   2  1

    5         6
   / \       / \           they are equal.
  1   2     2   1
 /     \   /    / 
3       4 4     3

Toutes les idées sont appréciés.

Créé 12/10/2011 à 01:18
source utilisateur
Dans d'autres langues...                            


6 réponses

voix
9

opérateurs d'égalité sont transitif: Si A = B et B = C, alors A = B = C alors A = C.

opérateurs d'égalité sont réflexif: A = A, B = B et C = C quelles que soient leurs valeurs.

opérateurs d'égalité sont symétriques. Si A = B, alors B = A. (Peu importe quel ordre ils sont.)

Maintenant, jeter un oeil à la définition qu'ils vous ont donné:

Un arbre est égal à un autre arbre, si les enfants sont égaux. Voyons voir. On peut supposer que les noeuds sont comparés au fond, ou bien la définition est assez inutile. Mais ils ne prennent pas la peine de vous dire comment résoudre cette comparaison, et la définition entière, ils vous ont donné des charnières dessus.

En bref, il est une question merdique.

Voyons voir ce qui se passe si nous décidons que nous voulons essayer de démêler la question, cependant.

Mais attendez, ils vous disent aussi que les deux enfants de tout arbre peuvent être permutés. Cela ajoute la contrainte que tout arbre qui est égal à rien d' autre (y compris lui - même) doit être égale à son image miroir. Et étant permutés les variations des enfants de ses sous - arbres.

Et rappelez - vous que cela est censé être une recherche arbre. Par conséquent, on peut sans doute supposer que deux qui sont des arbres de recherche différents traités par le même algorithme doit donner le même résultat si elles sont égales. Donc, si on passe autour des éléments d'un arbre, le temps de recherche serait affectée. Ainsi, les arbres qui ne sont pas tous les nœuds en place ne sont pas égaux entre eux.

Mettre qui, ensemble, avec la propriété « swappable » de cette égalité, nous pouvons voir ce n'est pas une définition valable de l'égalité. (Si nous essayons de l'appliquer, il se révèle que seuls les arbres qui ont le même noeud pour chaque noeud à un niveau particulier sont égaux, et seulement à eux-mêmes, qui brise la partie réflexivité d'un opérateur d'égalité).

Créé 12/10/2011 à 01:24
source utilisateur

voix
3

Si vous implémentez la définition d ' « égalité » avec flip-invariance, vous violer la définition de l'égalité. La définition ne fait même pas de sens, car ce n'est pas comment les arbres binaires de recherche sont égaux (à moins que chaque nœud a un pointeur auquel est sous-arbre « plus » et qui est « moins »).

Vous avez deux choix de définitions raisonnables:

  1. topologique équivalence (agnostique FLIP) (dans ce cas , vous ne pouvez pas l' appeler un « arbre de recherche binaire » , car il n'est pas triée):

    tree1==tree2 veux dire set(tree1.children)==set(tree2.children)

  2. arbre de recherche normale (flip-soins) équivalence:

    tree1==tree2 veux dire list(tree1.children)==list(tree2.children)

Pour les arbres binaires, les définitions ci - dessus fonctionnent comme écrit dans une langue qui prend en charge le listet les settypes de données (jeux de python étoufferont cependant sur les types de données unhashable). Néanmoins, voici quelques plus verbeux et laids C / définitions de type Java:

  1. équivalence topologique:

    t1==t2 veux dire (t1.left==t2.left and t1.right==t2.right) or (t1.left==t2.right and t1.right==t2.left)

  2. équivalence arbre Sorted:

    t1==t2 veux dire (t1.left==t2.left and t1.right==t2.right)

Les définitions ci-dessus sont récursifs; à savoir, ils supposent l'égalité a été définie pour les sous-arbres et de base-cas déjà, qu'il a.


sidenote:

citation: tree1-> enfant == tree2-> enfant

Ce n'est pas une déclaration valide, parce qu'un nœud d'arborescence ne dispose pas d'un seul enfant.

Créé 12/10/2011 à 02:20
source utilisateur

voix
7

Je ne pense pas que ce soit une question déraisonnable. Une solution récursive simple

boolean equals(x, y)
{
  if (x == null)
  {
    return y == null;
  }
  if (y == null)
  {
    return false;
  }
  if (x.val != y.val)
  {
    return false;
  }
  if (equals(x.left, y.left) && equals(x.right, y.right))
  {
    return true;
  }
  if (equals(x.left, y.right) && equals(x.right, y.left))
  {
    return true;
  }
  return false;
}

Cela peut être très coûteux, par exemple dans le cas où nous avons deux grands arbres de forme semblable où tous les nœuds non-feuilles ont la même valeur associée et les nœuds feuilles d'un sont une permutation des nœuds feuilles d'une autre.

Pour passer cela, vous pouvez tout d'abord le changement à gauche et à droite comme nécessaire pour que gauche <à droite, pour une définition récursive de <. Cela pourrait aussi être coûteux, mais beaucoup moins que de vérifier toutes les permutations, et je pense que le choix de la définition de <aiderait. Cela vous permettra de vérifier l'égalité avec une définition ordinaire.

Cette notion de http://en.wikipedia.org/wiki/Canonicalization suivie par l' égalité ordinaire résout également des questions quant à savoir si vous avez vraiment une relation d'équivalence. Une relation d'équivalence est équivalente à une partition. L' égalité ordinaire est évidemment une partition. Si vous comparez x et y en comparant f (x) et f (y) suivie d'une relation d'équivalence vous avez une partition de x et y, et donc une relation d'équivalence.

En pensant plus à ce sujet, je pense que la façon de faire soit à tester l'égalité canonicalisation ou raisonnablement efficace est de travailler à partir du bas vers le haut, annoter chaque nœud avec un jeton dont la valeur reflète le résultat des comparaisons avec d'autres nœuds, de sorte que vous pouvez comparer les noeuds et les sous-branches sous eux, être juste comparer les jetons.

La première étape pour l'égalité est par exemple utiliser une table de hachage pour annoter chaque feuille avec des jetons qui sont égaux que lorsque les valeurs les feuilles sont égales. Ensuite, pour les nœuds dont seuls les enfants sont les feuilles, utilisez par exemple une table de hachage pour attribuer des jetons supplémentaires pour que les jetons dans ces noeuds sont égaux que lorsque les feuilles, le cas échéant, sous les nœuds correspondent. Ensuite, vous pouvez aller un en plus de temps, et cette fois-ci, vous pouvez comparer les jetons à nœuds enfants au lieu de récursion dans l'arbre là-bas. Le coût de l'attribution des jetons de cette manière devrait être linéaire dans la taille des arbres en cause. En haut, vous pouvez comparer les arbres juste en comparant les jetons à la racine.

Créé 12/10/2011 à 06:57
source utilisateur

voix
0

Je lis les questions suivantes: étant donné deux arbres binaires, pour chaque profondeur dans l'arbre, savoir si l'ensemble de leurs enfants sont couverts dans l'autre.

Cela peut être codé relativement facile.

Créé 12/10/2011 à 12:30
source utilisateur

voix
0

Solution sans récursivité en Ruby

def same? top_t1, top_t2
  for_chek << [top_t1, top_t2]   # (1) put task for check into queue

  while t1,t2 = for_check.shift  # (2)
    return false unless t1.children.count == t2.children.count  # generally for non-binary tree, but also needed for controlling of nil children
    break if t1.children.empty?

    t1_children = t1.children.sort # this is sorted arrays
    t2_children = t2.children.sort # of childrens      
    return false unless t1_children == t2_children  # (3)

    0.upto(t1_children.count - 1) do |i|
      for_check << [t1_children[i], t2_children[i]]  # put equivalent child pairs into queue
    end
  end
  return true
end

Ruby conseils de syntaxe:

  • (1) élément de mise en réseau: arr << elem; dans ce cas , for_checkest un tableau de tableaux
  • (2) attribution parallèle: t1,t2 = [item1, item2]. Pareil quearr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrensuppose un comportement correspondant de == pour ce genre d'objets. Plus bavard sera être t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- ici mapproduit tableau de vals.
Créé 15/10/2011 à 16:17
source utilisateur

voix
1

Comparer les arbres à l' aide approche Canonisation suggérée par @mcdowella . La différence est que mon approche ne nécessite pas le O(N)numéro de WRT mémoire supplémentaire de nœuds dans l'arborescence:

# in Python
from collections import namedtuple
from itertools import chain

# Tree is either None or a tuple of its value and left, right trees
Tree = namedtuple('Tree', 'value left right')

def canonorder(a, b):
    """Sort nodes a, b by their values.

    `None` goes to the left
    """
    if (a and b and a.value > b.value) or b is None:
        a, b = b, a # swap
    return a, b

def canonwalk(tree, canonorder=canonorder):
    """Yield all tree nodes in a canonical order.

    Bottom-up, smaller children first, None is the smallest
    """
    if tree is not None:
        children = tree[1:]
        if all(t is None for t in children): return # cut None leaves
        children = canonorder(*children)            
        for child in chain(*map(canonwalk, children)):
            yield child
    yield tree 

canonwalk()nécessite des O(N*M)étapes et la O(log(N)*M)mémoire pour donner tous les noeuds dans un arbre, où Nest le nombre total de noeuds, le Mnombre d'enfants chaque noeud a (il est 2 pour les arbres binaires).

canonorder()pourrait facilement être généralisé pour toute représentation de noeud et un certain nombre d'enfants. canonwalk()exige seulement qu'un arbre peut accéder à ses enfants immédiats comme une séquence.

La fonction de comparaison qui appelle canonwalk():

from itertools import imap, izip_longest

unset = object() 
def cmptree(*trees):
    unequal = False # allow root nodes to be unequal
    # traverse in parallel all trees under comparison
    for nodes in izip_longest(*imap(canonwalk, trees), fillvalue=unset):
        if unequal:
            return False # children nodes are not equal
        if any(t is unset for t in nodes):
            return False # different number of nodes
        if all(t is not None for t in nodes):
            unequal = any(nodes[-1].value != t.value for t in nodes)
        else: # some are None
            unequal = any(t is not None for t in nodes)
    return True # equal

Exemple

    5         6
   / \       / \           they are equal.
  1   2     2   1
 /     \   /    / 
3       4 4     3

tree1 = Tree(5, 
             Tree(1, 
                  Tree(3, None,None), None), 
             Tree(2, 
                  None, Tree(4, None, None)))
tree2 = Tree(6, 
             Tree(2, Tree(4, None, None), None),
             Tree(1, Tree(3, None, None), None))
print cmptree(tree1, tree2)

Sortie

True
Créé 15/10/2011 à 21:10
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more