2 бинарных деревьев, равны или нет

голоса
7

Можно создать дубликат:
Определить , если два бинарных деревьев равны

вчера Получил интервью, вопрос у меня, вот это:

Описание

Есть 2 binary trees, проверить , если они равны.

Они равны тогда и только тогда , когда tree1->child == tree2->child, и одно дерево слева и справа children can be swapped with each other.

Например:

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

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

Любые идеи приветствуются.

Задан 12/10/2011 в 01:18
источник пользователем
На других языках...                            


6 ответов

голоса
9

Операторы равенства транзитивны: Если А = В и В = С, то А = В = С, так A = C.

Операторы равенства не рефлексивно: A = A, B = B, и C = C, независимо от того, каковы их ценности.

Операторы равенства симметричны. Если A = B, то В = A. (Это не имеет значения, в каком порядке они находятся.)

Теперь, принимая взглянуть на определение они дали вам:

Дерево равно другое дерево, если дети равны. Посмотрим. Можно предположить, что узлы сравниваются на дне, или же определение довольно бесполезно. Но они не удосужились сказать вам, как решить, что сравнение, и в целом определение они дали вам зависит от него.

Короче говоря, это дерьмовый вопрос.

Давайте посмотрим, что произойдет, если мы решим, что мы хотим, чтобы попытаться разгадать этот вопрос, хотя.

Но подождите, они также говорят, что двое детей любого дерева можно поменять местами. Это добавляет ограничение , что любое дерево , которое равно все остальное ( в том числе и себя) должно быть равно его зеркальным отражение. И любые вариации детей его поддеревьев могли быть обменены.

И помните , что это должно быть поиск дерево. Таким образом, мы можем предположить , что два различных дерева поиска, которые обрабатываются с помощью того же алгоритма должны дать тот же результат , если они равны. Таким образом, если мы переключаемся вокруг элементов дерева, то время поиска будет затронуто. Таким образом, деревья , которые не имеют каждый узел в месте, не равны друг другу.

Полагая, что вместе с «съемном» свойством этого равенства, мы можем видеть, что это не является допустимым определением равенства. (Если мы попытаемся применить его, то получается, что только деревья, которые имеют один и тот же узел для каждого узла на определенном уровне, равны, и только для себя, который ломает рефлексивности часть оператора равенства.)

Ответил 12/10/2011 в 01:24
источник пользователем

голоса
3

Если вы реализуете свое определение «равенства» с флип-инвариантности, вы будете нарушать определение равенства. Определение даже не имеет смысла, потому что это не так, как бинарные деревья поиска, равны (если каждый узел не имеет указатель на который поддерево «больше» и что «меньшее»).

У вас есть два варианта разумных определений:

  1. топологический (флип-агностик) эквивалентности (в этом случае вы не можете назвать это «бинарное дерево» , потому что это не отсортирован):

    tree1==tree2 означает set(tree1.children)==set(tree2.children)

  2. нормальное дерево поиска (флип-заботливый) эквивалентность:

    tree1==tree2 означает list(tree1.children)==list(tree2.children)

Для бинарных деревьев, приведенные выше определения будут работать как написаны на любом языке , который поддерживает listи setтипы данных (наборы Python будет заглушают однако на unhashable типов данных). Тем не менее, ниже приведены некоторые более многословные и уродливые / Java-подобные определения C:

  1. топологической эквивалентности:

    t1==t2 означает (t1.left==t2.left and t1.right==t2.right) or (t1.left==t2.right and t1.right==t2.left)

  2. отсортированный дерево эквивалентности:

    t1==t2 означает (t1.left==t2.left and t1.right==t2.right)

Определения выше, являются рекурсивными; то есть, они предполагают равенство было определено для поддеревьев и базовых случаях уже, что он имеет.


Примечание:

цитата: tree1-> ребенок == tree2-> ребенок

Это не является правильным утверждение, так как узел дерева не имеет ни одного ребенка.

Ответил 12/10/2011 в 02:20
источник пользователем

голоса
7

Я не думаю, что это неразумно вопрос. Простым решением является рекурсивным

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

Это может быть очень дорогим, например, в том случае, когда мы имеем два больших дерев одинаковой формы, где все узлы без листьев имеют то же значение, связанные и листовые узлы являются одной перестановкой листовых узлов другого.

Чтобы обойти это можно в первую очередь изменения влево и вправо по мере необходимости так, чтобы слева <вправо, для некоторого рекурсивного определения <. Это также может быть дорогим, но гораздо меньше, чем проверяя каждую перестановку, и я думаю, что выбор определения <поможет. Это позволит затем проверить на равенство с обычным определением.

Это понятие http://en.wikipedia.org/wiki/Canonicalization с последующим обычным равенством также решает вопросы , действительно ли у вас есть отношение эквивалентности. Отношение эквивалентности эквивалентно перегородке. Обыкновенное равенство очевидно раздел. Если сравнивать х и у, сравнивая Р (х) и Р (у) , а затем отношения эквивалентности у вас есть разбиение х и у, и , следовательно, отношение эквивалентности.

Думая об этом больше, я думаю, что способ сделать либо canonicalisation или равенство тестирования достаточно эффективна для работы снизу вверх, аннотирования каждый узел с маркером, значение которого отражает результат сравнения с другими узлами, так что вы можете сравнить узлы и поддеревья под ними, просто сравнивая маркеры.

Таким образом, первый шаг к равенству является, например, использовать хэш-таблицу для аннотирования каждого листа с маркерами, которые равны только тогда, когда значения в листах равны. Тогда для узлов, чьи только дети листья, используют, например, хэш-таблицу, чтобы назначить дополнительные маркеры, так что маркеры в этих узлах равны только тогда, когда листья, если таковые имеются, под этими узлами матча. Тогда вы можете пойти еще на один шаг, и на этот раз вы можете сравнить маркера на дочерних узлы вместо рекурсии вниз дерева там. Стоимость назначения маркеров таким образом, должен быть линейным размером деревьев, участвующих. На вершине вы можете сравнить деревья просто путем сравнения маркеров в корне.

Ответил 12/10/2011 в 06:57
источник пользователем

голоса
0

Я прочитал вопросы, как: даны два бинарных деревьев, для каждой глубины в дереве, выяснить, является ли покрыты их детский набор друг в друге.

Это может быть закодировано относительно легко.

Ответил 12/10/2011 в 12:30
источник пользователем

голоса
0

Решение без рекурсии в Рубине

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

Рубиновые советы синтаксис:

  • (1) положить элемент в массив: arr << elem; в этом случае for_checkявляется массивом массивов
  • (2) параллельное назначение: t1,t2 = [item1, item2]. Такой же какarr = [item1, item2]; t1 = arr[0]; t2 = arr[1]
  • (3) t1_children == t2_childrenпредполагается соответствующее поведение == для такого рода объектов. Подробней будет t1_children.map { |el| el.val } == t2_children.map { |el| el.val }- здесь mapпроизводит множество вальса.
Ответил 15/10/2011 в 16:17
источник пользователем

голоса
1

Сравнение деревьев , используя канонизации подход , предложенный @mcdowella . Разница заключается в том, что мой подход не требует O(N)дополнительной памяти WRT количество узлов в дереве:

# 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()требует O(N*M)шагов и O(log(N)*M)памяти , чтобы получить все узлы в дереве, где Nэто общее число узлов, Mчисло детей , каждый узел имеет (это 2 для бинарных деревьев).

canonorder()может быть легко обобщена для любого представления узлов и любое количество детей. canonwalk()требует только то , что дерево может получить доступ к его непосредственным потомкам в виде последовательности.

Функция сравнения , которая требует 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

пример

    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)

Вывод

True
Ответил 15/10/2011 в 21:10
источник пользователем

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