Как преобразовать двоичное дерево в двоичное поиск на месте, т. Е. Мы не можем использовать какое-либо дополнительное пространство

StackOverflow https://stackoverflow.com/questions/2577098

Вопрос

Как преобразовать двоичное дерево в двоичное поисковое дерево на месте, т. Е. Мы не можем использовать какое-либо дополнительное пространство.

Это было полезно?

Решение

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

Я предполагаю, что узлы деревьев выглядят как

struct tree_node {
    struct tree_node * left;
    struct tree_node * right;
    data_t data;
};

Я также предполагаю, что вы можете читать C

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

Требование, которое не будет использоваться дополнительного пространства, нечетное. Временно будет дополнительное пространство, если только на стеке. Я собираюсь предположить, что это означает, что вызывая Malloc или что-то в этом роде, а также что полученное дерево необходимо использовать больше памяти, чем исходное несортированное дерево.

Первое и простое решение состоит в том, чтобы пройти президенцию превышения отклоненного дерева, удаляя каждый узел из этого дерева и выполняя отсортированную вставку в новое дерево. Это O (n + nlog (n)), который o (nЖурнал (n)).

Если это не то, что они хотят, и вам придется использовать вращения и вещи ..... это ужасно!

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

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

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

Придумываясь с вычислениями времени выполнения для второго предложения - это довольно сложный. Сначала я подумал, что это просто будет o (n ^ 2), как пузырь и шейкер сортирует, но я не могу удовлетворить себя, что избегание прохождения поддерева может не победить достаточно, чтобы сделать его немного лучше, чем O (n ^ 2). По сути, пузырь и шейкер тоже сортирует эту оптимизацию, но только на концах, где происходит общее сортировка рано, и вы можете отрубить пределы. С этой версией дерева вы получаете возможность избежать кусочков в середине набора. Ну, как я уже сказал, это, вероятно, смертельно недостаточно.

Другие советы

Преобразовать двоичное дерево на вдвойне связанный список - можно сделать в центре O (n)
Тогда сортируйте его, используя Сортировать слияние, NLOGN
Преобразовать список обратно на дерево - O (N)

Простое решение NLOGN.

Сделайте прохождение потрансляции и от этого создают двоичное дерево поиска.

struct Node * newroot = '\0';

struct Node* PostOrder(Struct Node* root)
{
      if(root != '\0')
      {
          PostOrder(root->left);
          PostOrder(root->right);
          insertBST(root, &newroot);
      }
}

insertBST(struct Node* node, struct Node** root)
{
   struct Node * temp, *temp1;
   if( root == '\0')
   {
      *root == node;
       node->left ==  '\0';
       node->right == '\0';
   }
   else
   {
       temp = *root;
       while( temp != '\0')
       {
           temp1= temp;
           if( temp->data > node->data)
               temp = temp->left;
           else
               temp = temp->right;
       }
       if(temp1->data > node->data)
       {
           temp1->left = node;
       }
       else
       {
           temp1->right = node;
       }
       node->left = node->right = '\0';
    }
}

Сделать следующий алгоритм для достижения решения.

1) Найдите в преемнике порядка, без использования какого-либо места.

Node InOrderSuccessor(Node node)
{ 
    if (node.right() != null) 
    { 
        node = node.right() 
        while (node.left() != null)  
            node = node.left() 
        return node 
    }
    else
    { 
        parent = node.getParent(); 
        while (parent != null && parent.right() == node)
       { 
            node = parent 
            parent = node.getParent() 
        } 
        return parent 
    } 
} 

2) сделать в порядке обхода без использования пространства.

а) Найдите первый узел обхода Oindord. Он должен оставить большинство детей дерева, если он имеет, или оставил от первого правого ребенка, если он имеет, или правильный ребенок сам. б) Используйте выше алгоритм для поиска inoder-преемника первого узла. c) Повторите шаг 2 для всех возвращенных преемников.

Используйте выше 2 алгоритма и выполните форму, обход в порядке на двоичном дереве без использования дополнительного пространства. Сформируйте двоичное дерево поиска при прохождении прохождения. Но сложность O(N2) худший случай.

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

Это ужасный алгоритм, все вокруг - O (N ^ 2) время работы с худшим возможным выходным двоичным деревом, но это приличная отправная точка, прежде чем прийти с чем-то лучше и имеет преимущество в том, что вы сможете написать код для Это примерно в 20 линиях на доске.

Бинарное дерево обычно является Двоичное дерево поиска, и в этом случае преобразование не требуется.

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

#include <stdio.h>
#include <stdlib.h>

typedef int data_t;

struct tree_node {
    struct tree_node * left;
    struct tree_node * right;
    data_t data;
};

        /* a bonsai-tree for testing */
struct tree_node nodes[10] =
{{ nodes+1, nodes+2, 1}
,{ nodes+3, nodes+4, 2}
,{ nodes+5, nodes+6, 3}
,{ nodes+7, nodes+8, 4}
,{ nodes+9, NULL, 5}
,{ NULL, NULL, 6}
,{ NULL, NULL, 7}
,{ NULL, NULL, 8}
,{ NULL, NULL, 9}
        };

struct tree_node * harvest(struct tree_node **hnd)
{
struct tree_node *ret;

while (ret = *hnd) {
        if (!ret->left && !ret->right) {
                *hnd = NULL;
                return ret;
                }
        if (!ret->left ) {
                *hnd = ret->right;
                ret->right = NULL;;
                return ret;
                }
        if (!ret->right) {
                *hnd = ret->left;
                ret->left = NULL;;
                return ret;
                }
        hnd = (rand() &1) ? &ret->left : &ret->right;
        }

return NULL;
}

void insert(struct tree_node **hnd, struct tree_node *this)
{
struct tree_node *ret;

while ((ret= *hnd)) {
        hnd = (this->data  < ret->data ) ? &ret->left : &ret->right;
        }
*hnd = this;
}

void show(struct tree_node *ptr, int indent)
{
if (!ptr) { printf("Null\n"); return; }

printf("Node(%d):\n", ptr->data);
printf("%*c=", indent, 'L');  show (ptr->left, indent+2);
printf("%*c=", indent, 'R');  show (ptr->right, indent+2);
}

int main(void)
{
struct tree_node *root, *this, *new=NULL;

for (root = &nodes[0]; this = harvest (&root);  ) {
        insert (&new, this);
        }

show (new, 0);
return 0;
}
struct Node
{
    int value;
    Node* left;
    Node* right;
};

void swap(int& l, int& r)
{
    int t = l;
    l = r;
    r = t;
}

void ConvertToBST(Node* n, Node** max)
{
    if (!n) return;

    // leaf node
    if (!n->left && !n->right)
    {
        *max = n;
        return;
    }

    Node *lmax = NULL, *rmax = NULL;
    ConvertToBST(n->left, &lmax);
    ConvertToBST(n->right, &rmax);

    bool swapped = false;
    if (lmax && n->value < lmax->value)
    {
        swap(n->value, lmax->value);
        swapped = true;
    }

    if (rmax && n->value > rmax->value)
    {
        swap(n->value, n->right->value);
        swapped = true;
    }

    *max = n;
    if (rmax && rmax->value > n->value) *max = rmax;

    // If either the left subtree or the right subtree has changed, convert the tree to BST again
    if (swapped) ConvertToBST(n, max);
}

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

Куча сортирует дерево .. nlogn Colotoity ..

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top