Está en la página 1de 21

Árboles Binarios

Definición
 Un árbol es una estructura dinámica que permite establecer una relación
jerárquica entre sus elementos.
 La relación está dada por niveles.
 La relación más directa es la de padre – hijo.
Observaciones
 Un padre puede tener múltiples hijos.
 Un hijo a su vez, puede ser padre de más hijos.
 Al único nodo que no tiene padre se le llama raíz.
 Si un hijo no tiene descendencia, se le llama nodo hoja.
Representación Gráfica

Árboles Binarios
 Un árbol binario es una estructura de árbol limitada, de manera que tan solo
pueda tener cada padre de cero a dos hijos.
Definición de Clase
 Un árbol binario requiere una estructura de Nodo que permita almacenar el
dato correspondiente, además de una liga al Hijo izquierdo y una más al
Hijo Derecho.
 El árbol será una liga al Nodo Raíz, a partir del cual se podrá acceder al
resto de la estructura.
Definición de Clase NodoDeArbol
public class NodoDeArbol{
int dato; //Para hacer transparentes los métodos
NodoDeArbol izq;
NodoDeArbol der;
}
Observación – La estructura es equivalente a la de un Nodo de listas doblemente
ligadas, pero los métodos son diferentes.
Definición de Clase Árbol
public class Arbol{
NodoDeArbol raiz;
public Arbol(){
raiz = null;
}
public Arbol(String d){
raiz = new NodoDeArbol(d);
}
public Arbol(NodoDeArbol n){
raiz = n;
}
}
Métodos
 Los métodos principales son:
 Recorridos
 Inserción
 Eliminación
 Métodos secundarios:
 HijoDe
 PadreDe
 Vacío
Recorridos en Árboles
 Evidentemente, recorrer un árbol no es un método lineal, por lo que
frecuentemente se utiliza recursión.
 Existen al menos dos formas de recorrer un árbol:
 A lo ancho
 A lo profundo
Recorrido a lo Ancho

 Para recorrer un árbol a lo ancho, se debe agregar a una cola cada uno de
los hijos del nodo raíz, luego, llamar recursivamente al procedimiento sobre
la cola, hasta que ésta se encuentre vacía.
Recorrido a lo Ancho
Recorrido a lo Profundo
 Para recorrer un árbol a lo profundo, se debe ejecutar simplemente el
recorrido sobre cada uno de los nodos hijos del nodo actual.
Ejercicio: Sea el siguiente árbol, ejecute el recorrido a lo profundo y obtenga la
secuencia numérica correspondiente.
Inserción en Árboles

 Para insertar un dato en un árbol, se debe decidir en qué punto se


insertará.
 Normalmente los árboles binarios mantienen un orden en los datos que
contienen.
 Los datos menores al dato raíz se almacenan a su izquierda, los datos
mayores a su derecha.
 Insertemos datos… Partiendo de un árbol vacío, agreguemos la siguiente
lista numérica:
5,8,1,6,2,3
 El primer paso sería crear el nodo raíz, que contiene el primer valor de la
lista: 5
 Se almacena el siguiente dato: 8, como es mayor que el nodo raíz, se
almacena a su derecha.
 Se inserta también el siguiente dato: 1, que por ser menor que 5, se
almacena a su izquierda.

 Ahora, se trata de insertar el siguiente dato: 6, que por ser mayor que 5 se
debería insertar a su derecha.
 Como ya existe un nodo hijo derecho de 5, se llama nuevamente al
procedimiento de inserción en ése nodo.
 De esta manera, insertaremos el dato 6 como si el nodo 8 fuera la raíz del
árbol.
 Como 6 es menor que 8, se inserta a su izquierda.

 Se inserta a continuación el dato 2.


 Como el nodo 5 ya tiene a su izquierda un hijo, se llama nuevamente al
procedimiento para que tome a éste hijo como la raíz del árbol e inserte en
él el dato.
 Como 2 es mayor que 1, se inserta a su derecha.

 Por último, agregaremos el dato 3.


 Como 5 tiene su nodo izquierdo hijo ocupado (3<5), insertaremos en el
nodo 1.
 Como 1 tiene su nodo derecho ocupado (1<3), insertaremos en el nodo 2.
 Como 2 es menor que 3, insertaremos el 3 a su derecha.
 Finalmente, el árbol queda:
public void inserta(NodoDeArbol actual,int dato){
if (dato<actual.dato)
if (actual.izq==null)
actual.izq = new NodoDeArbol(dato);
else
inserta(actual.izq,dato);
if (dato>actual.dato)
if (actual.der==null)
actual.der = new NodoDeArbol(dato);
else
inserta(actual.der,dato);
}
Eliminación
 La eliminación tampoco es un caso trivial. Eliminar un nodo significa tener
que reacomodar a sus hijos huérfanos, a fin de que algún padre los
“adopte”, de lo contrario, se perderían todos los datos que penden de ellos.
 Supongamos que del árbol resultante, quisiéramos eliminar el nodo 1.
 De hacerlo directamente, perderíamos el nodo 2 y el nodo 3.
 Existen posibles soluciones para no perder a éstos nodos.
 Cada solución consiste en convertir a uno de éstos nodos en hijo directo del
padre del nodo a eliminar y luego convertir a éste nodo en padre de su
hermano
Eliminación… Paso a paso
 Tomemos el ejemplo anterior…
 Como 1 sólo tiene un hijo (2), podemos hacer a 2 el hijo de 5 para mantener
la estructura del árbol.

 Es obvio que si queremos eliminar un nodo que no tiene hijos, simplemente


no nos da problemas, ¿pero qué pasa si queremos eliminar un nodo con 2
hijos?.
 Supongamos que en el árbol del resultado anterior se insertara nuevamente
el 1… entonces tendríamos:
 Ahora, si de ésta estructura quisiéramos eliminar el nodo 2… tenemos
problemas!
 Una solución consiste en hacer primero a 1 padre de 3 y luego hacer a 1
hijo de 5.

 ¿Por qué hicimos 3 hijo de 1 y no al revés? Pues porque es


equivalente…Mientras mantengamos los datos ordenados, puede hacerse
como resulte más fácil.
 ¿Qué hubiera pasado si 1 tuviera ya dos hijos? Simplemente avanzamos
hasta encontrar una hoja del lado derecho donde poder insertar a 3.
EJERCICIO DE ARBOLES BINARIOS EN C#

CODIGO GENERADO

public class NodoA


{
public NodoA padre, izq, der;
public int dato;
public NodoA()
{
dato = 0;
padre = null;
izq = null;
der = null;
}
public NodoA(int d)
{
dato = d;
padre = null;
izq = null;
der = null;
}
}
public class NodoP
{
public int valor;
public NodoP siguiente;
public NodoP(int m)
{
valor = m;
siguiente = null;
}
}

public class Pila


{
public NodoP tope;
public void Insertar(int x)
{
NodoP nuevo = new NodoP(x);
nuevo.siguiente = tope;
tope = nuevo;
}
public int Eliminar()
{
int x = tope.valor;
tope = tope.siguiente;
return x;
}
public bool PilaVacia()
{
if (tope == null)
return true;
else
return false;
}
}

public class Arboles


{
public NodoA raiz;

public Arboles()
{
raiz=null;
}

public Arboles(int dato)


{
NodoA nuevo = new NodoA(dato);
raiz = nuevo;
}

public void Insertar(int dato)


{
raiz = Insertar(dato, raiz);
}
private NodoA Insertar(int dato, NodoA rz)
{
if (rz == null)
{
NodoA nuevo = new NodoA(dato);
rz = nuevo;
}
else
{
NodoA actual = rz;
if (actual.dato > dato)
{
actual.izq = Insertar(dato, actual.izq);
actual.izq.padre = actual;
}
if (actual.dato < dato)
{
actual.der = Insertar(dato, actual.der);
actual.der.padre = actual;
}
if (actual.dato == dato)
MessageBox.Show("No Se pueden insertar datos
duplicados!");
}
return rz;
}

public NodoA Busca(int dato)


{
NodoA aux = Busca(dato, raiz);
return aux;
}
public NodoA Busca(int dato, NodoA rz)
{
NodoA aux = null;
if (rz != null)
{
if (rz.dato > dato)
{
aux = Busca(dato, rz.izq);
}
else
if (rz.dato < dato)
{
aux = Busca(dato, rz.der);
}
else
if (rz.dato == dato)
{
aux = rz;
}
}
else
{
aux = null;
}
return aux;
}
public Pila alapila(NodoA nodo, Pila lapila)
{
if (nodo != null)
lapila.Insertar(nodo.dato);
if (nodo.izq != null)
alapila(nodo.izq, lapila);
if (nodo.der != null)
alapila(nodo.der, lapila);
return lapila;
}

public void Borrar(int dato)


{
NodoA nodo=Busca(dato);
if (nodo==raiz)
{
if ((nodo.izq==null)&&(nodo.der==null))
raiz=null;
else
if ((nodo.izq!=null)&&(nodo.der==null))
raiz=nodo.izq;
else
if ((nodo.izq==null)&&(nodo.der!=null))
raiz=nodo.der;
else
if ((nodo.izq!=null)&&(nodo.der!=null))
{
Pila mipila=new Pila();
mipila=alapila(nodo,mipila);
raiz=null;
while (!mipila.PilaVacia())
{
int n;
if ((n=mipila.Eliminar())!=dato)
Insertar(n);
}
}
}
else
if (nodo!=raiz)
{
if ((nodo.izq==null)&&(nodo.der==null))
{
if (nodo.padre.izq==nodo)
nodo.padre.izq=null;
else
nodo.padre.der=null;
nodo.padre=null;
}
else
{
if ((nodo.izq!=null)&&(nodo.der==null))
{
nodo.izq.padre=nodo.padre;
if (nodo.padre.izq==nodo)
nodo.padre.izq=nodo.izq;
else
nodo.padre.der=nodo.izq;
}
else
if ((nodo.izq==null)&&(nodo.der!=null))
{
nodo.der.padre=nodo.padre;
if (nodo.padre.izq==nodo)
nodo.padre.izq=nodo.der;
else
nodo.padre.der=nodo.der;
}
else
if ((nodo.izq!=null)&&(nodo.der!=null))
{
Pila mipila=new Pila();
mipila=alapila(nodo,mipila);
if (nodo.padre.izq==nodo)
nodo.padre.izq=null;
else
nodo.padre.der=null;
while (!mipila.PilaVacia())
{
int n;
if ((n=mipila.Eliminar())!=dato)
Insertar(n);
}
}
}
}
MessageBox.Show("\nBorrado Exitoso!\n");
}
public void enOrden(NodoA rz)
{
if (rz.izq!=null)
{
enOrden(rz.izq);
}
MessageBox.Show(rz.dato+" ");
if (rz.der!=null)
{
enOrden(rz.der);
}
}

public void posOrden(NodoA rz)


{
if (rz.izq!=null)
{
posOrden(rz.izq);
}
if (rz.der!=null)
{
posOrden(rz.der);
}
MessageBox.Show(rz.dato + " ");
}
public void preOrden(NodoA rz)
{
MessageBox.Show(rz.dato + " ");
if (rz.izq!=null)
{
preOrden(rz.izq);
}
if (rz.der!=null)
{
preOrden(rz.der);
}
}
}

CODIGO DE BOTONES

private void button1_Click(object sender, EventArgs e)


{
rz = Convert.ToInt16(textBox1.Text);
arbol1=new Arboles(rz);
textBox1.Text = "";

private void button2_Click(object sender, EventArgs e)


{
rz1 = Convert.ToInt16(textBox2.Text);
arbol1.Insertar(rz1);
textBox2.Text = "";
}

private void button3_Click(object sender, EventArgs e)


{
arbol1.enOrden(arbol1.raiz);
}

private void button4_Click(object sender, EventArgs e)


{
arbol1.posOrden(arbol1.raiz);
}

private void button5_Click(object sender, EventArgs e)


{
arbol1.preOrden(arbol1.raiz);
}

private void button6_Click(object sender, EventArgs e)


{
rz1 = Convert.ToInt16(textBox2.Text);
arbol1.Borrar(rz1);
textBox2.Text = "";
}

También podría gustarte