2 binární stromy jsou stejné, nebo ne

hlasů
7

Možné Duplicitní:
Určit, zda dva binární stromy jsou si rovny

Dostal rozhovor včera otázka mě dostala, je to tady:

Popis

Existuje 2 binary trees, zkontrolujte, jestli jsou si rovny.

Jsou stejné tehdy a jen tehdy, pokud tree1->child == tree2->childa jeden strom je vlevo a vpravo children can be swapped with each other.

Například:

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

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

Nějaké nápady jsou vítány.

Položena 12/10/2011 v 01:18
zdroj uživatelem
V jiných jazycích...                            


6 odpovědí

hlasů
9

Operátory rovnosti jsou tranzitivní: Je-li A = B a B = C, pak A = B = C, takže A = C.

Operátory rovnosti jsou reflexivní: A = A, B = B a C = C bez ohledu na to, jaké jsou jejich hodnoty.

Operátory rovnosti jsou symetrické. Je-li A = B, pak B = A. (Nezáleží na tom, v jakém pořadí jsou in.)

Nyní, při pohledu na definici, že ti dal:

Strom se rovná jiný strom v případě, že děti jsou si rovny. Uvidíme. Dá se předpokládat, že uzly jsou srovnávány na dně, anebo definice je docela k ničemu. Ale oni neobtěžují říct, jak vyřešit tuto srovnání, a celá definice, které vám dal závisí na něm.

Stručně řečeno, je to mizerný otázka.

Podívejme se, co se stane, když se rozhodneme chceme pokusit rozluštit otázku, ačkoli.

Ale počkat, ale také říci, že dvě děti jakéhokoliv stromu mohou být zaměněny. Přidá omezení, že jakýkoliv strom, který se rovná něco jiného (včetně sebe), musí být rovna svým zrcadlovým obrazem. A jakékoliv varianty dětí svých podstromů jsou prohozeny.

A nezapomeňte, že je to má být vyhledávací strom. Proto můžeme zřejmě předpokládat, že dvě různé vyhledávací stromy, které jsou zpracovány stejným algoritmem musí dávat stejný výsledek, pokud jsou stejné. Takže, pokud bychom přejít kolem prvků stromu, pak by to mít vliv na vyhledávání podle času. Takže stromy, které nemají každý uzel na místě nejsou navzájem rovné.

Uvedení, že společně s „swap“ vlastnost této rovnosti můžeme vidět, že to není platná definice rovnosti. (Pokud se budeme snažit ji aplikovat, a pak se ukáže, že jen stromy, které mají stejný uzel pro každý uzel na určité úrovni jsou si rovny, a jen pro sebe, který rozbíjí Reflexivita část operátorem rovnosti.)

Odpovězeno 12/10/2011 v 01:24
zdroj uživatelem

hlasů
3

Pokud se rozhodnete jejich definici „rovnosti“ s flip-invariance, budete porušovat definici rovnosti. Tato definice není ani smysl, protože to není, jak binární vyhledávací stromy jsou si rovny (pokud má každý uzel ukazatel, který podstrom je „větší“ a která je „menší“).

Máte dvě možnosti přiměřených definicím:

  1. topologické (flip-agnostik) ekvivalence (V takovém případě nelze hovořit o „binární vyhledávací strom“, protože je to netřídí):

    tree1==tree2 prostředek set(tree1.children)==set(tree2.children)

  2. normální vyhledávací strom (flip-pečující) rovnocennost:

    tree1==tree2 prostředek list(tree1.children)==list(tree2.children)

Pro binární stromy, budou výše uvedené definice pracovat jako napsané v jakémkoli jazyce, který podporuje listi setdatové typy (python sad bude dusit však na unhashable datové typy). Nicméně, Níže jsou některé další obsáhlá a ošklivé C / Java-jako definice:

  1. topologická ekvivalence:

    t1==t2 prostředek (t1.left==t2.left and t1.right==t2.right) or (t1.left==t2.right and t1.right==t2.left)

  2. tříděný strom ekvivalence:

    t1==t2 prostředek (t1.left==t2.left and t1.right==t2.right)

Výše uvedené definice jsou rekurzivní; to znamená, že předpokládají, rovnost byla definována pro podstromy a bází případů už kterou má.


Sidenote:

Citace: tree1-> dítě == tree2-> dítě

Toto není platný příkaz, protože strom uzel nemá jediné dítě.

Odpovězeno 12/10/2011 v 02:20
zdroj uživatelem

hlasů
7

Nemyslím si, že je to nesmyslné otázka. Jednoduchým řešením je rekurzivní

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

To může být velmi nákladné, například v případě, kdy máme dva velké stromy podobného tvaru, kde jsou všechny non-koncové uzly mají stejnou hodnotu přiřazenou a koncové uzly jednoho jsou permutace listových uzlů jiného.

Chcete-li získat kolem tohoto byste mohli především změny vlevo a vpravo podle potřeby tak, aby vlevo <pravdu, nějakou rekurzivní definice <. To by mohlo být také dražší, ale mnohem méně, než kontrolou každé permutace, a myslím, že volba definice <by pomohlo. To by pak umožní kontrolovat a mužů s běžnou definicí.

Toto pojetí http://en.wikipedia.org/wiki/Canonicalization následované obyčejným rovnosti řeší také otázky o tom, zda opravdu mají vztah rovnocennosti. Vztah ekvivalence je ekvivalentní k oddílu. Obyčejný rovnost je samozřejmě partition. Srovnáme-li x a y porovnáním f (x) a f (y) a následně vztahu ekvivalence máte oddíl z X a Y, a proto relace ekvivalence.

Trochu víc přemýšlet o tom, myslím, že způsob, jak buď canonicalisation nebo rovnost testování přiměřeně efektivní je práce zdola nahoru, vyložit každý uzel s tokenu, jehož hodnota odráží výsledek srovnání s jinými uzly, takže si můžete porovnat uzly a pod nimi podstromy, prostě být porovnávání tokeny.

Takže první krok pro dosažení rovného postavení je například použít hash tabulky opatřit každý list s žetony, které jsou stejné, pouze pokud jsou hodnoty v listech jsou si rovny. Potom pro uzly, jejichž jediným děti jsou listy, použijte např hash tabulky přiřadit další žetony, takže žetony v těchto uzlech jsou shodné pouze v případě, že listy, pokud vůbec, pod tyto uzly utkání. Pak můžete jít ještě jeden krok nahoru, a tentokrát si můžete porovnat žetony na dětské uzly namísto tam rekurzi ze stromu. Náklady na přiřazení žetony tímto způsobem by mělo být lineární ve velikosti stromů zúčastněných. Na vrcholu si můžete porovnat stromy jen srovnáním tokeny u kořene.

Odpovězeno 12/10/2011 v 06:57
zdroj uživatelem

hlasů
0

Četl jsem na otázky jako: daný dva binární stromy, pro každou hloubku ve stromě, zjistit, zda jsou jejich dětský set zahrnuty v sobě.

To může být kódovány poměrně snadné.

Odpovězeno 12/10/2011 v 12:30
zdroj uživatelem

hlasů
0

Řešení bez rekurze v 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

syntaxe tipy Ruby:

  • (1) uvedení prvku do pole: arr << elem; v tomto případě for_checkje pole polí
  • (2) paralelní přiřazení: t1,t2 = [item1, item2]. Stejný jakoarr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrenpředpokládá odpovídající chování == pro tento druh objektů. Upovídanejší bude t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- zde mapprodukuje řadu valech.
Odpovězeno 15/10/2011 v 16:17
zdroj uživatelem

hlasů
1

Porovnávat stromů pomocí přístupu svatořečení navrhl @mcdowella . Rozdíl je v tom, že můj přístup nevyžaduje O(N)přídavné paměti wrt počet uzlů ve stromu:

# 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()vyžaduje O(N*M)kroky a O(log(N)*M)paměť, čímž se získá všechny uzly na stromě, kde Nje celkový počet uzlů, Mpočet dětí má každý uzel (to je 2 pro binární stromy).

canonorder()lze snadno zobecnit pro jakoukoli reprezentaci uzlu a libovolný počet dětí. canonwalk()vyžaduje pouze to, že strom může přístup k jeho přímé potomky jako sekvence.

Funkce srovnání který volá 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

Příklad

    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)

Výstup

True
Odpovězeno 15/10/2011 v 21:10
zdroj uživatelem

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