2 alberi binari sono uguali oppure no

voti
7

Eventuali duplicati:
determinare se due alberi binari sono uguali

Ha ottenuto un colloquio di ieri, una domanda mi ha fatto, eccolo:

Descrizione

Ci sono 2 binary trees, controllare se sono uguali.

Sono uguali se e solo se tree1->child == tree2->child, e un albero di destra e sinistra children can be swapped with each other.

Per esempio:

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

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

Tutte le idee sono apprezzati.

È pubblicato 12/10/2011 alle 01:18
fonte dall'utente
In altre lingue...                            


6 risposte

voti
9

operatori di uguaglianza sono transitiva: se A = B e B = C, allora A = B = C = C in modo A.

operatori di uguaglianza sono riflessiva: A = A, B = B, e C = C, non importa ciò che i loro valori.

operatori di uguaglianza sono simmetriche. Se A = B, allora B = A. (Non importa in che ordine si trovano.)

Ora, dare un'occhiata alla definizione che ti ha dato:

Un albero è uguale a un altro albero se i bambini sono uguali. Vediamo. Si può presumere che i nodi vengono confrontati in fondo, altrimenti la definizione è abbastanza inutile. Ma loro non si preoccupano di dirvi come risolvere il confronto, e l'intera definizione che ti ha dato cerniere su di esso.

In breve, si tratta di una domanda di merda.

Vediamo cosa succede se decidiamo che vogliamo cercare di dipanare la questione, però.

Ma l'attesa, ma anche ti dicono che i due bambini di qualsiasi albero possono essere scambiati. Questo aggiunge il vincolo che ogni albero che è uguale a qualsiasi altra cosa (compreso se stesso) deve essere uguale sua immagine speculare a. E le eventuali variazioni dei figli suoi sottostrutture essere scambiati.

E ricordate che questo dovrebbe essere una ricerca di albero. Pertanto, possiamo supporre che probabilmente due diversi alberi di ricerca che vengono elaborati dallo stesso algoritmo deve dare lo stesso risultato se sono uguali. Quindi, se si passa intorno agli elementi di un albero, poi il tempo di ricerca ne risentirebbe. Così, gli alberi che non hanno tutti i nodi in atto non sono uguali tra loro.

Mettendo insieme alla proprietà "swap" di questa uguaglianza, possiamo vedere che non è una definizione valida di uguaglianza. (Se cerchiamo di applicarlo, poi si scopre che solo alberi che hanno lo stesso nodo per ogni nodo ad un livello particolare sono uguali, e solo a se stessi, che rompe la parte riflessività di un operatore uguaglianza.)

Risposto il 12/10/2011 a 01:24
fonte dall'utente

voti
3

Se si implementa la loro definizione di "uguaglianza" con flip-invarianza, si violare la definizione di uguaglianza. La definizione non ha nemmeno senso, perché non è così che binarie alberi di ricerca sono uguali (a meno che ogni nodo ha un puntatore alla quale sottostruttura è "maggiore" e che è "minore").

Hai due scelte di definizioni ragionevoli:

  1. topologica (flip-agnostic) equivalenza (in questo caso, non si può chiamare un "albero binario di ricerca", perché non è ordinato):

    tree1==tree2 si intende set(tree1.children)==set(tree2.children)

  2. ricerca normale albero (flip-cura) equivalenza:

    tree1==tree2 si intende list(tree1.children)==list(tree2.children)

Per gli alberi binari, le definizioni di cui sopra funzionerà come-scritti in qualsiasi lingua che supporta la liste settipi di dati (set di Python soffocare tuttavia sui tipi di dati nel calcolo dell'hash). Tuttavia, di seguito sono alcuni C definizioni più prolisso e brutto / Java-like:

  1. equivalenza topologica:

    t1==t2 si intende (t1.left==t2.left and t1.right==t2.right) or (t1.left==t2.right and t1.right==t2.left)

  2. Ordinati albero di equivalenza:

    t1==t2 si intende (t1.left==t2.left and t1.right==t2.right)

Le definizioni di cui sopra sono ricorsivi; cioè, assumono parità è stata definita per le sottostrutture e base-casi già da essa.


nota a margine:

quote: tree1-> bambino == tree2-> bambino

Questa non è una dichiarazione valida, perché un nodo della struttura non dispone di un singolo bambino.

Risposto il 12/10/2011 a 02:20
fonte dall'utente

voti
7

Non credo che questa è una domanda irragionevole. Una soluzione semplice è ricorsiva

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

Questo può essere molto costoso, per esempio nel caso in cui abbiamo due grandi alberi di forma simile in cui tutti i nodi non foglia hanno lo stesso valore associato e nodi foglia uno sono una permutazione dei nodi foglia di un altro.

Per superare questo si potrebbe prima di tutto il cambiamento a destra ea sinistra, come richiesto in modo che a sinistra <destra, per qualche definizione ricorsiva di <. Questo potrebbe anche essere costoso, ma molto meno di quanto controllando ogni permutazione, e credo che una scelta di definizione di <aiuterebbe. Questo sarebbe quindi consentire di verificare per l'uguaglianza con una definizione comune.

Questa nozione di http://en.wikipedia.org/wiki/Canonicalization seguita da uguaglianza ordinaria risolve anche interrogativi sul fatto che avete veramente una relazione di equivalenza. Una relazione di equivalenza è equivalente a una partizione. Uguaglianza ordinaria è ovviamente una partizione. Se si confrontano xey confrontando f (x) ef (y) seguito da una relazione di equivalenza avete una partizione di x ed y, e quindi una relazione di equivalenza.

Pensando di più su questo, penso che il modo di fare sia la canonicalizzazione o uguaglianza-test ragionevolmente efficiente è quello di lavorare dal basso verso l'alto, annotando ogni nodo con un token il cui valore riflette il risultato di confronti con altri nodi, in modo da poter confrontare i nodi , e le sottostrutture sotto di loro, basta essere confrontando gettoni.

Quindi il primo passo per l'uguaglianza è ad esempio utilizzare una tabella hash per annotare ogni foglia con gettoni che sono uguali solo quando i valori alle foglie sono uguali. Quindi, per i nodi cui figli solo sono foglie, usare, ad esempio una tabella hash di assegnare ulteriori token in modo che i token in tali nodi sono uguali solo quando le foglie, eventualmente sotto quelli nodi partita. Poi si può fare un passo in più, e questa volta è possibile confrontare i token a nodi figli invece di recursing l'albero lì. Il costo di assegnare i token in questo modo deve essere lineare nella dimensione degli alberi coinvolti. Nella parte superiore è possibile confrontare alberi appena confrontando i gettoni alla radice.

Risposto il 12/10/2011 a 06:57
fonte dall'utente

voti
0

Ho letto le domande come: date due alberi binari, per ogni profondità nell'albero, scoprire se insieme dei loro figli sono coperti in ogni altro.

Questo può essere codificato relativamente facile.

Risposto il 12/10/2011 a 12:30
fonte dall'utente

voti
0

Soluzione senza ricorsione 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

punte di sintassi di Ruby:

  • (1) messa elemento nella matrice: arr << elem; in questo caso for_checkè matrice di matrici
  • (2) Assegnazione parallelo: t1,t2 = [item1, item2]. Uguale aarr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrenassunto comportamento corrispondente == per questo tipo di oggetti. Più verbose sarà t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- qui mapproduce serie di vals.
Risposto il 15/10/2011 a 16:17
fonte dall'utente

voti
1

Confronta alberi che utilizzano l'approccio suggerito da canonizzazione @mcdowella . La differenza è che il mio approccio non richiede O(N)ulteriore numero WRT memoria di nodi dell'albero:

# 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()richiede O(N*M)passi e O(log(N)*M)memoria per produrre tutti i nodi in un albero, dove Nè il numero totale di nodi, Mnumero di figli ciascun nodo contiene (è 2 per alberi binari).

canonorder()potrebbe essere facilmente generalizzato per qualsiasi rappresentazione nodi e qualsiasi numero di figli. canonwalk()richiede solo che un albero può accedere ai suoi figli immediati come una sequenza.

La funzione di confronto che chiama 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

Esempio

    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)

Produzione

True
Risposto il 15/10/2011 a 21:10
fonte dall'utente

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