Для заданного двоичного дерева поиска максимального двоичного поиска поддерева

голоса
13

Для данного бинарного дерева, найти наибольшее поддерево, которое также бинарное дерево поиска?

Пример:

Входные данные:

                   10
               /         \
             50           150
            /  \         /   \
          25    75     200    20
         / \   / \    /  \    / \
        15 35 65 30  120 135 155 250 

Вывод:

                   50
                  /   \
                 25   75
                / \   /
               15 35  65
Задан 02/07/2010 в 06:15
источник пользователем
На других языках...                            


7 ответов

голоса
0

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

  • Выполните заказовМои обхода элементов (ВИЗИТ ВЛЕВО, ВИЗИТ ROOT, ВИЗИТ ПРАВЫЙ)
  • Делая это, получить данные узла, сравнить ли меньше, чем следующие данные данные предыдущего узла. Если да, то приращение счетчика на 1. Хранить начальный узел.
  • Когда сравнение не удается, сохранить конечный узел и сброс счетчика на 0
  • Хранить эту информацию (счетчик, начало, конец) узел в структуре массива, чтобы позже найти который, имеющие максимальное значение и что даст вам длинное бинарный поиск суб дерева
Ответил 02/07/2010 в 06:26
источник пользователем

голоса
2

Интересный вопрос!

Моя предыдущая попытка была moronically неправильно!

Вот еще одна попытка (надеюсь исправить это время).

Я предполагаю, что дерево связано.

Предположим , что для каждого узла п дерева, вы имели множество потомков п, S п со свойством

  • Для каждого члена х S п , единственный путь из п х является Двоичное дерево (это всего лишь путь, но вы можете считать это дерево).

  • Для каждого потомка у й, такие , что путь от п к у является БСТОМ, у находится в S п .

Множество узлов S п , дает наибольший BST укоренились в п.

Мы можем построить S п для каждого узла, выполнив глубины первого поиска по дереву, и переходя в информации о пути (пути от корня до текущего узла) и обновление набора узлов в пути, отступает вдоль пути.

Когда мы посещаем узел, мы идем вверх по дорожке, и проверить, если свойство BST выполнено для этого отрезок пути шел до сих пор. Если да, то мы добавим текущий узел к соответствующему набору узла пути мы просто гуляли к. Мы перестаем ходить по пути в момент, когда свойство BST нарушается. Проверка, если отрезок пути мы шли до сих пор является БСТ может быть сделан в O (1) время, в течение времени обработки всего вывода (PATH_LENGTH) времени, для каждого узла.

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

Время , необходимое для этого является суммой глубин узлов (в худшем случае), и что представляет собой О (NlogN) в среднем случае (см раздел 5.2.4 http://www.toves.org/books/ данные / CH05-деревья / index.html ), но O (N ^ 2) в худшем случае.

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

Псевдо-код может быть что-то вроде:

static Tree void LargestBST(Tree t)
{
    LargestBST(t, new List<Pair>());
    // Walk the tree and return the largest subtree with max |S_n|.
}

static Tree LargestBST(Tree t, List<Pair> path)
{
    if (t == null) return;

    t.Set.Add(t.Value);

    int value = t.Value;
    int maxVal = value;
    int minVal = value;

    foreach (Pair p in path)
    {
        if (p.isRight)
        {
            if (minVal < p.node.Value)
            {
                break;
            }
        }

        if (!p.isRight)
        {
            if (maxVal > p.node.Value)
            {
                break;
            }
        }

        p.node.Set.Add(t.Value);

        if (p.node.Value <= minVal)
        {
            minVal = p.node.Value;
        }

        if (p.node.Value >= maxVal)
        {
            maxVal = p.node.Value;
        }
    }

    Pair pl = new Pair();
    pl.node = t;
    pl.isRight = false;

    path.Insert(0, pl);
    LargestBST(t.Left, path);

    path.RemoveAt(0);

    Pair pr = new Pair();
    pr.node = t;
    pr.isRight = true;

    path.Insert(0, pr);

    LargestBST(t.Right, path);

    path.RemoveAt(0);

}
Ответил 02/07/2010 в 14:13
источник пользователем

голоса
0
GetLargestSortedBinarySubtree(thisNode, ref OverallBestTree)
    if thisNode == null
        Return null
    LeftLargest = GetLargestSortedBinarySubtree(thisNode.LeftNode, ref OverallBestTree)
    RightLargest = GetLargestSortedBinarySubtree(thisNode.RightNode, ref OverallBestTree)
    if LeftLargest.Max < thisNode.Value & RightLargest.Min > thisNode.Value
        currentBestTree = new BinaryTree(LeftLargest, thisNode.Value, RightLargest)
    else if LeftLargest.Max < thisNode.Value
        currentBestTree = new BinaryTree(LeftLargest, thisNode.Value, null)
    else if RightLargest.Min > thisNode.Value
        currentBestTree = new BinaryTree(null, thisNode.Value, RightLargest)
    else
        currentBestTree = new BinaryTree(null, thisNode.Value, null)
    if (currentBestTree.Size > OverallBestTree.Size)
        OverallBestTree = currentBestTree
    return currentBestTree

Как BlueRaja отметил, что этот алгоритм не является правильным.

Это должно быть действительно называется GetLargestSortedBinarySubtreeThatCanBeRecursivelyConstructedFromMaximalSortedSubtrees.

Ответил 02/07/2010 в 19:46
источник пользователем

голоса
3

Предыдущий алгоритм (см пересмотров) был O(n^2)- мы можем обобщить его O(n log n), заметив , что факты:

  1. Если Ь является корнем из крупнейших BST и b.left.value < b.value, затем b.leftтакже в BST ( то же самое для b.right.value ≥ b.value)
  2. Если Ь является корнем из крупнейших BST и также в BST, то каждый узел между а и Ь в BST.

Таким образом , если с между а и Ь, и с не является в BST корни на Ь, ни является ( в силу (2)) . Используя этот факт, мы можем легко определить , если узел находится в BST коренится любыми данными предка. Мы будем делать это, передавая узел в функцию вместе со списком своих предков, и ассоциированная мин / maxValues , что нынешний ребенок-узел должен удовлетворять , если в самом деле , что предок был корень из крупнейших BST (мы» позвоню этот список ancestorList). Мы будем хранить всю коллекцию потенциальных корней вoverallRootsList

Давайте определим структуру, называемую potentialRoot следующим образом:

Каждый potentialRoot содержит следующие значения:
* узел : Узел мы рассматриваем для корня BST
* MinValue и MaxValue : диапазон другой узел должен находиться в пределах , чтобы быть частью BST коренится узлом (различной для каждого узла)
* подузлами : список остальных узлов в крупнейших BST коренится узлом

Псевдокод выглядит следующим образом (обратите внимание , что все списки , упомянутые списки potentialRoots) :

FindLargestBST(node, ancestorList):
    leftList, rightList = empty lists
    for each potentialRoot in ancestorList:
        if potentialRoot.minValue < node.Value ≤ potentialRoot.maxValue:
            add node to potentialRoot.subNodes (due to (1.))
            (note that the following copies contain references, not copies, of subNodes)
            add copy of potentialRoot to leftList, setting maxValue = node.Value
            add copy of potentialRoot to rightList, setting minValue = node.Value

    add the potentialRoot (node, -∞, +∞) to leftList, rightList, and overallRootsList
    FindLargestBST(node.left, leftList)
    FindLargestBST(node.right, rightList)

В конце overallRootsListбудет список npotentialRoots, каждый со списком подузлами. Один с самым большим списком подузлами ваш BST.

Поскольку существует <treeHeight значения в ancestorList, а затем ( в предположении , что дерево является сбалансированным), алгоритм работает вO(n log n)

Ответил 02/07/2010 в 20:21
источник пользователем

голоса
0
root(Tree L A R) = A

MaxBST(NULL) = (true, 0, NULL)
MaxBST(Tree L A R as T) = 
  let
    # Look at both children
    (L_is_BST, L_size, L_sub) = MaxBST(L)
    (R_is_BST, R_size, R_sub) = MaxBST(R)
  in
  # If they're both good, then this node might be good too
  if L_is_BST and R_is_BST and (L == NULL or root(L) < A) and (R == NULL or A < root(R))
  then (true, 1 + L_size + R_size, T)
  else
       # This node is no good, so give back the best our children had to offer
       (false, max(L_size, R_size), if L_size > R_size then L_sub else R_sub)

Смотрит на каждом узле дерева ровно один раз, так что работает в O (N).

Edit: Crud, это не считает, что он может оставить некоторые части поддерева. Когда я прочитал поддерево, я предположил, «все дерево с корнем в некотором узле». Я могу вернуться, чтобы исправить это позже.

Ответил 03/07/2010 в 01:15
источник пользователем

голоса
4

Этот ответ ранее содержалось О (п п) войти алгоритм , основанный на ссылку / срезанных деревьев. Вот более простой (п) вывод раствор.

Ядро представляет собой процедуру, которая принимает узел, единственного максимум BSST укоренились на лев ребенка, единственный максимум BSST коренится в его праве ребенка, а также указатели на крайние левые и правые большинства элементов этих BSSTs. Это разрушает его входы (можно избежать стойкими структур данных) и создает уникальный максимальный BSST с корнем в данном узле, вместе с его минимальным и максимальными элементами. Все узлы BSST прокомментированы с числом потомков. Как и прежде, эта процедура вызывается многократно из обхода после заказа. Чтобы восстановить суб-дерево, помните корень крупнейшего BSST; ее реконструкции требует только простого обхода.

Я буду относиться к левому BSST только; право является симметричным. Если корень левого BSST больше , чем новый корень, то все поддерево удаляется, и новый корень теперь самым левое. В противном случае, старая левая узел еще самый левые. Начиная с самого правого узла левого BSST и движется вверх, найти первый узел , который меньше или равен корню. Его право ребенок должен быть удален; Теперь заметим , что в силу свойства BST, никакие другие узлы не должны идти! Приступить к корню левого BSST, обновление счетчиков , чтобы отразить удаление.

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


EDIT: коллективно пути, пройденные являются максимальным прямолинейными путями в BST, для левого отдела позвоночника и правого позвоночника, за исключением. Например, на входе

              H
             / \
            /   \
           /     \
          /       \
         /         \
        /           \
       /             \
      D               L
     / \             / \
    /   \           /   \
   /     \         /     \
  B       F       J       N
 / \     / \     / \     / \
A   C   E   G   I   K   M   O

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

              H
             / \
            /   \
           /     \
          /       \
         /         \
        /           \
       /             \
      D               L
     / h             h \
    /   h           h   \
   /     h         h     \
  B       F       J       N
 / d     d h     h l     l \
A   C   E   G   I   K   M   O
Ответил 03/07/2010 в 17:46
источник пользователем

голоса
1

КРУПНЕЙШИЙ бинарное дерево поиска в бинарном дереве:

Есть два способа, которыми мы можем подойти к этой проблеме,

я) Самый большой BST не индуцируется (от узла, все его дети не должны удовлетворять условию BST)

б) сам большой БСТ индуцированный (от узла, все его дети будут удовлетворять условию BST)

Мы будем обсуждать о наибольшем BST (не индуцируется) здесь. Мы будем следить за подход "снизу вверх" (Post порядок обхода), чтобы решить эту проблему.

а) Reach узел листа

б) узел дерева (от листа) будет возвращать объект TreeNodeHelper, который имеет следующие поля в нем.

public static class TreeNodeHelper {
        TreeNode node;
        int nodes;
        Integer maxValue;
        Integer minValue;
        boolean isBST;


        public TreeNodeHelper() {}

        public TreeNodeHelper(TreeNode node, int nodes, Integer maxValue, Integer minValue, boolean isBST) {
            this.node = node;
            this.nodes = nodes;
            this.maxValue = maxValue;
            this.minValue = minValue;
            this.isBST = isBST;
        }      
    }

в) Изначально из листового узла, узлы = 1, isBST = верно, MinValue = MaxValue = node.data. И далее, узлы Count будет увеличено, если она удовлетворяет условию BST.

d) С помощью этого, мы будем проверять состояние BST с текущим узлом. И мы будем повторять то же самое до корня.

е) Из каждого узла два объекта будет возвращен. один за последний максимальный BST и другой для тока BST удовлетворения узлов. Таким образом, от каждого узла (выше) листа (2 + 2) = 4 (2 для левого поддерева и 2 для правого дерева к югу) объекты будут сопоставлены и два будут возвращены.

е) Конечный максимальный объект узла от корня будет самым большим БСТ

ПРОБЛЕМА:

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

 55
  \
   75
  /  \
 27  89
    /  \
   26  95
      /  \
     23  105
         /  \
        20  110

От узлов листа (20110) объекты будут испытаны с узлом (105), он удовлетворяет условие. Но когда он достигает узла (95) листовой узел (20) не удовлетворяет условию BST. Так как это решение для BST (не индуцируется) мы не должны игнорировать узел (105) и узел (110), которая удовлетворяет условию. Таким образом, от узла (95), мы должны возвратиться снова испытывать состояние BST и поймать эти узлы (105, 110).

Полный код для этой реализации доступен в этой ссылке

https://github.com/dineshappavoo/Implementation/tree/master/LARGEST_BST_IN_BT_NOT_INDUCED_VER1.0

Ответил 27/03/2014 в 00:48
источник пользователем

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