2 drzewo binarne są równe lub nie

głosy
7

Powiel możliwe:
Ustal, czy dwa drzewa binarne są równe

Dostał wywiad wczoraj, pytanie got me, to jest tutaj:

Opis

Są to 2 binary treesnależy sprawdzić, czy są one równe.

Są równe wtedy i tylko wtedy tree1->child == tree2->child, i jedno drzewo na lewo i prawo children can be swapped with each other.

Na przykład:

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

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

Wszelkie pomysły są mile widziane.

Utwórz 12/10/2011 o 01:18
źródło użytkownik
W innych językach...                            


6 odpowiedzi

głosy
9

Operatorzy równość to przechodni: jeśli A = B, a B = C, to A = B = C, tak, A = C.

Operatorzy równości są refleksyjne: A = A, B = B i C = C bez względu na to, jakie są ich wartości.

Operatorzy równości są symetryczne. Jeżeli A = B, następnie B = A. (Nie ma znaczenia w jakiej kolejności są one w.)

Teraz przyjrzeniu definicji dali Ci:

Drzewo jest równy innym drzewie, jeśli dzieci są równe. Zobaczmy. Możemy założyć, że węzły są porównywane na dole, albo definicja jest całkiem bezużyteczny. Ale nie przeszkadza, aby powiedzieć, jak rozwiązać tego porównania, a cała definicja dali ci zależy na nim.

W skrócie, jest to bzdura pytanie.

Zobaczmy, co się stanie, jeśli zdecydujemy chcemy spróbować rozwikłać kwestię, choć.

Ale czekaj, oni również powiedzieć, że dwoje dzieci z każdego drzewa mogą zostać zamienione. Dodaje to ograniczenie, że każdy drzewo, które jest równe do niczego innego (w tym siebie) musi być równa jego lustrzane odbicie. Oraz wszelkie wariacje dzieci swoich poddrzew są zamienione.

I pamiętaj, że to ma być poszukiwanie drzewo. W związku z tym, możemy założyć, że prawdopodobnie dwa różne drzewa wyszukiwania, które są przetwarzane przez ten sam algorytm musi dać taki sam efekt, jeżeli są one równe. Tak więc, jeśli możemy przełączyć się wokół elementów drzewa, to czas wyszukiwania mogą być naruszone. Więc, drzewa, które nie mają każdy węzeł w miejscu nie są sobie równe.

Umieszczenie że wraz z „swap” własności tej równości, widzimy, że nie jest to ważna definicja równości. (Jeśli staramy się go stosuje, a potem okazuje się, że tylko drzewa, które mają ten sam węzeł dla każdego węzła na określonym poziomie są równe, i tylko dla siebie, który łamie część zwrotności z operatorem równości).

Odpowiedział 12/10/2011 o 01:24
źródło użytkownik

głosy
3

W przypadku zastosowania ich definicji „równości” z flip-niezmienności, będzie naruszać definicję równości. Definicja nie ma sensu, bo to nie jest jak binarne drzewo poszukiwań są równe (chyba każdy węzeł posiada wskaźnik do którego poddrzewo jest „większy”, a która jest „mniejszym”).

Masz dwie możliwości wyboru rozsądnych definicji:

  1. topologiczna (flip-agnostyk) równoważność (w takim przypadku nie można nazwać „binarne drzewo poszukiwań”, ponieważ to nie jest klasyfikowane):

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

  2. normalne wyszukiwanie drzewo (flip-opiekuńczy) równoważność:

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

Dla drzew binarnych, powyższe definicje będą działać jako napisany w dowolnym języku, który wspiera listi settypów danych (zestawy Python będzie dusić jednak na unhashable typów danych). Niemniej jednak, poniżej kilka dokładniejszych informacji i brzydkie / Java-C jak definicje:

  1. równoważność topologiczna:

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

  2. sortowych drzewo równoważność:

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

Definicje powyżej są rekurencyjne; czyli załóżmy, że równość została zdefiniowana dla poddrzew i bazowych przypadków już, co ma.


dygresja:

cytat: tree1-> dziecko == tree2-> dziecko

To nie jest ważne stwierdzenie, ponieważ węzeł drzewa nie ma jednego dziecka.

Odpowiedział 12/10/2011 o 02:20
źródło użytkownik

głosy
7

Nie sądzę, że jest to nierozsądne pytanie. Prostym rozwiązaniem jest rekurencyjne

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

Może to być bardzo kosztowne, na przykład w przypadku, gdy dwa duże drzewka o podobnym kształcie, w którym wszystkie węzły nie liści mają taką samą wartość oraz związanego węzły liściu, to permutacji węzłów liściowych innego.

Aby ominąć ten można przede wszystkim zmiany w lewo i prawo, jak tego wymaga więc w lewo <prawo jakiegoś rekurencyjnej definicji <. Może to być również drogie, ale znacznie mniej niż kontrolowanie każdej permutacji i myślę, że wybór definicji <pomoże. To następnie pozwala na sprawdzenie równości ze zwykłej definicji.

To pojęcie http://en.wikipedia.org/wiki/Canonicalization następnie zwykłym równości rozwiązuje również wątpliwości, czy naprawdę masz relacją równoważności. Równoważnością odpowiada partycji. Zwyczajne równość jest oczywiście partycji. Jeśli porównać x i y przez porównanie f (x) i f (r), a następnie przez stosunku równoważnikowym mieć przegrodę z X i Y, a więc równoważnością.

Myśląc o tym więcej, myślę, że sposób, aby zarówno canonicalisation lub równość testowania rozsądnie skuteczny jest praca z dołu do góry, opisywanie każdego węzła z tokenem, którego wartość odzwierciedla wyniki porównań z innymi węzłami, dzięki czemu można porównać węzłów oraz poddrzewa poniżej nich, tylko porównanie tokenów.

Tak więc pierwszym krokiem do równości jest na przykład użycie tabeli mieszania do opisywania każdego liścia z żetonami, które są równe tylko wtedy, gdy wartości na liście są równe. Następnie, na węzłach, których dzieci są tylko liście, użyj np stolik hash przypisać dalsze znaki tak, że tokeny w tych węzłach są równe tylko wtedy, gdy liście, jeśli w ogóle, pod tych węzłów meczu. Następnie można przejść jeszcze jeden krok w górę i tym razem można porównać znaki na dziecko węzłów zamiast recursing dół drzewa tam. Koszt przypisywania żetony w ten sposób powinien być liniowy w wielkości drzew zaangażowanych. Na szczycie drzewa można porównać tylko przez porównanie tokenów u nasady.

Odpowiedział 12/10/2011 o 06:57
źródło użytkownik

głosy
0

Czytałem pytania jak: podane dwa drzewa binarne, na każdej głębokości w drzewie, dowiedzieć się, czy zestaw ich dzieci są objęte w siebie.

To mogą być kodowane stosunkowo łatwe.

Odpowiedział 12/10/2011 o 12:30
źródło użytkownik

głosy
0

Rozwiązanie bez rekursji w 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 wskazówki składni:

  • (1) umieszczenia elementu do tablicy: arr << elem; w tym przypadku for_checkjest szereg tablic
  • (2) wyznaczenie równolegle: t1,t2 = [item1, item2]. Taki sam jakarr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrenprzyjmuje się odpowiednie zachowanie == tego rodzaju przedmiotów. Więcej komunikatów będzie t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- tu mapprodukuje szereg odstępach.
Odpowiedział 15/10/2011 o 16:17
źródło użytkownik

głosy
1

Porównaj drzew przy użyciu podejścia kanonizacyjnego sugerowanego przez @mcdowella . Różnica polega na tym, że moje podejście nie wymaga O(N)dodatkowej pamięci numer wrt węzłów w drzewie:

# 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()wymaga O(N*M)etapów i O(log(N)*M)pamięć wydajność wszystkich węzłów w drzewie, gdzie Noznacza całkowitą liczbę węzłów, Mliczba dzieci każdy węzeł (to jest 2 do drzewa binarnego).

canonorder()można łatwo uogólnić dla każdej reprezentacji węzła i dowolnej liczby dzieci. canonwalk()Wymaga jedynie, że drzewo może uzyskać dostęp do jego natychmiastowe dzieci jako sekwencja.

Funkcja porównania, która wywołuje 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

Przykład

    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)

Wydajność

True
Odpowiedział 15/10/2011 o 21:10
źródło użytkownik

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