Professional Documents
Culture Documents
1 Definicin
^
Un rbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios
nodos.
Tambin se suele dar una definicin recursiva: un rbol es una estructura en
compuesta por un dato y varios rboles.
Esto son definiciones simples. Pero las caractersticas que implican no lo son tanto.
rbol
Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos
del rbol. En el ejemplo, 'L' y 'M' son hijos de 'G'.
Nodo padre: nodo que contiene un puntero al nodo actual. En el
ejemplo, el nodo 'A' es padre de 'B', 'C' y 'D'.
Los rboles con los que trabajaremos tienen otra caracterstica importante: cada nodo
slo puede ser apuntado por otro nodo, es decir, cada nodo slo tendr un padre. Esto
hace que estos rboles estn fuertemente jerarquizados, y es lo que en realidad les da la
apariencia de rboles.
En cuanto a la posicin dentro del rbol:
Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos
para referirnos al rbol. En el ejemplo, ese nodo es el 'A'.
Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H',
'I', 'K', 'L', 'M', 'N' y 'O'.
Nodo rama: aunque esta definicin apenas la usaremos, estos son los
nodos que no pertenecen a ninguna de las dos categoras anteriores. En
el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'.
Otra caracterstica que normalmente tendrn nuestros rboles es que todos los nodos
contengan el mismo nmero de punteros, es decir, usaremos la misma estructura para
todos los nodos del rbol. Esto hace que la estructura sea ms sencilla, y por lo tanto
tambin los programas para trabajar con ellos.
Tampoco es necesario que todos los nodos hijos de un nodo concreto existan. Es decir,
que pueden usarse todos, algunos o ninguno de los punteros de cada nodo.
Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se
llama rbol completo.
En una cosa, los rboles se parecen al resto de las estructuras que hemos visto: dado un
nodo cualquiera de la estructura, podemos considerarlo como una estructura
independiente. Es decir, un nodo cualquiera puede ser considerado como la raz de un
rbol completo.
Existen otros conceptos que definen las caractersticas del rbol, en relacin a su
tamao:
O generalizando ms:
#define ORDEN 5
struct nodo {
int dato;
struct nodo *rama[ORDEN];
};
Al igual que hicimos con las listas que hemos visto hasta ahora, declaramos un
tipo tipoNodo para declarar nodos, y un tipopNodo para es el tipo para declarar
punteros a un nodo.
Arbol es el tipo para declarar rboles de orden ORDEN.
rbol
algo lineal, como una lista, en el que cada captulo sigue al anterior, tambin es posible
acceder a cualquier punto de l a travs de la tabla de contenido.
Tambin se suelen organizar en forma de rbol los organigramas de mando en
empresas o en el ejrcito, y los rboles genealgicos.
rboles
Antes de comenzar a trabajar sobre rboles es importante estudiar recursividad
Contenidos
1.
1 Introduccin
2.
2 Visin Recursiva
3.
4.
4 Recorridos
1.
2.
5.
5 Cdigo fuente
Introduccin
Algunas definiciones:
Un rbol es una estructura de datos enlazada que organiza elementos en forma jer
decir, hay una relacin padre/hijos.
Un rbol es de orden N (o N-ario) cuando la mxima cantidad de hijos que puede tener
Visin Recursiva
Cada rama de un rbol puede ser visto como un sub-rbol. De esta forma, el rbol genealgico
Bouvier est compuesto por el rbol de Marge, el de Patty y el de Selma. Esto repercute en el e
programacin: todas las funciones que recorren o modifican el rbol hacen uso de caracterstic
Esto significa que a veces el trmino nodo y rbol se usan indistintamente, lo cual puede caus
desprevenido.
Haciendo uso de la nocin recursiva de un rbol, podemos definir un rbol como la unin de un
ramas.
class Arbol:
def __init__(self, elemento):
self.hijos = []
self.elemento = elemento
agregar elementos
Una forma de agregar elementos podra ser:
abuela = "Jacqueline Gurney"
marge = "Marge Bouvier"
patty = "Patty Bouvier"
selma = "Selma Bouvier"
bart = "Bart Simpson"
lisa = "Lisa Simpson"
maggie = "Maggie Simpson"
ling = "Ling Bouvier"
arbol = Arbol(abuela)
agregarElemento(arbol, patty, abuela)
agregarElemento(arbol, selma, abuela)
agregarElemento(arbol, ling, selma)
agregarElemento(arbol, marge, abuela)
agregarElemento(arbol, bart, marge)
agregarElemento(arbol, lisa, marge)
Para lo cual necesitamos escribir el mtodo agregarElemento que recibe el rbol, el elemento
padre de dicho elemento. Este mtodo obtiene el sub-rbol que contiene al elemento padre y
nueva rama (rbol) con el nuevo elemento.
Es importante entender que la bsqueda del sub-rbol debe ser recursiva. La condicin de cor
elemento est en el rbol actual, si no se busca en cada uno de los hijos.
Profundidad y grado
El grado es el maximo entre la cantidad de sus hijos directos y el grado de sus hijos
def profundidad(arbol):
if len(arbol.hijos) == 0:
return 1
return 1 + max(map(profundidad,arbol.hijos))
def grado(arbol):
return max(map(grado, arbol.hijos) + [len(arbol.hijos)])
Recorridos
Recorrer un rbol significa comenzar a visitar a cada uno de los elementos (tanto al elemento de la raiz como a los
descendientes). A veces se realiza porque se quiere ejecutar algo por cada uno u otras veces es porque se est busca
particular.
Existen dos maneras de recorrer un rbol: profundidad primero y ancho primero.
Profundidad Primero
Esta forma es la ms sencilla: consiste en explorar toda una rama antes de pasar a la siguiente. Es decir, hasta no
toda la rama de marge, no iniciar con Patty.
Ac un diagrama que muestra el rden de recorrido sobre un rbol:
En el mtodo que vimos anteriormente de buscarSubArbol estamos usando esta estrategia para encontrar el element
ejemplo de una funcin de orden superior que ejecuta sobre cada elemento del rbol:
def printElement(element):
print element
ejecutarProfundidadPrimero(arbol, printElement)
Patty Bouvier
Selma Bouvier
Ling Bouvier
Marge Bouvier
Bart Simpson
Lisa Simpson
Maggie Simpson
Ancho Primero
Esta forma es un poco ms compleja pero puede ser conveniente dependiendo del problema. En nuestro ejemplo ir r
generacin a generacin: Primero la abuela, luego todas las hijas, y luego todos los nietos.
Ac otro diagrama a modo esquemtico:
Para poder resolver este algoritmo, es necesario retrasar la ejecucin de la funcin sobre los hijos hasta que no se ha
ejecutar todos los hermanos/primos. Por eso se usa una cola (Primero que entra, Primero que sale) para lograr esto.
un nodo, ejecuta la funcin, agrega sus hijos a la cola, y luego llama a la funcin recursiva pero en lugar de hacerlo so
(como haca profundidad primero) lo hace sobre el prximo de la cola, que seguramente es un alguien de su nivel si a
primero del prximo nivel.
Invocacin:1
Elemento: Jackeline
Consola
Jacqueline
Gurney
Cola
Patty Bouvier
Selma Bouvier
Marge Bouvier
Invocacin:2
Elemento: Patty
No tiene hijos, por lo tanto no agrega elementos a la cola
Consola
Jacqueline
Gurney
Patty Bouvier
Cola
Selma Bouvier
Marge Bouvier
Invocacin:3
Elemento: Selma
Agrega a Ling a la cola
Consola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Invocacin:4
Cola
Marge Bouvier
Ling Bouvier
Elemento: Marge
Agrega a Bart, Lisa y Maggie
Consola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Marge Bouvier
Cola
Ling Bouvier
Bart Simpson
Lisa Simpson
Maggie Simpson
Invocacin:5
Elemento: Ling
Consola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Marge Bouvier
Ling Bouvier
Cola
Bart Simpson
Lisa Simpson
Maggie Simpson
Invocacin:6
Elemento: Bart
Consola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Marge Bouvier
Ling Bouvier
Bart Simpson
Cola
Lisa Simpson
Maggie Simpson
Invocacin:7
Elemento: Lisa
Consola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Marge Bouvier
Ling Bouvier
Bart Simpson
Lisa Simpson
Cola
Maggie Simpson
Invocacin:8
Elemento: Maggie
Consola
Cola
Jacqueline
Gurney
Patty Bouvier
Selma Bouvier
Marge Bouvier
Ling Bouvier
Bart Simpson
Lisa Simpson
Maggie Simpson
from _2_arboles import *
def printElement(element):
print element
abuela = "Jacqueline Gurney"
marge = "Marge Bouvier"
patty = "Patty Bouvier"
selma = "Selma Bouvier"
bart = "Bart Simpson"
lisa = "Lisa Simpson"
maggie = "Maggie Simpson"
ling = "Ling Bouvier"
arbol = Arbol(abuela)
agregarElemento(arbol,
agregarElemento(arbol,
agregarElemento(arbol,
agregarElemento(arbol,
agregarElemento(arbol,
agregarElemento(arbol,
agregarElemento(arbol,
patty, abuela)
selma, abuela)
ling, selma)
marge, abuela)
bart, marge)
lisa, marge)
maggie, marge)
print profundidad(arbol)
print grado(arbol)
#
# PROFUNDIDAD
#
ejecutarProfundidadPrimero(arbol, printElement)
#
# ANCHO
#
ejecutarAnchoPrimero(arbol, printElement)
otra
from collections import deque
class Arbol:
def __init__(self, elemento):
self.elemento = elemento
self.hijos = []
def agregarElemento(arbol, elemento, elementoPadre):
subarbol = buscarSubarbol(arbol, elementoPadre);
subarbol.hijos.append(Arbol(elemento))
def buscarSubarbol(arbol, elemento):
if arbol.elemento == elemento:
return arbol
for subarbol in arbol.hijos:
encontrado = buscarSubarbol(subarbol, elemento)
if encontrado != None:
return encontrado
return None
# Exceptions
def profundidad(arbol):
if len(arbol.hijos) == 0:
return 1
profundidades = map(profundidad, arbol.hijos)
return 1 + max(profundidades)
def grado(arbol):
return max(map(grado, arbol.hijos) + [len(arbol.hijos)])
#
# RECORRIDOS
#
def ejecutarProfundidadPrimero(arbol, funcion):
funcion(arbol.elemento)
for hijo in arbol.hijos:
ejecutarProfundidadPrimero(hijo, funcion)
def ejecutarAnchoPrimero(arbol, funcion, cola = deque()):
funcion(arbol.elemento)
if (len(arbol.hijos) > 0):
cola.extend(arbol.hijos)
if (len(cola) != 0):
ejecutarAnchoPrimero(cola.popleft(), funcion, cola)
from collections import deque
class Arbol:
def __init__(self, elemento):
self.elemento = elemento
self.hijos = []
def agregarElemento(arbol, elemento, elementoPadre):
subarbol = buscarSubarbol(arbol, elementoPadre);
subarbol.hijos.append(Arbol(elemento))
def buscarSubarbol(arbol, elemento):
if arbol.elemento == elemento:
return arbol
for subarbol in arbol.hijos:
encontrado = buscarSubarbol(subarbol, elemento)
if encontrado != None:
return encontrado
return None
# Exceptions
def profundidad(arbol):
if len(arbol.hijos) == 0:
return 1
profundidades = map(profundidad, arbol.hijos)
return 1 + max(profundidades)
def grado(arbol):
return max(map(grado, arbol.hijos) + [len(arbol.hijos)])
#
# RECORRIDOS
#
def ejecutarProfundidadPrimero(arbol, funcion):
funcion(arbol.elemento)
for hijo in arbol.hijos:
ejecutarProfundidadPrimero(hijo, funcion)
def ejecutarAnchoPrimero(arbol, funcion, cola = deque()):
funcion(arbol.elemento)
if (len(arbol.hijos) > 0):
cola.extend(arbol.hijos)
if (len(cola) != 0):
ejecutarAnchoPrimero(cola.popleft(), funcion, cola)
1 Descripcin
2 Implementacin en Python
3 Operaciones
3.1 Bsqueda
3.2 Insercin
3.3 Borrado
3.5 Recorridos
4 Tipos de rboles binarios de bsqueda
5 Comparacin de rendimiento
7 Vase tambin
8 Referencias
9 Enlaces externos
Descripcin[editar]
Un rbol binario de bsqueda (ABB) es un rbol binario definido de la siguiente forma:
rbol binario
la mayora de los rboles binarios son de bsqueda
Un rbol binario no vaco, de raz R, es un rbol binario de bsqueda si:
En caso de tener subrbol izquierdo, la raz R debe ser mayor que el valor mximo
almacenado en el subrbol izquierdo, y que el subrbol izquierdo sea un rbol binario de
bsqueda.
En caso de tener subrbol derecho, la raz R debe ser menor que el valor mnimo
almacenado en el subrbol derecho, y que el subrbol derecho sea un rbol binario de
bsqueda.
Para una fcil comprensin queda resumido en que es un rbol binario que cumple que el
subrbol izquierdo de cualquier nodo (si no est vaco) contiene valores menores que el que
contiene dicho nodo, y el subrbol derecho (si no est vaco) contiene valores mayores.
Para estas definiciones se considera que hay una relacin de orden establecida entre los
elementos de los nodos. Que cierta relacin est definida, o no, depende de cada lenguaje de
programacin. De aqu se deduce que puede haber distintos rboles binarios de bsqueda
para un mismo conjunto de elementos.
La altura h en el peor de los casos es siempre el mismo tamao que el nmero de elementos
disponibles. Y en el mejor de los casos viene dada por la
expresin
podemos hacer la siguiente definicin para un rbol binario de bsqueda (tambin en maude):
fth ORDEN is
protecting BOOL .
sort Elt .
*** operaciones
op _<_ : Elt Elt -> Bool .
endfth
para que un rbol binario pertenezca al tipo rbol binario de bsqueda debe cumplir la
condicin de ordenacin siguiente que ira junto al mdulo ARBOL-BINARIO-BUSQUEDA:
var
R : X$Elt .
Implementacin en Python[editar]
class nodo:
Operaciones[editar]
Todas las operaciones realizadas sobre rboles binarios de bsqueda estn basadas en la
comparacin de los elementos o clave de los mismos, por lo que es necesaria una subrutina,
que puede estar predefinida en el lenguaje de programacin, que los compare y pueda
establecer una relacin de orden entre ellos, es decir, que dados dos elementos sea capaz de
reconocer cual es mayor y cual menor. Se habla de clave de un elemento porque en la
mayora de los casos el contenido de los nodos ser otro tipo de estructura y es necesario que
la comparacin se haga sobre algn campo al que se denomina clave.
Bsqueda[editar]
La bsqueda Silaina consiste en acceder a la raz del rbol, si el elemento a localizar coincide
con ste la bsqueda ha concluido con xito, si el elemento es menor se busca en el subrbol
izquierdo y si es mayor en el derecho. Si se alcanza un nodo hoja y el elemento no ha sido
encontrado se supone que no existe en el rbol. Cabe destacar que la bsqueda en este tipo
de rboles es muy eficiente, representa unafuncin logartmica. El mximo nmero de
comparaciones que necesitaramos para saber si un elemento se encuentra en un rbol
binario de bsqueda estara entre [log2(N+1)] y N, siendo N el nmero de nodos. La bsqueda
de un elemento en un ABB (rbol Binario de Bsqueda) se puede realizar de dos formas,
iterativa o recursiva.
Ejemplo de versin iterativa en el lenguaje de programacin C, suponiendo que estamos
buscando una clave alojada en un nodo donde est el correspondiente "dato" que precisamos
encontrar:
data Buscar_ABB(abb t,clave k)
{
abb p;
dato e;
e=NULL;
p=t;
if (!estaVacio(p))
{
while (!estaVacio(p) && (p->k!=k) )
{
if (k < p->k)
{
p=p->l;
}
if (p->k < k)
{
p=p->r;
}
}
if (!estaVacio(p) &&(p->d!=NULL) )
{
e=copiaDato(p->d);
}
}
return e;
}
Vase ahora la versin recursiva en ese mismo lenguaje:
busqueda:=busqueda(^T.dch,y);
else
busqueda:=busqueda(^T.izq,y);
end;
Una especificacin en maude para la operacin de bsqueda quedara de la siguiente forma:
Insercin[editar]
La insercin es similar a la bsqueda y se puede dar una solucin tanto iterativa como
recursiva. Si tenemos inicialmente como parmetro un rbol vaco se crea un nuevo nodo
como nico contenido el elemento a insertar. Si no lo est, se comprueba si el elemento dado
es menor que la raz del rbol inicial con lo que se inserta en el subrbol izquierdo y si es
mayor se inserta en el subrbol derecho.
// Puntero Avanzado
// Puntero Retrasado
FIN
PROC InsertarABB(rbol:TABB; dato:TElemento)
VARIABLES
ele:TElemento
INICIO
SI (ABBVaco(rbol)) ENTONCES
rbol <- NUEVO(TNodoABB)
rbol^.izq <- NULO
rbol^.der <- NULO
rbol^.elem <- dato
EN OTRO CASO
ele = InfoABB(rbol)
SI (dato.clave < ele.clave) ENTONCES
InsertarABB(rbol^.izq, dato)
EN OTRO CASO
InsertarABB(rbol^.dch, dato)
FINSI
FINSI
FIN
if R1 < R2 then
arbolBin(R2, insertar(R1,
I), D)
else
arbolBin(R2, I,
insertar(R1, D))
fi .
Borrado[editar]
La operacin de borrado no es tan sencilla como las de bsqueda e insercin. Existen varios
casos a tener en consideracin:
Borrar un nodo sin hijos o nodo hoja: simplemente se borra y se establece a nulo el
apuntador de su padre.
Nodo a eliminar 74
Borrar un nodo con un subrbol hijo: se borra el nodo y se asigna su subrbol hijo
como subrbol de su padre.
Nodo a eliminar 70
Borrar un nodo con dos subrboles hijo: la solucin 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 ms a la derecha de su subrbol
izquierdo (mayor nodo del subarbol izquierdo), y su sucesor el nodo ms a la izquierda de
su subrbol derecho (menor nodo del subarbol derecho). En la siguiente figura se muestra
cmo existe la posibilidad de realizar cualquiera de ambos reemplazos:
Nodo a eliminar 59
*a = (*a)->hIzquierdo;
}
else
reemplazar(&(*a)->hDerecho, & aux);
}
Otro ejemplo en Pascal.
Procedure Borrar(var T:ABR, x:ABR)
var
aBorrar:ABR;
anterior:ABR;
actual:ABR;
hijo:ABR;
begin
if (^x.izq=nil) or (^x.dch=nil) then
aBorrar:=x;
else
aBorrar:=sucesor(T,x);
actual:=T;
anterior:=nil;
while (actual<>aBorrar) do
begin
anterior:=actual;
if (^actual.raiz<^aBorrar.raiz) then
actual:=^actual.dch;
else
actual:=^actual.izq;
end;
if (^actual.izq=nil) then
hijo:=^actual.dch;
else
hijo:=^actual.izq;
if (anterior=nil) then
T:=hijo;
else
if (^anterior.raiz<^actual.raiz) then
^anterior.dch:=hijo;
else
^anterior.izq:=hijo;
if (aBorrar<>x) then
^x.raiz:=^aBorrar.raiz;
free(aBorrar);
end;
Otras Operaciones[editar]
Otra operacin sera por ejemplo comprobar que un rbol binario es un rbol binario de
bsqueda. Su implementacin en maude es la siguiente:
op
var
vars
R : X$Elt .
I D : ABB{X} .
eq esABB?(crear) = true .
eq esABB?(arbolbBin(R, I, D)) =
(Max(I) < R) and (Min(D) > R) and
(esABB?(I)) and (esABB?(D)) .
Recorridos[editar]
Se puede hacer un recorrido de un rbol en profundidad o en anchura.
Los recorridos en anchura son por niveles, se realiza horizontalmente desde la raz a todos los
hijos antes de pasar a la descendencia de alguno de los hijos.
El coste de recorrer el ABB es O(n), ya que se necesitan visitar todos los vrtices.
El recorrido en profundidad lleva al camino desde la raz hacia el descendiente ms lejano del
primer hijo y luego contina con el siguiente hijo. Como recorridos en profundidad
tenemos inorden, preorden y postorden.
Una propiedad de los ABB es que al hacer un recorrido en profundidad inorden obtenemos los
elementos ordenados de forma ascendente.
If IsNothing(padre) Then
Return
End If
cadenasalida = cadenasalida & "-" & padre.dato
rePreorden(padre.ant)
rePreorden(padre.sig)
End Sub
'funcin de recorrido en POSTORDEN
Public Function postorden() As String
cadenasalida = ""
reposorden(raz)
Return cadenasalida
End Function
Private Sub repostorden(ByVal padre As Nodo)
If IsNothing(padre) Then
Return
End If
repostorden(padre.ant)
repostorden(padre.sig)
cadenasalida = cadenasalida & "-" & padre.dato
End Sub
'funcin de recorrido en ENORDEN
Public Function inorden() As String
cadenasalida = ""
reinorden(raz)
Return cadenasalida
End Function
Private Sub reinorden(ByVal padre As Nodo)
If IsNothing(padre) Then
Return
End If
reinorden(padre.ant)
cadenasalida = cadenasalida & "-" & padre.dato
reinorden(padre.sig)
End Sub
los niveles estn llenos con excepcin del ltimo que puede no estarlo, por ltimo, en lo
montculos, cada nodo mantiene una prioridad y siempre, un nodo padre tendr una prioridad
mayor a la de su hijo.
Otras dos maneras de configurar un rbol binario de bsqueda podra ser como un rbol
completo o degenerado.
Un rbol completo es un rbol con "n" niveles, donde cada nivel d <= n-1; el nmero de nodos
existentes en el nivel "d" es igual que 2d. Esto significa que todos los posibles nodos existen
en esos niveles, no hay ningn hueco. Un requirimiento adicional para un rbol binario
completo es que para el nivel "n", los nodos deben estar ocupados de izquierda a derecha, no
pudiendo haber un hueco a la izquierda de un nodo ocupado.
Un rbol degenerativo es un rbol que, para cada nodo padre, slo hay asociado un nodo hijo.
Por lo que se comporta como una lista enlazada.
Comparacin de rendimiento[editar]
D. A. Heger(2004)1 realiza una comparacin entre los diferentes tipos de rboles binarios de
bsqueda para encontrar que tipo nos dara el mejor rendimiento para cada caso. Los
montculos se encuentran como el tipo de rbol binario de bsqueda que mejor resultado
promedio da, mientras que los rboles rojo-negro los que menor rendimiento medio nos
aporta.
En cambio, si no sabemos la secuencia en la que los elementos del rbol van a ser accedidos,
podemos usar rboles biselados que son tan buenos como cualquier rbol de bsqueda que
podemos construir para cualquier secuencia en particular de operaciones de bsqueda.
rboles alfabticos son rboles Huffman con una restriccin de orden adicional, o lo que es lo
mismo, rboles de bsqueda con modificacin tal que todos los elementos son almacenados
en las hojas.
Contenido
[ocultar]
1 rboles
1.3 Definiciones
1.6.4.1.1 Demostracin
1.6.4.2 Operaciones
1.7 rboles B
1.7.2 Bsqueda
1.7.3 Insercin
1.7.4 Borrado
1.8 rboles B+
1.8.2 Insercin
1.8.3 Eliminacin
rboles[editar]
rbol: estructura no lineal y dinmica de datos. Dinmica: puede cambiar durante la ejecucin
de un programa. No lineal: a cada elemento del rbol pueden seguirle varios elementos. Estn
formados por un conjunto de nodos y un conjunto de aristas que conectan pares de nodos.
Definicin no recursiva[editar]
Conjunto de nodos y conjunto de aristas que conectan pares de nodos con las siguientes
caractersticas:
A cada nodo c (excepto la raz) le llega una arista desde exactamente un nodo p
diferente a c, al cual se le llama padre de c.
Hay un nico camino desde la raz hasta cada nodo. La misma longitud del camino es
su nmero de aristas.
Definicin recursiva[editar]
Un rbol es o bien vaco o consiste en una raz y cero o ms subrboles no vacos
,
, cada una de cuyas races est conectada por medio de una arista con la raz.
Definiciones[editar]
v son propios.
Operaciones bsicas[editar]
Insertar
Buscar
Eliminar
Ir a la raz
Recorrer
rboles binarios[editar]
Un rbol binario es o bien vaco o consta de una raz, un hijo rbol binario izquierdo y otro
derecho. Los rboles binarios de bsqueda permiten inserciones y acceso a los elementos en
tiempo logartmico. Los rboles binarios llamados colas con prioridad soportan acceso y
eliminacin del mnimo de una coleccin de elementos.
Todos los valores de los nodos del subrbol izquierdo de A deben ser menores al valor
del nodo A.
Todos los valores de los nodos del subrbol derecho de A deben ser mayores o iguales
al valor del nodo A. Un recorrido en inorden del rbol proporciona una lista en orden
ascendente de los valores almacenados en los nodos. Para describir las operaciones, se
considera que estas se enmarcan dentro de la clase NodoBinario. El lenguaje utilizado es
JAVA.
Operacin buscar[editar]
public boolean buscar(Object o)
{
if (o.equals(valor))
return true;
else if (o.compareTo(valor)<0)
return buscar(getIzq(),o);
else return buscar(getDer(),o);
}
Operacin insertar[editar]
public NodoBinario insertar(Comparable o){
if (o.compareTo(valor)<0)
setIzq(insertar(getIzq(),o));
else setDer(insertar(getDer(),o));
return this;
}
Operacin recorrer[editar]
Los recorridos pueden ser en preorden, postorden o inorden (orden simtrico). Todos son
O(N).
Los recorridos no necesitan obligatoriamente recursividad, se puede emplear una pila para
realizarlos iterativamente.
Operacin borrado[editar]
El nodo a borrar debe ser reemplazado por el nodo ms a la derecha en el subrbol izquierdo
o el nodo ms a la izquierda en el subrbol derecho (el nodo ms a la derecha del subrbol
izquierdo ser mayor o igual que cualquier otro nodo de ese subrbol y menor que todos los
del subrbol derecho, y el nodo ms a la izquierda del subrbol derecho ser menor que todos
los dems nodos de ese subrbol y mayor que todos los del subrbol izquierdo). Para el caso
en el que el nodo elegido tengo un subrbol, hay por lo menos tres soluciones posibles:
La segunda solucin consiste en colgar del padre del nodo promovido hacia la raz, el
subrbol remanente. Esto es consistente, porque todo elemento del subrbol derecho de
un nodo ser mayor que el valor de ese nodo, y viceversa. Estas soluciones aprovechan
la ventaja de contar con que el nodo promovido tiene, a lo sumo, un subrbol.
Un hueco dejado por un nodo promovido tambin puede pensarse como una
eliminacin. un arbol es un arbol jajaja
rboles equilibrados[editar]
Un procedimiento de insercin que siempre restaure la estructura del rbol a un equilibrio
perfecto es poco eficiente. Se usa una formulacin menos estricta de equilibrio: Un rbol
est equilibrado si para cada uno de sus nodos ocurre que las alturas de sus dos subrboles
difieren como mucho en 1(rboles AVL).
Borrar un nodo con una clave dada. Un rbol AVL de altura H tiene por lo menos
(Fibonacci(H+3) -1) nodos. Los pasos necesarios para insertar un nodo en un rbol AVL
son:
B.setDer(A);
return B;
}
Como se ve, el problema se convirti en un problema igual al del primer caso. Los pasos
necesarios para suprimir un nodo en un rbol AVL son:
rboles rojinegros[editar]
rbol binario de bsqueda, donde cada nodo est coloreado con los colores rojo o negro, y se
verifican las siguientes propiedades:
1. La raz es negra.
2. Si un nodo es rojo, sus hijos deben ser negros.
3. Todos los caminos desde un nodo a un nodo vaco deben contener el mismo nmero de
nodos negros.
Las condiciones (2) y (3) aseguran que el rbol nunca est demasiado desbalanceado. (2)
asegura que no puedan haber demasiados nodos rojos, y (3) dice que, despreciando el
nmero de nodos rojos, que es limitado, el rbol es perfectamente balanceado. La condicin
(1) es trivial: si la raz es roja, simplemente se colorea negra, ya que esto no violar ninguna
regla. En los ARN la operacin eliminar se complica. Cuando se necesitan rboles
equilibrados y se requieren muchas eliminaciones se emplean los AA-rboles que aaden una
condicin adicional a las impuestas por los ARN:
4. Los hijos izquierdos no pueden ser rojos.
Altura de un ARN[editar]
En un ARN con n nodos, la altura h ser:
Demostracin[editar]
La condicin (3) nos permite asegurar que, despreciando el nmero de nodos rojos, el rbol
es perfectamente balanceado, y, en virtud de esa caracterstica, su
altura
. La condicin (2) evita que haya nodos rojos consecutivos, como
mximo, la mitad de los nodos de un camino -que constituirn una altura- sern rojos.
Operaciones[editar]
Se pueden realizar operaciones de bsqueda con complejidad O(log N), por lo expuesto
anteriormente. Al realizar una insercin, la complejidad de bsqueda ser O(log N), pero
aparece un problema: el resultado ser un rbol de bsqueda binario, pero no necesariamente
un ARN. Si coloreamos el nuevo nodo rojo, el balance de negros quedar intacto, pero se
puede incurrir en una violacin rojo-rojo. Si lo coloreamos negro, no se incurrir en una
violacin rojo-rojo, pero en este caso, siempre alteraremos el balance de negros. Al eliminar, si
el nodo a eliminar es negro, ambas violaciones pueden aparecer.
Reparacin del balance del rbol[editar]
Una vez detectada una violacin, se deben tomar medidas que reparen el balance del rbol.
Estas medidas utilizan dos herramientas: rotaciones y cambios de color.
Insercin ascendente[editar]
Sea X la nueva hoja aadida, P su padre, S el hermano de P (si existe) y G el abuelo.
1. Los nuevos nodos se insertan en el rbol como hojas de color rojo.
2. Si el padre es negro, hemos acabado.
3. Si el padre es rojo violamos la regla 2, entonces debemos modificar el rbol de forma que
se cumpla la regla (2) sin introducir violaciones de la propiedad (3).
4. Si el padre P es la raz, se colorea negro. La altura negra aumenta en 1, pero el balance se
preserva. Hemos acabado.
Reparacin del balance[editar]
Asumiendo que P no es la raz
5. Si S es rojo, se puede aplicar un cambio de color: Se elimina as la violacin, y el balance
de negros se mantiene. Qu pasa si el padre de G es tambin rojo? Solucin: propagar este
procedimiento hacia arriba hasta conseguir que no haya dos nodos rojos consecutivos o
alcanzar la raz. Esta propagacin es anloga a la que se hace en los rboles AVL.
6. Si S es negro, tenemos dos casos, con sus simtricos asociados: violacin en el margen, y
violacin por dentro.
7. Si es una violacin es por dentro, la convertimos a una violacin en el margen haciendo una
rotacin: Como X y P son rojos, no aaden nada en el balance de negros a los caminos que
pasan por g, de manera que el balance se preserva.
8. Teniendo el caso de violacin por dentro, se efecta una rotacin simple. La rama izquierda
de desbalancea, le falta un nodo negro para todos sus caminos, y an tenemos la violacin
rojo-rojo. Solucionamos ambos problemas haciendo un cambio de color.
Insercin descendente[editar]
Objetivo: garantizar que en el momento de la insercin S no sea rojo, de manera que slo
haya que aadir una hoja roja y, si fuere necesario, realizar una rotacin (simple o doble). En
el camino descendente, si un nodo X tiene dos hijos rojos, el color de X cambia a rojo y el de
sus dos hijos a negro. El nmero de nodos negros en los caminos por debajo de X permanece
inalterable. Si X es la raz, la convertiramos en roja, hay que volver a negro (esto no puede
violar ninguna de las reglas). Si el padre de X es rojo, hay que aplicar rotacin simple o doble.
Qu pasa si el hermano del padre de X es tambin rojo? Esta situacin NO puede darse,
gracias al proceso efectuado en el camino descendiente.
rboles B[editar]
, la altura
Cada pgina, excepto la pgina raz y las pginas hojas, tienen entre M/2 y M
descendientes, y entre (M/2 -1) y (M-1) elementos.
Bsqueda[editar]
Debe tenerse en memoria principal la pgina sobre la cual vamos a buscar. Considrese el
elemento a buscar x. Si la bsqueda es infructuosa dentro de la pgina se estar en una de
las siguientes situaciones:
.
. Si en algn caso la referencia es nula,
Insercin[editar]
Siempre se inserta en los nodos hojas. Primero se comprueba que la clave no se encuentre
en el rbol. Si la cantidad de elementos es menor que 2n:
Los 2n+1 elementos se dividen en dos pginas, excluyendo la clave del medio.
Borrado[editar]
Si la clave a ser borrada no est en una hoja, su predecesor inmediato tiene que estar en una
hoja (esto se debe a que todas las hojas tienen el mismo nivel, de manera que si existe un
valor menor en un nodo ms abajo, tambin tiene que haber uno mayor), y se puede
promover, y as borrar el espacio que estaba en la hoja. Si la hoja queda con menos de n
elementos, se comprueba si se puede promover un elemento de un hermano adyacente a su
padre, y bajar el del padre a la hoja. Si el hermano tiene slo n elementos, las dos hojas y la
clave del medio se unen, y la clave del medio se elimina del nodo padre.
rboles B+[editar]
Las diferencias con los rboles B son que:
Slo los nodos hoja apuntan a los registros o cubetas del fichero.
Existe un orden lineal entre las hojas, que estn encadenadas mediante punteros para
permitir un eficiente acceso secuencial.
Insercin[editar]
Se busca el nodo hoja correspondiente y se inserta la clave si no est all. Si tiene lugar una
particin, se inserta una clave en el nodo padre, que ser duplicada si la particin ocurre en
una hoja.
1. include<conio.h>
2. include<stdio.h>
3. include<iostream.h>
4. include<stdlib.h>
5. include<dos.h>
struct nodo {
int valor;
struct nodo*sig;
}*cab; void insertar(int num); void mostrar(void); void BorrarTodo(void); void Eliminar(int num);
void insertord(int num);
while(1)
{
clrscr();
printf("1.-Insertar un nodo.\n2.-Eliminar un nodo.\n3.-Mostrar\n4.Insettar nodos en orden\n0.-Salir\n");
printf("\nElige una opcion: ");
scanf("%d",&op);
switch(op)
{
case 1:
printf("Valor del nodo que deseas insertar: ");
scanf("%d",&num);
insertar(num);
break;
case 2:
printf("Dame el valor del nodo a eliminar: ");
scanf("%d",&num);
Eliminar(num);
break;
case 3:
mostrar();
break;
case 4:
printf("Valor del nodo que deseas insertar: ");
scanf("%d",&num);
insertord(num);
break;
case 0:
BorrarTodo();
exit(0);//para usar exit debes declarar stdlib.h
break;
default:
printf("ERROR Opcion incorrecta");
getch();
}
getch();
}
nodo *aux,*nuevo;
aux=cab;
nuevo=new nodo;
nuevo->valor=num;
nuevo->sig=NULL;
if(cab==NULL)
cab=nuevo;
else
{
while(aux->sig!=NULL)
aux=aux->sig;
aux->sig=nuevo;
}
void mostrar()
{
nodo *aux; //Aux es un apuntador
aux=cab; //En esta line aux toma la direccion de cab
while(aux!=NULL)
{
printf("%d, ",aux->valor);
aux=aux->sig;
}
}
void BorrarTodo(void)
{
nodo *aux;
aux=cab;
while(aux!=NULL)
{
cab=aux->sig;
delete aux;
aux=cab;
}
}
if(c==1)
{
if(prev->sig==NULL)
{
cab=cab->sig;
delete aux;
}
else
{
aux2 = aux->sig;
prev->sig = aux2;
delete aux;
}
}
nodo *aux,*nuevo,*aux2,*prev;
int c=0;
aux2=cab;
nuevo=new nodo;
// nuevo->valor=num;
while(aux2!=NULL)
{
if(aux2->valor>=num)
{
prev->sig=nuevo;
nuevo->valor=num;
nuevo->sig=aux2;
cab=prev;
aux2=NULL;
c=1;
}
prev=aux2;
aux2=aux2->sig;
}
if(aux2==NULL)
if(c==0)
{
insertar(num);
}
else
{
delete aux2;
}
Eliminacin[editar]
Se busca el nodo hoja correspondiente y se elimina la clave. Si al eliminar una clave, n queda
menor a (M/2 -1), entonces debe realizarse una redistribucin de claves, tanto en el ndice
como en las pginas hojas.
1. include<conio.h>
2. include<stdio.h>
3. include<iostream.h>
4. include<stdlib.h>
5. include<dos.h>
struct nodo {
int valor;
struct nodo*sig;
}*cab; void insertar(int num); void mostrar(void); void BorrarTodo(void); void Eliminar(int num);
void insertord(int num);
while(1)
{
clrscr();
printf("1.-Insertar un nodo.\n2.-Eliminar un nodo.\n3.-Mostrar\n4.Insettar nodos en orden\n0.-Salir\n");
printf("\nElige una opcion: ");
scanf("%d",&op);
switch(op)
{
case 1:
printf("Valor del nodo que deseas insertar: ");
scanf("%d",&num);
insertar(num);
break;
case 2:
printf("Dame el valor del nodo a eliminar: ");
scanf("%d",&num);
Eliminar(num);
break;
case 3:
mostrar();
break;
case 4:
printf("Valor del nodo que deseas insertar: ");
scanf("%d",&num);
insertord(num);
break;
case 0:
BorrarTodo();
exit(0);//para usar exit debes declarar stdlib.h
break;
default:
printf("ERROR Opcion incorrecta");
getch();
}
getch();
}
nodo *aux,*nuevo;
aux=cab;
nuevo=new nodo;
nuevo->valor=num;
nuevo->sig=NULL;
if(cab==NULL)
cab=nuevo;
else
{
while(aux->sig!=NULL)
aux=aux->sig;
aux->sig=nuevo;
}
void mostrar()
{
nodo *aux; //Aux es un apuntador
aux=cab; //En esta line aux toma la direccion de cab
while(aux!=NULL)
{
printf("%d, ",aux->valor);
aux=aux->sig;
}
}
void BorrarTodo(void)
{
nodo *aux;
aux=cab;
while(aux!=NULL)
{
cab=aux->sig;
delete aux;
aux=cab;
}
}
{
aux2 = aux->sig;
prev->sig = aux2;
delete aux;
}
}
nodo *aux,*nuevo,*aux2,*prev;
int c=0;
aux2=cab;
nuevo=new nodo;
// nuevo->valor=num;
while(aux2!=NULL)
{
if(aux2->valor>=num)
{
prev->sig=nuevo;
nuevo->valor=num;
nuevo->sig=aux2;
cab=prev;
aux2=NULL;
c=1;
}
prev=aux2;
aux2=aux2->sig;
}
if(aux2==NULL)
if(c==0)
{
insertar(num);
}
else
{
delete aux2;
}
}
Categ