Определение того, являются ли 2 BST, представленные массивами, изоморфными или нет - PullRequest
0 голосов
/ 07 ноября 2011

1) Учитывая 2 массива, содержащих элементы полного двоичного дерева (уровень за уровнем), без фактической реконструкции дерева (т. Е. Путем выполнения перестановок в массиве), как я могу найти, изоморфны ли эти 2 массива или нет?

2) Лучшее решение, если одно изоморфное дерево образует дерево двоичного поиска.

обновление например,

     5 
    / \
    4  7
   /\  /\
  2  3 6 8

может быть представлен в массиве как 5 4 7 2 3 6 8

Изоморфные деревья - это деревья, которые можно преобразовать друг в друга вращением вокруг узлов

     5 
    / \
    4  7
   /\  /\
  2  3 6 8



     5 
    / \
    4  7
   /\  /\
  3  2 6 8



     5 
    / \
    4  7
   /\  /\
  3  2 8 6



     5 
    / \
    7  4
   /\  /\
  8  6 3 2

Ответы [ 4 ]

2 голосов
/ 08 ноября 2011

Для первой задачи:

Немного обозначений:

  • t0, t1 - деревья
  • значение (t) - число, хранящееся в узле
  • left (t) - левое поддерево
  • right (t) - правое поддерево

t1 и t2 изоморфны, тогда как t1и t2 пустые,

или value (t1) == value (t2)

и

или left(t1) изоморфны left(t2), а right(t1) изоморфны right(t2),

или left(t1) изоморфно right(t2), а right(t1) изоморфно left(t2)

Предполагая, что деревья хранятся в массивах, так что элемент 0 является корнем ии если t является индексом внутреннего узла, 2t+1 и 2t+2 являются индексами его непосредственных потомков, прямая реализация:

#include <stdio.h>

#define N 7

int a[] = { 5, 4, 7, 2, 3, 6, 8 };
int b[] = { 5, 7, 4, 6, 8, 2, 3 };

int
is_isomorphic (int t1, int t2)
{
  if (t1 >= N && t2 >= N)
    return 1;

  if (a [t1] != b [t2])
    return 0;

  return ((is_isomorphic (2*t1 + 1, 2*t2 + 1)
           && is_isomorphic (2*t1 + 2, 2*t2 + 2))
          || (is_isomorphic (2*t1 + 1, 2*t2 + 2)
              && is_isomorphic (2*t1 + 2, 2*t2 + 1)));
}

int main ()
{
  printf ("%s\n", (is_isomorphic (0, 0) ? "yes" : "no"));
  return 0;
}

Для второй задачи на каждом шаге мы сравниваемподдерево a с меньшим корнем к поддереву b с меньшим корнем и затем поддерево a с большим корнем к поддереву b с большим корнем (меньше и больше текущих корней a и b).

int
is_isomorphic_bst (int t1, int t2)
{
  if (t1 >= N && t2 >= N)
    return 1;

  if (a [t1] != b [t2])
    return 0;

  int t1l, t1r, t2l, t2r;
  if (a [2*t1 + 1] < a [t1] && a [t1] < a [2*t1 + 2])
    {
      t1l = 2*t1 + 1;
      t1r = 2*t1 + 2;
    }
  else if (a [2*t1 + 1] > a [t1] && a [t1] > a [2*t1 + 2])
    {
      t1l = 2*t1 + 2;
      t1r = 2*t1 + 1;
    }
  else
    return 0;

  if (b [2*t2 + 1] < b [t2] && b [t2] < b [2*t2 + 2])
    {
      t2l = 2*t2 + 1;
      t2r = 2*t2 + 2;
    }
  else if (b [2*t2 + 1] > b [t2] && b [t2] > b [2*t2 + 2])
    {
      t2l = 2*t2 + 2;
      t2r = 2*t2 + 1;
    }
  else
    return 0;

  return is_isomorphic_bst (t1l, t2l) && is_isomorphic_bst (t1r, t2r);
}
2 голосов
/ 07 ноября 2011

Вы можете выполнить обход дерева по порядку на обоих из них одновременно и проверить, совпадают ли элементы.

0 голосов
/ 16 марта 2013

Для BST:

  1. Возьмите первые элементы обоих массивов и сопоставьте.Если не равны, то BST не будут одинаковыми.
  2. Найдите первых левых потомков , которые не были отсканированы (в позициях leftPos1 и leftPos2) и сопоставьте.Если не совпадают, то BST не совпадают.
  3. Найдите первых правых потомков , которые не были отсканированы (в позициях rightPos1 и rightPos2) и сопоставьте.Если не совпадают, то BST не совпадают.
  4. Если оба левых и правых потомка совпадают, рекурсивно выполняются одни и те же операции над двумя парами sublists / subtree (из leftPos1 и leftPos2) и (из rightPos1 и rightPos2).Родителем этого поддерева является первый элемент массива.

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

#include <stdio.h>

#define BOOL int
#define TRUE 1
#define FALSE 0

BOOL isLeft(int parent, int child) {
    return child <= parent;
}

BOOL isRight(int parent, int child) {
    return child > parent;
}

BOOL isBelongToChild(int parent, int child, int value) {
    if (isLeft(parent, child) && (isLeft(parent, value))) {
        return TRUE;
    }
    if (isRight(parent, child) && (isRight(parent, value))) {
        return TRUE;
    }
    return FALSE;
}

int getLeftPosition(int * array, int size, int parent, BOOL parentExists) {
    int i;

    int first = *array;
    for (i = 1; i < size; i++) {
        int value = *(array + i);
        if (! isBelongToChild(parent, first, value)) {
            continue;
        }
        if (isLeft(first, value)) {
            return i;
        }
    }
    return -1;
}

int getRightPosition(int * array, int size, int parent, BOOL parentExists) {
    int i;

    int first = *array;
    for (i = 1; i < size; i++) {
        int value = *(array + i);
        if (! isBelongToChild(parent, first, value)) {
            continue;
        }
        if (isRight(first, value)) {
            return i;
        }
    }
    return -1;
}

BOOL areSame(int * array1, int pos1, int * array2, int pos2) {
    if (pos1 == -1 && pos2 == -1) {
        return TRUE;
    } else if (*(array1 + pos1) == *(array2 + pos2)) {
        return TRUE;
    } else {
        return FALSE;
    }
}

BOOL isSameBst(int * array1, int size1, int * array2, int size2, int parent, BOOL parentExists) {
    if (0 == size1 && 0 == size2) {
        return TRUE;
    }
    if (*array1 != *array2) {
        return FALSE;
    }

    int leftPos1 = getLeftPosition(array1, size1, parent, parentExists);
    int leftPos2 = getLeftPosition(array2, size2, parent, parentExists);
    if (! areSame(array1, leftPos1, array2, leftPos2)) {
        return FALSE;
    }
    int rightPos1 = getRightPosition(array1, size1, parent, parentExists);
    int rightPos2 = getRightPosition(array2, size2, parent, parentExists);
    if (! areSame(array1, rightPos1, array2, rightPos2)) {
        return FALSE;
    }

    if (leftPos1 > -1) {
        int result = isSameBst((array1 + leftPos1), size1 - leftPos1, (array2 + leftPos2), size2 - leftPos2, *array1, TRUE);
        if (FALSE == result) {
            return FALSE;
        }
    }
    if (rightPos1 > -1) {
        int result = isSameBst((array1 + rightPos1), size1 - rightPos1, (array2 + rightPos2), size2 - rightPos2, *array1, TRUE);
        if (FALSE == result) {
            return FALSE;
        }
    }
    return TRUE;
}

int main ()
{
    int a[] = { 5, 6, 2, 7, 4 };
    int b[] = { 5, 6, 7, 2, 4 };
    printf ("%s\n", (isSameBst(a, 5, b, 5, 0, FALSE) ? "yes" : "no"));
    return 0;
}
0 голосов
/ 08 ноября 2011

Вначале принимая участие в части (2), меняйте пары узлов - и их потомков - на каждом уровне, по мере необходимости, чтобы превратить каждое дерево в двоичное дерево поиска с левыми узлами <= правые узлы.Это займет время n log n.После того, как вы это сделали, если у вас было дерево двоичного поиска и дерево, изоморфное дереву двоичного поиска, у вас теперь есть два дерева двоичного поиска.Как указывает yi_H, это означает, что обход дерева по порядку покажет одинаковые элементы в одном и том же порядке, если оба дерева изоморфны.Но обход дерева по порядку в дереве, хранящемся в массиве, как в ваших примерах, является лишь особым способом посещения всех элементов массива, поэтому, если деревья изоморфны, два массива должны быть идентичны. </p>

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...