Come convertire un albero binario di ricerca binaria albero posto, cioè, che non possiamo utilizzare qualsiasi spazio extra

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

Domanda

Come convertire un albero binario di ricerca binaria albero posto, cioè, che non possiamo utilizzare qualsiasi spazio extra.

È stato utile?

Soluzione

non dare molto per andare avanti, ma se il requisito è quello che penso che sia, si dispone di un albero binario già creato e seduta in memoria, ma non ordinate (il modo in cui si desidera essere ordinato, in ogni caso ).

Sto assumendo che i nodi della struttura sembrano

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

Sono anche supponendo che si può leggere C

Mentre potremmo semplicemente sedersi intorno chiedendosi perché questo albero è stato mai creato senza essere stato creato in modo ordinato che non ci serve a niente, quindi mi ignorarlo e basta trattare con l'ordinamento esso.

Il requisito che nessuno spazio in più da utilizzare è dispari. Temporaneamente non ci sarà spazio extra, anche se solo in pila. Ho intenzione di assumere che significa che chiamando malloc o qualcosa del genere e, inoltre, che l'albero risultante è di utilizzare non più memoria rispetto l'albero non ordinato originale.

Il primo e più semplice soluzione è quella di fare un preordine attraversamento della struttura non ordinata la rimozione di ogni nodo da quell'albero e facendo un inserimento ordinato in un nuovo albero. Questo è O (n + n log (n)), che è O (n log (n)).

Se questo non è ciò che vogliono e si sta andando ad avere per uso rotazioni e roba ..... che è orribile!

Ho pensato che si potrebbe fare questo facendo una versione dispari di un mucchio sorta, ma mi sono imbattuto in problemi. Un'altra cosa che è venuto in mente, che sarebbe terribilmente lento, potrebbe fare una versione dispari di bubble sort sull'albero.

Per questo ogni nodo viene confrontata e possibilmente scambiato con ciascuno dei figli è diretto (e quindi anche con il suo genitore) fino a quando si attraversa l'albero e non si trova alcuna swaps necessario. Facendo uno shaker sort (bubble sort che va da sinistra a destra e la destra a sinistra) versione di questo dovrebbe funzionare meglio, e dopo il passo iniziale, non avrebbe bisogno di attraversare le sottostrutture che non sembravano fuori ordine rispetto ad esso con i genitori .

sono sicuro che sia questo algorthm è stato pensato da qualcun altro prima di me e ha un nome fresco che io proprio non lo so, o che è fondamentalmente errata, in qualche modo che non sto vedendo.

Venendo con i calcoli di runtime per il secondo suggerimento è un piuttosto complicato. In un primo momento ho pensato che sarebbe semplicemente O (n ^ 2), come bolla e shaker sorta, ma non può soddisfare me stesso che la sottostruttura attraversamento evitamento non potrebbe vincere abbastanza per renderlo un po 'meglio di O (n ^ 2). Essenzialmente bolla e shaker sorta ottenere questa ottimizzazione troppo, ma solo alle estremità dove sortedness totale si verifica precocemente e si può abbattere i limiti. Con questa versione albero si ottiene molta opportunità di evitare possibilmente pezzi nel mezzo del set pure. Beh, come ho detto, probabilmente è fatalmente incrinata.

Altri suggerimenti

Convertire albero binario a una lista- doppiamente legato può essere inplace fatto in O (n)
Poi sorta utilizzando merge sort, nlogn
Convertire la lista di nuovo ad un albero - O (n)

soluzione nlogn semplice.

Fare la postorder Traversal e da quella di creare un albero binario di ricerca.

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

Fare il seguente algoritmo per arrivare alla soluzione.

1) trovare l'ordine successore senza l'utilizzo di qualsiasi spazio.

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) Fare in modo trasversale senza l'utilizzo di spazio.

a) Trovare il primo nodo di inorder di attraversamento.Dovrebbe a sinistra la maggior parte dei bambini dell'albero se ha, o a sinistra del primo diritto di un bambino se si ha, di destra o di bambino.b) l'Uso al di sopra algoritmo per la ricerca di fuori inoder successore del primo nodo.c) Ripetere il passaggio 2 per tutte le restituiti successore.

Utilizzare al di sopra del 2 algoritmo e fare in modo trasversale su albero binario senza l'utilizzo di spazio extra.Modulo di ricerca binaria albero quando si fa la traversata.Ma la complessità è O(N2) il caso peggiore.

Bene, se questa è una domanda intervista, la prima cosa che vorrei spifferare (da zero pensiero reale) è questo: iterate l'intero binario in modo ricorsivo e e trovare l'elemento più piccolo. Tirarla fuori della albero binario. Ora, ripetere il processo in cui si itera l'intero albero e trovare il più piccolo elemento e aggiungerlo come un genitore dell'ultimo elemento trovato (con l'elemento precedente diventare figlio sinistro del nuovo nodo). Ripetere tante volte quanto necessario fino a quando l'albero originale è vuota. Alla fine, si sono lasciati con la peggiore possibile albero binario ordinata - una lista collegata. Il puntatore punta al nodo radice, che è l'elemento più grande.

Questo è un algoritmo orribile all-around - O (n ^ 2) tempo di esecuzione con la peggiore possibile uscita albero binario, ma è un punto di partenza decente prima di venire con qualcosa di meglio e ha il vantaggio di voi di essere in grado di scrivere il codice per esso in circa 20 linee su una lavagna.

Un albero binario di solito è un albero binario di ricerca, nel qual caso non è necessaria alcuna conversione.

Forse avete bisogno di chiarire la struttura di quello che si esegue la conversione. È il vostro albero dei sorgenti non bilanciata? Non è forse ordinato dal tasto che si desidera cercare? Come sei arrivato a l'albero dei sorgenti?

#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 ordine simmetrico dell'albero binario e memorizzare il risultato. ordinare il risultato in ordine acending formare l'albero binario di ricerca prendendo elemento centrale della lista ordinata come root (questo può fare usando la ricerca binaria). Così otteniamo equilibrati albero binario di ricerca.

mucchio sorta l'albero .. complessità nlogn ..

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top