2012-06-08 3 views
2

Два дерева называются одинаковыми, если они содержат один и тот же набор элементов, но могут иметь разные структуры. , например. 4,3,5 и 5,4,3Идентичные BST's

Как проверить, идентичны ли эти два дерева?

Один из подходов, о котором я могу думать, - использовать хэширование. Для каждого элемента в первом дереве соответствующий счет увеличивается. Для каждого элемента во втором дереве счетчик уменьшается. В конце, хэш пуст, мы уверены, что деревья идентичны. Сложность времени: O (N) Сложность объекта: O (N)

Но этот подход не использует, является ли дерево BST или простым BINARY TREE.

Подход 2: Проведите обход обоих деревьев в массиве. Мы имеем два массива со отсортированными данными. Ли линейный поиск, чтобы проверить, идентичны ли массивы, нет. Сложность времени: O (N) Сложная сложность: O (N)

Но, я хотел знать, что существует ли какое-либо лучшее решение?

+1

Что вы подразумеваете под «двумя деревьями одинаковыми»? Означает ли это, что (1) они содержат один и тот же набор элементов, (2) формы деревьев одинаковы, но они могут содержать разные элементы, (3) оба элемента и формы одинаковы или (4) что-то еще? Мне кажется, что люди неявно принимают разные интерпретации и дают ответы на разные вопросы. –

+0

«два дерева одинаковы» означает, что они содержат один и тот же набор элементов. –

+0

Пожалуйста, отредактируйте этот вопрос. Как вы можете видеть из всех этих разных интерпретаций, «деревья одинаковы» неоднозначны. –

ответ

1

Ваше последнее решение кажется лучше, чем ваше прежнее, так как в то время как наихудшее время для последнего - O (N), лучший случай (где разные элементы в обходных порядках отличаются) будет Ω (1), тогда как для первого в лучшем случае все равно будет Ω (N), поскольку вам нужно дождаться конца, чтобы точно знать.

Как оптимизация для последнего, вы не могли бы просто использовать указатель на текущий элемент в каждом дереве, а не делать копии всех данных? Алгоритм обхода дерева по порядку (по крайней мере, с естественным порядком) не требует создания каких-либо копий данных. Таким образом, ваша космическая сложность будет равна O (1).

+0

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

+0

Я не считаю, что стек необходим, если вы используете итеративный алгоритм для обхода двоичного дерева, если у ваших дочерних узлов есть указатели на своих родителей (что, по общему признанию, увеличило бы размер дерева от одного без обратных указателей примерно такого же размера, как массив указателей на узлы. Хотя самобалансирующийся BST может понадобиться таким указателям). Вы могли бы просто пройти весь путь вниз по пути с наименьшим значением, затем просто продолжайте идти к родительскому и идите по следующему пути. Если у родителя нет второго пути, просто перейдите к его родительскому элементу и повторите попытку, пока не достигнете корня. – JAB

+1

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

1

Проблема с хэшированием - если у вас есть два дерева поиска двоичных данных, {2, 1, 3} и {0, 0, 6}, они могут иметь одинаковый общий хэш-код, и у вас все еще есть разные элементы.

Метод обхода пути, вероятно, самый эффективный, и я подозреваю, что O(n) - лучшее, что вы когда-либо могли получить, учитывая, что вам необходимо провести сравнительные сравнения n.

+0

Что делать, если мы реализуем наше собственное хеширование (предположим, что мы собираемся реализовать его в C & not JAVA)? –

+0

Если вы не можете гарантировать 'item1.HashCode() + item2.HashCode()! = Item3.HashCode() + item4.HashCode()' для всех комбинаций 'item1',' item2', 'item3',' item4 'если' item1' и 'item2' не' item3' и 'item4', добавление хэшей вместе никогда не является достаточным условием для проверки равенства. –

+0

Другой способ взглянуть на это: 'HashCode()' возвращает 'int', который имеет 2^32 - 1 возможных значений. Ваше двоичное дерево может содержать потенциально бесконечные значения, каждый из типов 'int', с' 2^32n-1' возможных комбинаций (где 'n' - количество элементов в вашем bst). Вы не можете сопоставить каждый из них с уникальным хеш-кодом. –

5

Это отвечает на вопрос, как изначально сформулированный, то есть после идентификация деревьев в смысле одной и той же структуры и элементов.

Сравнение последовательности (или любой другой) последовательности не будет работать: разные деревья имеют одинаковый обход. Например, деревья

enter image description here
[source]

имеют то же самое в порядка обхода a,b,c,d,e. Вы можете использовать two (different) traversals и проверить, одинаковы ли они соответственно.

Классическое решение, однако, является рекурсивный алгоритм:

equal Leaf(x)  Leaf(y)  => x == y 
| equal Node(x,l1,r1) Node(y,l2,r2) => x == y && equal(l1,l2) && equal(r1,r2) 
| equal _    _    => false; 

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


Что касается обновленного вопроса, то проверка обходных порядков для элементарного равенства достаточно. Обратите внимание, что по определению обход BST-порядка в порядке сортированного списка сохраненных элементов, поэтому этот подход является правильным. В рекурсивной форме, это алгоритм:

inorder Leaf(x)  = [x] 
| inorder Node(x,l,r) = (inorder l) ++ [x] ++ (inorder r); 

    equal []  []  = true 
| equal x1::r1 x2::r2 = x1 == x2 && (equal r1 r2) 
| equal _  _  = false; 

    sameElems t1 t2 = let 
         e1 = inorder t1 
         e2 = inorder t2 
        in 
         equal e1 e2 
        end; 

Если список конкатенация может быть сделана во время O (1), это работает во время Q (п) и пространство Q (п); итерационные решения, безусловно, такие же хорошие, и, вероятно, лучшие константы.

Если вы хотите выполнить эту проверку в o (n) времени, вы даже не можете смотреть на каждый элемент. В общем, оба дерева содержат попарно разные элементы, поэтому вы не можете использовать какие-либо диапазоны, поэтому для каждой общей проверки равенства элемента требуется время Ω (n) (предполагайте более быстрый алгоритм и постройте два дерева, для которых он не выполняется).

Пространство может быть выполнено лучше, чем O (n). Если вы реализуете в порядке cleverly ¹, вам потребуется только O (1) дополнительное пространство (указатель на текущие элементы, некоторые управляющие счетчики/флаги).


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