2 binäre Bäume gleich sind oder nicht

stimmen
7

Mögliche Duplizieren:
Bestimmen Sie, ob zwei binäre Bäume gleich sind

Haben Sie ein Interview gestern, bekam eine Frage mich, hier ist es:

Beschreibung

Es gibt 2 binary trees, zu überprüfen , ob sie gleich sind.

Sie sind gleich , wenn und nur wenn tree1->child == tree2->child, und ein Baum des nach links und rechts children can be swapped with each other.

Beispielsweise:

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

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

Alle Ideen sind willkommen.

Veröffentlicht am 12/10/2011 um 01:18
quelle vom benutzer
In anderen Sprachen...                            


6 antworten

stimmen
9

Gleichheitsoperatoren sind transitiv: Wenn A = B und B = C, dann A = B = C, so A = C.

Gleichheitsoperatoren sind reflexiv: A = A, B = B, und C = C egal, was ihre Werte sind.

Gleichheitsoperatoren sind symmetrisch. Wenn A = B, dann B = A. (Es ist egal, in welcher Reihenfolge sie sind in.)

Nun, ein Blick auf die Definition sie dir gegeben habe:

Ein Baum ist zu einem anderen Baum gleich, wenn die Kinder gleich sind. Mal schauen. Wir können davon ausgehen, dass die Knoten am Boden verglichen werden, oder aber die Definition ist ziemlich nutzlos. Aber sie kümmern sich nicht darum, Ihnen zu sagen, wie man diesen Vergleich zu lösen, und die ganze Definition sie Sie gaben Scharniere darauf.

Kurz gesagt, ist es eine beschissene Frage.

Mal sehen, was passiert, wenn wir uns entscheiden, die Frage versuchen wollen und zu entwirren, though.

Aber warten Sie , sie Ihnen auch sagen , dass die beiden Kinder jeden Baum getauscht werden kann. Dadurch wird die Einschränkung , dass jeder Baum, der auf etwas anderes (einschließlich sich selbst) gleich ist , muss auf sein Spiegelbild gleich sein. Und alle Variationen seiner Unterbäume Kinder getauscht werden.

Und denken Sie daran , dass es sich hierbei um eine sein Suchbaum. Deshalb können wir wohl davon ausgehen , dass zwei verschiedene Suchbäume , die durch den gleichen Algorithmus verarbeitet werden , müssen das gleiche Ergebnis , wenn sie gleich sind. Also, wenn wir um die Elemente eines Baumes zu wechseln, dann würde die Suchzeit beeinflusst werden. Also, Bäume, die einander nicht jeden Knoten an der richtigen Stelle sind nicht gleich.

dass zusammen mit der „Swap“ Eigenschaft dieser Gleichheit Einlochen, können wir es keine gültige Definition der Gleichheit sehen. (Wenn wir versuchen, es anzuwenden, dann stellt sich heraus, dass nur Bäume, die den gleichen Knoten für jeden Knoten auf einer bestimmten Ebene haben gleich sind, und nur auf sich selbst, die die Reflexivität Teil eines Gleichheitsoperator bricht.)

Beantwortet am 12/10/2011 um 01:24
quelle vom benutzer

stimmen
3

Wenn Sie ihre Definition von „Gleichheit“ mit Flip-Invarianz implementieren, werden Sie die Definition der Gleichheit verstoßen. Die Definition ist auch nicht sinnvoll, denn das ist nicht, wie binäre Suchbäume gleich sind (es sei denn jeder Knoten einen Zeiger aufweist, an dem Teilbaum „größer“ ist und was „weniger“).

Sie haben zwei Möglichkeiten der angemessenen Definitionen:

  1. topologischen (Flip-Agnostiker) Äquivalenz (in diesem Fall können Sie nicht nennt es einen „binärer Suchbaum“ , weil es nicht sortiert ist):

    tree1==tree2 meint set(tree1.children)==set(tree2.children)

  2. normaler Suchbaum (Flip-fürsorgliche) Äquivalenz:

    tree1==tree2 meint list(tree1.children)==list(tree2.children)

Für binäre Bäume, werden die obigen Definitionen arbeiten als schriftliche in jeder Sprache , der die Träger listund setDatentypen (Python - Sets werden Drossel jedoch auf unhashable Datentypen). Dennoch unten sind einige ausführlichere und hässlich C / Java-ähnliche Definitionen:

  1. topologische Äquivalenz:

    t1==t2 meint (t1.left==t2.left and t1.right==t2.right) or (t1.left==t2.right and t1.right==t2.left)

  2. sortierten Baum Äquivalenz:

    t1==t2 meint (t1.left==t2.left and t1.right==t2.right)

Die obigen Definitionen sind rekursiv; das heißt, übernehmen sie die Gleichstellung der für die Teilbäume und basen Fällen bereits definiert, die es hat.


Randnotiz:

Zitat: tree1-> Kind == tree2-> Kind

Dies ist keine gültige Aussage, weil ein Baumknoten kein einziges Kind hat.

Beantwortet am 12/10/2011 um 02:20
quelle vom benutzer

stimmen
7

Ich glaube nicht, das eine unzumutbare Frage. Eine einfache rekursive Lösung ist

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;
}

Dies kann sehr teuer sein, zum Beispiel in dem Fall, wenn wir zwei große Bäume mit ähnlicher Form haben, wo alle Nicht-Blatt-Knoten den gleichen zugeordneten Wert und die Blattknoten einen sind eine Permutation des Blattknoten eines andere hat.

Um diese Vergangenheit konnte man in erster Linie ändern links und rechts je nach Bedarf, so dass links <rechts, für einige rekursive Definition von <. Dies könnte auch teuer sein, aber viel weniger als jede Permutation prüft, und ich denke, eine Wahl der Definition von <helfen würde. Dies würde dann können Sie für die Gleichstellung mit einer gewöhnlichen Definition überprüfen.

Dieser Begriff der http://en.wikipedia.org/wiki/Canonicalization gefolgt von gewöhnlicher Gleichheit löst auch Fragen darüber , ob Sie wirklich eine Äquivalenzbeziehung zu tun haben. Eine Äquivalenzbeziehung ist , in eine Partition äquivalent. Gewöhnliche Gleichheit ist offensichtlich eine Partition. Wenn Sie x und y zu vergleichen mit einer Äquivalenzrelation gefolgt f (x) und f (y) zu vergleichen haben Sie eine Partition von x und y, und daher eine Äquivalenzrelation.

Denken Sie mehr darüber, ich glaube, die Art und Weise entweder Kanonisierung oder Gleichheit-Prüfung zu machen einigermaßen effizient ist von unten nach oben zu arbeiten, wobei jeder Knoten mit einem Token mit Anmerkungen versehen, deren Wert spiegelt das Ergebnis von Vergleichen mit anderen Knoten, so dass Sie Knoten vergleichen und die Teilbäume unter ihnen, werden nur Token zu vergleichen.

So ist der erste Schritt für die Gleichstellung ist zB eine Hash-Tabelle zu verwenden, um jedes Blatt mit Token mit Anmerkungen versehen, die nur gleich sind, wenn die Werte an den Blättern gleich sind. Dann wird für Knoten, deren Kinder sind nur Blätter, verwenden zB eine Hash-Tabelle weiteren Tokens zuweisen, so dass die Zeichen in diesen Knoten gleich sind, nur dann, wenn die Blätter, wenn überhaupt, unter diesen Knoten Spiel. Dann können Sie noch einen Schritt nach oben gehen, und dieses Mal können Sie Token vergleichen, um Kind-Knoten statt Rekursion den Baum dort unten. Die Kosten für die Token auf diese Weise die Zuweisung sollte in der Größe der beteiligten Bäume linear sein. An der Spitze können Sie Bäume vergleichen nur durch die Token an der Wurzel zu vergleichen.

Beantwortet am 12/10/2011 um 06:57
quelle vom benutzer

stimmen
0

Ich las die Fragen wie: zwei binäre Bäume gegeben, für jede Tiefe in dem Baum, herauszufinden, ob ihre Kinder Satz ist in ihnen abgedeckt.

Dies kann relativ einfach codiert werden.

Beantwortet am 12/10/2011 um 12:30
quelle vom benutzer

stimmen
0

Lösung ohne Rekursion in 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-Syntax Tipps:

  • (1) setzen Element in Array: arr << elem; in diesem Fall for_checkist Array von Arrays
  • (2) parallel Zuordnung: t1,t2 = [item1, item2]. Gleich wiearr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrenangenommen entsprechendes Verhalten von == für diese Art von Objekten. Ausführlicher sein wird t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- hier mapproduziert von vals Array.
Beantwortet am 15/10/2011 um 16:17
quelle vom benutzer

stimmen
1

Vergleichen Bäume mit Heiligsprechung Ansatz vorgeschlagen @mcdowella . Der Unterschied ist , dass mein Ansatz nicht erfordert O(N)zusätzliche Speicher WRT Anzahl der Knoten im Baum:

# 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()erfordert O(N*M)Schritte und O(log(N)*M)Speicher , alle Knoten in einem Baum zu erhalten, in denen NGesamtanzahl von Knoten ist, MAnzahl der Kinder jeder Knoten hat (es ist 2 für binäre Bäume).

canonorder()könnte für jede Knotendarstellung und eine beliebige Anzahl von Kindern leicht verallgemeinert. canonwalk()nur verlangt , dass ein Baum seiner unmittelbaren Kinder als Folge zugreifen kann.

Die Vergleichsfunktion, die ruft 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

Beispiel

    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)

Ausgabe

True
Beantwortet am 15/10/2011 um 21:10
quelle vom benutzer

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