Wie ein binären Baum auf binären Suchbaum an Ort und Stelle zu konvertieren, das heißt, wir können keinen zusätzlichen Raum nutzen

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

Frage

Wie man einen binären Baum auf binären Suchbaum an Ort und Stelle konvertieren, das heißt, wir können keinen zusätzlichen Platz nutzen.

War es hilfreich?

Lösung

Sie geben nicht viel weiter zu gehen, aber wenn die Anforderung ist, was ich denke, es ist, Sie haben ein binärer Baum bereits erstellt und im Speicher sitzt, aber nicht sortiert (so, wie Sie es möchten sortiert werden, auf jeden Fall ).

Ich gehe davon aus, dass der Baumknoten aussieht

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

Ich gehe davon aus, dass Sie C lesen

Während wir einfach herumsitzen fragen, warum dieser Baum jemals ohne in sortierter Reihenfolge erstellt wurde geschaffen zu haben, die uns nicht gut tun, so dass ich es ignorieren würde und befassen sich nur mit ihm zu sortieren.

Die Anforderung, dass kein zusätzlicher Raum ungerade verwendet werden. Vorübergehend wird es besonders viel Platz sein, wenn auch nur auf den Stapel. Ich gehe davon aus, dass es bedeutet, dass wie das malloc oder etwas fordern und auch, dass der resultierende Baum nicht mehr Speicher als der original unsortiert Baum zu verwenden hat.

Die erste und einfachste Lösung ist ein Vorordnungsdurchquerung des unsortierten Baumes zu tun, jeden Knoten aus dem Baum zu entfernen und ein sortierte Einsetzen in einen neuen Baum zu tun. Dies ist O (n + n log (n)), die O (n log (n)).

Wenn dies nicht das, was sie wollen, und Sie gehen zu verwenden Drehungen und Sachen haben ..... das ist schrecklich!

Ich dachte, dass Sie dies tun könnte durch eine ungerade Version eines Haufens Art zu tun, aber ich lief in Probleme. Eine andere Sache, die den Sinn kam, die schrecklich langsam sein würde, wäre eine seltsame Version von Bubble Sort auf dem Baum zu tun.

Für das jeder Knoten verglichen wird und möglicherweise mit jedem, es ist direkt Kinder (und damit auch mit der Mutter) getauscht wiederholt, bis Sie den Baum durchlaufen und finden Sie nicht benötigten Swaps. einen Shaker sort (Blase Art, die nach rechts und von rechts nach links links geht) tun würde beste Version dieser Arbeit, und nach dem Anstich würden Sie nicht zu durchqueren hinunter Teilbäume müssen, die nicht mit Bezug auf, um es übergeordneten Blick haben .

Ich bin sicher, dass entweder diese algorthm wurde sonst vor mir von jemandem erdacht und hat einen coolen Namen, dass ich einfach nicht wissen, oder dass es grundsätzlich in irgendeiner Weise fehlerhaft ist, dass ich sehe nicht.

Kommen Sie mit den Laufzeitberechnungen für den zweiten Vorschlag up ist ziemlich kompliziert. Zuerst dachte ich, dass es einfach O (n ^ 2) sein, wie Blase und Shaker Sorten, aber ich kann mich nicht überzeugen, dass die Unterstruktur Traversal Vermeidung nicht genug gewinnen könnte, um es ein wenig besser als O (n ^ 2). Im Wesentlichen erhalten Sorten Blase und Shaker diese Optimierung auch, aber nur an den Enden, wo insgesamt sortedness früh auftritt und Sie können die Grenzen fällen. Mit dieser Baum-Version erhalten Sie oppurtunities möglicherweise Stücke in der Mitte des Satzes zu vermeiden als auch. Nun, wie ich schon sagte, ist es wahrscheinlich tödlich fehlerhaft.

Andere Tipps

konvertieren Binary Tree zu einem doppelt verknüpften Listen- kann getan Inplace in O (n) sein
Dann sortieren indem es Mergesort, nlogn
Konvertieren Sie die Liste zurück an einen Baum - O (n)

Einfache nlogn Lösung.

Haben die Nachordnungsdurchquerung und aus, die einen binären Suchbaum erstellen.

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

Do-Algorithmus nach der Lösung zu erreichen.

1) die um Nachfolger finden, ohne jeden Raum verwendet wird.

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) Do, um Traversal ohne Raum verwendet wird.

a) Bestimmen Sie den ersten Knoten von Inorder Traversal. Es soll die meisten Kind des Baumes links, wenn es hat, oder das ersten rechtes Kind verlassen, wenn es hat, oder rechtes Kind selbst. b) Verwenden obigen Algorithmus, um herauszufinden, inoder Nachfolger des ersten Knotens. c) Wiederholen Sie Schritt 2 für alle zurückgegebenen Nachfolger.

Mit über 2-Algorithmus und tut das, um Traversal auf Binärbaum ohne zusätzlichen Platzbedarf. Bildet den binären Suchbaum, wenn Traversal tun. Aber Komplexität ist O(N2) schlimmster Fall.

Nun, wenn dies eine Interviewfrage ist, das erste, was würde ich herausplatzen (mit Null eigentlichen Gedanken) ist dies: iterate die gesamte binäre rekursiv und und das kleinste Element zu finden. Nehmen Sie es von dem binären Baum aus. Nun wiederholen Sie den Vorgang, bei dem Sie den gesamten Baum durchlaufen und das kleinste Element finden, und es fügen Sie als Eltern des letzten Elements (mit dem vorherigen Element des neuen Knotens linken Kind immer) gefunden. Wiederholen Sie so oft wie nötig, bis der ursprüngliche Baum ist leer. Am Ende werden Sie mit dem schlimmstmöglichen sortierten binären Baum links - eine verbundene Liste. Der Zeiger zeigt auf den Wurzelknoten, der das größte Element ist.

Dies ist ein schrecklicher Algorithmus all-around - O (n ^ 2) Laufzeit mit der schlechtesten möglichen binären Baum ausgegeben, aber es ist ein anständigen Ausgangspunkt, bevor besser mit etwas kommen und hat den Vorteil, Sie schreiben in der Lage, der Code für sie in etwa 20 Zeilen auf einem Whiteboard.

Ein Binärbaum in der Regel ist ein binärer Suchbaum, wobei in diesem Fall keine Konvertierung erforderlich ist.

Vielleicht müssen Sie die Struktur klären, was Sie von konvertieren. Ist Ihr Quellbaum unausgeglichen? Ist es nicht der Schlüssel, den Sie suchen auf möchten bestellt? Wie kommen Sie auf dem Quellbaum?

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

Do Inorder Traversal des binären Baumes und das Ergebnis speichern. sortieren Sie das Ergebnis in acending bestellen bildet den binären Suchbaum durch mittleres Element der sortierten Liste als root unter (dies kann unter Verwendung von binärer Suche durchgeführt). so erhalten wir binären Suchbaum ausgeglichen.

heap Art der Baum .. nlogn Komplexität ..

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top