14/7/11

Arboles..

Para realizar la operación de borrado , se tienen que tener en consideracion varios cosas:



Borrar un nodo sin hijos ó nodo hoja: Simplemente se borra y se establece a nulo el apuntador

de su padre.

Borrar un nodo con un subárbol hijo: se borra el nodo y se asigna su subárbol hijo como subárbol de su padre.

Borrar un nodo con dos subárboles hijo: la solución está en reemplazar el valor del nodo por el

de su predecesor o por el de su sucesor en inorden y posteriormente borrar este nodo. Su predecesor en
inorden será el nodo más a la derecha de su subárbol izquierdo (mayor nodo del subarbol izquierdo), y su sucesor el nodo más a la izquierda de
su subárbol derecho (menor nodo del subarbol derecho).Aunque en realidad aún no he podido implementarlo =(.. pues el codigo no hace lo que debería.

Toda esta información la encontré en wikipedia. http://es.wikipedia.org/wiki/%C3%81rbol_binario_de_b%C3%BAsqueda


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "bool.h"

#define DEBUG 1

// NOTA: faltan implementar las rotaciones
// dobles; por ahora no balancea bien

// un nodo de ruteo no cuenta duplicados
#define NO_VALIDO -1


  int next = 0;


struct nodo_de_arbol {
  char dato;
  int altura;
  int contador;

  int id;

  struct nodo_de_arbol* padre;
  struct nodo_de_arbol* izq; // hijo
  struct nodo_de_arbol* der; // otro hijo
};
typedef struct nodo_de_arbol nodo;

void borra(nodo* n) {
  if (n == NULL) {
    return;
  } else {
    borra(n->izq);
    borra(n->der);
    free(n);
  }
  return;
}

void muestra(nodo* n) {
  if (n == NULL) {
    return; // caso base de recursion
  } else {
    muestra(n->izq);

    if (n->izq != NULL && n->der != NULL) {
      printf("[%c, %d <%d / %d, %d>] ", 
         n->dato, n->altura, n->id,
         n->izq->id, n->der->id);
    } else {
      printf("(%c, %d <%d> #%d) ", 
         n->dato, n->altura, n->id,
         n->contador);
    }

    if (n->izq == NULL && n->der == NULL) {
      printf("%c[%d] ", n->dato, n->contador);
    }

    muestra(n->der);
  }
  return;
}
void elimina(nodo* n,nodo** raiz){
nodo-> NULL; 
}
void balancea(nodo* n, nodo** raiz) {
  int ai, ad, max, min, aalt, balt;
  nodo* t = NULL;
  nodo* u = NULL;
  nodo* v = NULL;
  nodo* a = NULL;
  nodo* b = NULL;
  nodo* p = NULL;
  nodo* x1 = NULL;
  nodo* x2 = NULL;

  if (n == NULL) {

    printf("Ya topamos con la raiz.\n");

    return;
  }
  if (n->izq == NULL ||
      n->der == NULL) {

    printf("No se puede sin hijos.\n");

    return;
  }
  
  t = n; // nodo actual
  assert(t != NULL);
  

  printf("Checando balance en %c (alt. %d).\n",
     t->dato, t->altura);


  u = n->izq; // hijo izquierdo
  assert(u != NULL);
  v = n->der; // hijo derecho
  assert(v != NULL);

  ai = u->altura;
  ad = v->altura;


  printf("Hijos %c (alt. %d) y %c (alt. %d).\n",
     u->dato, ai, v->dato, ad);


  max = (ai > ad) ? ai : ad;
  min = (ai > ad) ? ad : ai;

  if (max + 1 != t->altura) {
    t->altura = max + 1; // actualizar altura
  }

  if (max - min > 1) { // balancear
    p = t->padre; // padre del actual


    printf("%c a altura %d requiere balanceo.\n", 
       t->dato, t->altura);
    printf("Entrando tenemos:\n");
    if (p != NULL) {
      printf("p = %d, ", p->id);
    } else {
      printf("p = NULL, ");
    }
    printf("t = %d, \n", t->id);
    printf("u = %d, v = %d, \n", 
       u->id, v->id);

    
    if (ai <= ad - 2) { 
      // si hay demasiada altura a la der
      // => voltear "peso" hacia la izq.
      a = v->izq;
      b = v->der;
      assert(a != NULL);
      assert(b != NULL);
      aalt = a->altura;
      balt = b->altura;
      

      printf("a = %d, b = %d, \n", 
         a->id, b->id);


      if (aalt <= balt) { // rotacion simple izq
    printf("Simple izquierda.\n");
    if (p != NULL) {
      // v debe reemplazar a t como hijo
      if (p->izq == t) {
        p->izq = v;
      } else { // era derecho 
        p->der = v;
      }
    } else {
      // v es ahora raiz
      *raiz = v;
    }
    // el padre de t sera padre de v
    v->padre = p;
    // printf("Arreglado hacia arriba.\n");
    
    // v ahora es hijo izq de t
    // t es padre de v
    v->izq = t;
    t->padre = v;
    // el hijo der de t no cambia
    // printf("Arreglado entre t y v.\n");
    
    // a va a ser hijo derecho de t
    // t va a ser padre de a
    t->der = a;
    a->padre = t;
    // printf("Arreglado entre a y t.\n");


    if (p != NULL) {
      printf("v = %d es hijo de p = %d,\n",
         v->id, p->id);
    }
    printf("t = %d = %d es hijo de v = %d,\n",
           t->id, v->izq->id, v->id);
    printf("a = %d = %d es hijo de t = %d\n",
           a->id, t->der->id, t->id);
    printf("b = %d = %d es hijo de v = %d,\n",
           b->id, v->der->id, v->id);
    printf("u = %d = %d es hijo de t = %d.\n",
           u->id, t->izq->id, t->id);

    // para ni u ni b nada cambia
      } else { 
    printf("Simple derecha-izquierda.\n");
    x1 = a->izq;
    assert(x1 != NULL);
    x2 = a->der;
    assert(x2 != NULL);
    
    if (p != NULL) {
      if (p->izq == t) {
        p->izq = a; // w
      } else { // era der.
        p->der = a;
      }
    } else { // t era raiz
      *raiz = a; // avisar main
    }
    v->padre = a;
    a->der = v;
    t->padre = a;
    a->izq = t;
    v->izq = x2;
    x2->padre = v;
    t->der = x1;
    x1->padre = t;
      }
    } else if (ai >= ad + 2) {
      // voltear hacia la derecha
      a = u->izq;
      b = u->der;
      assert(a != NULL);
      assert(b != NULL);
      aalt = a->altura;
      balt = b->altura;
      if (aalt >= balt) { 
    printf("Simple derecha.\n");
    if (p != NULL) {
      if (p->izq == t) {
        p->izq = u;
      } else { // era derecho 
        p->der = u;
      }
    } else {
      // cambiando la raiz para ser u
      *raiz = u;
    }
    u->padre = p;
    // printf("Arreglado hacia arriba.\n");
    u->der = t;
    t->padre = u;
    // printf("Arreglado entre t y u.\n");
    t->izq = b;
    b->padre = t;
    // printf("Arreglado entre b y t.\n");
      } else { // (aalt < balt)
    printf("Doble izquierda derecha.\n");
    x1 = b->izq;
    assert(x1 != NULL);
    x2 = b->der;
    assert(x2 != NULL);
    
    if (p != NULL) {
      if (p->izq == t) {
        p->izq = b; // w
      } else { // era der.
        p->der = b;
      }
    } else { // t era raiz
      *raiz = b; // avisar main
    }
    u->padre = b;
    b->izq = u;
    t->padre = b;
    b->der = t;
    u->der = x1;
    x1->padre = u;
    t->izq = x2;
    x2->padre = t;
      }
    }
    if (p != NULL) {
      balancea(p, raiz);
    }
  } else {

    printf("%c esta bien (%d vs. %d).\n", 
       n->dato, ai, ad);

    // siempre checa hasta la raiz
    balancea(n->padre, raiz);
  }
  return;
}

bool agrega(char dato, nodo* arbol, nodo** n) {
  nodo* nuevo;
  nodo* reemplazo;
  char ruteo;
  if (arbol == NULL) {
    // caso especial de no tener nada aun
    nuevo = (nodo*)malloc(sizeof(nodo));
    nuevo->contador = 1;

    nuevo->id = next++;

    nuevo->altura = 1; // como hoja
    nuevo->dato = dato;
    nuevo->padre = NULL;
    nuevo->izq = NULL;
    nuevo->der = NULL;
    *n = nuevo; // nueva raiz
    return TRUE;
  } else {
    if (arbol->izq == NULL &&
    arbol->der == NULL) { // si es hoja

      if (arbol->dato == dato) {
    // iguales; agregar duplicidad
    arbol->contador++;
    return FALSE;
      }
      

      printf("Agregando %c en %c.\n",
         dato, arbol->dato);

      
      ruteo = (arbol->dato < dato ? 
           arbol->dato : dato);
      
      nuevo = (nodo*)malloc(sizeof(nodo));
      nuevo->contador = 1;

      nuevo->id = next++;

      nuevo->altura = 1; // como hoja
      nuevo->dato = dato;
      nuevo->padre = arbol;
      nuevo->izq = NULL;
      nuevo->der = NULL;

      reemplazo = (nodo*)malloc(sizeof(nodo));
      reemplazo->contador = arbol->contador;
      arbol->contador = NO_VALIDO;

      reemplazo->id = next++;

      reemplazo->altura = 1; // como hoja
      reemplazo->dato = arbol->dato;
      reemplazo->padre = arbol;
      reemplazo->izq = NULL;
      reemplazo->der = NULL;

      if (dato < arbol->dato) {
    arbol->izq = nuevo;
    arbol->der = reemplazo;
      } else if (dato > arbol->dato) {
    arbol->der = nuevo;
    arbol->izq = reemplazo;
      }

      arbol->dato = ruteo;
      arbol->altura = 2;
      balancea(arbol->padre, n);
    } else {
      if (dato <= arbol->dato) {
    agrega(dato, arbol->izq, n);
      } else { // mayor
    agrega(dato, arbol->der, n);
      }
    }
  }
  return TRUE;
}

int main(int argc, char** args) {
  nodo* raiz = NULL;
  char dato;
  int contador = 0;

  do {
    dato = getchar(); // lee un caracter
    if (!isspace(dato)) {
      if (agrega(dato, raiz, &raiz)) {
    contador++;
      }
      if (raiz != NULL) {
    printf("\nCon %d nodos, altura %d: \n",
           contador, raiz->altura);
    muestra(raiz);
    printf("\n");
      } else {
    printf("No hay nada.\n");
      }
    }
  } while (dato != '!'); // parar despues de !
  borra(raiz);

  return 1;
}

1 comentario:

Elisa dijo...

O sea, echaste mucho rollo sobre cómo eliminar y luego a fin de cuentas nada más le pusiste null :D
LOL, +2.