Вы находитесь на странице: 1из 57

6.

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

Definiremos varios conceptos. En relacin con otros nodos:

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:

Orden: es el nmero potencial de hijos que puede tener cada elemento


de rbol. De este modo, diremos que un rbol en el que cada nodo puede
apuntar a otros dos es de orden dos, si puede apuntar a tres ser
de orden tres, etc.
Grado: el nmero de hijos que tiene el elemento con ms hijos dentro
del rbol. En el rbol del ejemplo, el grado es tres, ya que tanto 'A' como
'D' tienen tres hijos, y no existen elementos con ms de tres hijos.
Nivel: se define para cada elemento del rbol como la distancia a la
raz, medida en nodos. El nivel de la raz es cero y el de sus hijos uno.
As sucesivamente. En el ejemplo, el nodo 'D' tiene nivel 1, el nodo 'G'
tiene nivel 2, y el nodo 'N', nivel 3.
Altura: la altura de un rbol se define como el nivel del nodo de mayor
nivel. Como cada nodo de un rbol puede considerarse a su vez como la
raz de un rbol, tambin podemos hablar de altura de ramas. El rbol
del ejemplo tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene
altura 1, la 'H' cero, etc.
Los rboles de orden dos son bastante especiales, de hecho les dedicaremos varios
captulos. Estos rboles se conocen tambin como rboles binarios.
Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil
moverse a travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo
padre. De este modo podremos avanzar en direccin a la raz, y no slo hacia las hojas.
Es importante conservar siempre el nodo raz ya que es el nodo a partir del cual se
desarrolla el rbol, si perdemos este nodo, perderemos el acceso a todo el rbol.
El nodo tpico de un rbol difiere de los nodos que hemos visto hasta ahora para listas,
aunque slo en el nmero de nodos. Veamos un ejemplo de nodo para crear rboles de
orden tres:
struct nodo {
int dato;
struct nodo *rama1;
struct nodo *rama2;
struct nodo *rama3;
};

O generalizando ms:
#define ORDEN 5

struct nodo {
int dato;
struct nodo *rama[ORDEN];
};

6.2 Declaraciones de tipos para manejar rboles en C


^

Para C, y basndonos en la declaracin de nodo que hemos visto ms arriba,


trabajaremos con los siguientes tipos:
typedef struct _nodo {
int dato;
struct _nodo *rama[ORDEN];
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Arbol;

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

El movimiento a travs de rboles, salvo que implementemos punteros al nodo padre,


ser siempre partiendo del nodo raz hacia un nodo hoja. Cada vez que lleguemos a un
nuevo nodo podremos optar por cualquiera de los nodos a los que apunta para avanzar
al siguiente nodo.
En general, intentaremos que exista algn significado asociado a cada uno de los
punteros dentro de cada nodo, los rboles que estamos viendo son abstractos, pero las
aplicaciones no tienen por qu serlo. Un ejemplo de estructura en rbol es el sistema
de directorios y ficheros de un sistema operativo. Aunque en este caso se trata de
rboles con nodos de dos tipos, nodos directotio y nodos fichero, podramos considerar
que los nodos hoja son ficheros y los nodos rama son directorios.
Otro ejemplo podra ser la tabla de contenido de un libro, por ejemplo de este mismo
curso, dividido en captulos, y cada uno de ellos en subcaptulos. Aunque el libro sea

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.

3 Ejemplo de un rbol en python

4.

4 Recorridos

1.

4.1 Profundidad Primero

2.

4.2 Ancho Primero

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.

Cada nodo puede tener ms de un hijo, pero un solo padre.

Existe un nodo que no tiene padre denominado raiz.

Los nodos que no tienen hijos se denominan hojas

Un rbol es de orden N (o N-ario) cuando la mxima cantidad de hijos que puede tener

La profundidad de un rbol es la distancia (saltos entre nodos) desde la raiz hasta


lejana.

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.

Ejemplo de un rbol en python


definicin

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)

agregarElemento(arbol, maggie, 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.

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:
arbolBuscado = buscarSubarbol(subarbol, elemento)
if (arbolBuscado != None):
return arbolBuscado
return None

Profundidad y grado

La profundidad de un rbol es 1 + la profundidad del hijo ms profundo

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 ejecutarProfundidadPrimero(arbol, funcion):


funcion(arbol.elemento)
for hijo in arbol.hijos:
ejecutarProfundidadPrimero(hijo, funcion)

Al utilizarlo con una funcin que imprime un elemento :

def printElement(element):
print element
ejecutarProfundidadPrimero(arbol, printElement)

podemos ver el siguiente resultado:


Jacqueline Gurney

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.

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)
Se usa de la siguiente manera:
def printElement(element):
print element
ejecutarAnchoPrimero(arbol, printElement)

Veamos paso a paso que ocurre:

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)

rbol binario de bsqueda


Un rbol binario de bsqueda tambin llamados BST (acrnimo
del ingls Binary Search Tree) es un tipo particular de rbol binario que presenta
una estructura de datos en forma de rbol usada en informtica.
ndice
[ocultar]

1 Descripcin

2 Implementacin en Python

3 Operaciones

3.1 Bsqueda

3.2 Insercin

3.3 Borrado

3.4 Otras Operaciones

3.5 Recorridos
4 Tipos de rboles binarios de bsqueda

5 Comparacin de rendimiento

6 Buscando el rbol binario de bsqueda ptimo

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.

Un rbol binario de bsqueda de tamao 9 y profundidad 3, con raz 8 y hojas 1, 4, 7 y 13

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

, donde ceil indica redondeo por exceso.

El inters de los rboles binarios de bsqueda (ABB) radica en que su recorrido en


inordenproporciona los elementos ordenados de forma ascendente y en que la bsqueda de
algn elemento suele ser muy eficiente.
Dependiendo de las necesidades del usuario que trate con una estructura de este tipo, se
podr permitir la igualdad estricta en alguno, en ninguno o en ambos de los subrboles que
penden de la raz. Permitir el uso de la igualdad provoca la aparicin de valores dobles y hace
la bsqueda ms compleja.
Un rbol binario de bsqueda no deja de ser un caso particular de rbol binario, as usando la
siguiente especificacin de rbol binario enmaude:

fmod ARBOL-BINARIO {X :: TRIV}is


sorts ArbolBinNV{X} ArbolBin{X} .
subsort ArbolBinNV{X} < ArbolBin{X} .
*** generadores
op crear : -> ArbolBin{X} [ctor] .
op arbolBin : X$Elt ArbolBin{X} ArbolBin{X} -> ArbolBinNV{X} [ctor] .
endfm

podemos hacer la siguiente definicin para un rbol binario de bsqueda (tambin en maude):

fmod ARBOL-BINARIO-BUSQUEDA {X :: ORDEN} is


protecting ARBOL-BINARIO{VOrden}{X} .
sorts ABB{X} ABBNV{X} .
subsort ABBNV{X} < ABB{X} .

subsort ABB{X} < ArbolBin{VOrden}{X} .


subsort ABBNV{X} < ArbolBinNV{VOrden}{X} .
*** generadores
op crear : -> ArbolBin{X} [ctor] .
op arbolBin : X$Elt ArbolBin{X} ArbolBin{X} -> ArbolBinNV{X} [ctor] .
endfm

con la siguiente teora de orden:

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 .

vars INV DNV : ABBNV{X} .


vars I D : ABB{X} .
mb crear : ABB{X} .
mb arbolBin(R, crear, crear) : ABBNV{X} .
cmb arbolBin(R, INV, crear) : ABBNV{X} if R > max(INV) .
cmb arbolBin(R, crear, DNV) : ABBNV{X} if R < min(DNV) .
cmb arbolBin(R, INV, DNV) : ABBNV{X} if (R > max(INV)) and (R <
min(DNV)) .
ops min max : ABBNV{X} -> X$Elt .
eq min(arbolBin(R, crear, D)) = R .
eq min(arbolBin(R, INV, D)) = min(INV) .
eq max(arbolBin(R, I, crear)) = R .
eq max(arbolBin(R, I, DNV)) = max(DNV) .

Implementacin en Python[editar]
class nodo:

izq , der, dato = None, None, 0


def __init__(self, dato):
# crea un nodo
self.izq = None
self.der = None
self.dato = dato
class arbolBinario:
def __init__(self):
# inicializa la raiz
self.raiz = None
def agregarNodo(self, dato):
# crea un nuevo nodo y lo devuelve
return nodo(dato)
def insertar(self, raiz, dato):
# inserta un dato nuevo en el rbol
if raiz == None:
# si no hay nodos en el rbol lo agrega
return self.agregarNodo(dato)
else:
# si hay nodos en el rbol lo recorre
if dato <= raiz.dato:
# si el dato ingresado es menor que el dato guardado
va al subrbol izquierdo
raiz.izq = self.insertar(raiz.izq, dato)
else:
# si no, procesa el subrbol derecho
raiz.der = self.insertar(raiz.der, dato)
return raiz

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:

int buscar(tArbol *a, int elem)


{
if (a == NULL)
{
return 0;
}
else if (a->clave < elem)
{
return buscar(a->hDerecho, elem);
}
else if (a->clave > elem)
{
return buscar(a->hIzquierdo, elem);
}
else
{
return 1;
}
}
Otro ejemplo en Python:
def buscar(raiz, clave):
# busca el valor clave dentro del arbol
if raiz == None:
print 'No se encuentra'
else:
#
if clave == raiz.dato:
print 'El valor ',clave,' se encuentra en el ABB'
elif clave < raiz.dato:
# lado izquierdo
return buscar(raiz.izq, clave)
else:
# lado derecho
return buscar(raiz.der, clave)
En Pascal:
Function busqueda(T:ABR, y: integer):ABR
begin
if (T=nil) or (^T.raiz=y) then
busqueda:=T;
else
if (^T.raiz<y) then

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:

op esta? : X$Elt ABB{X} -> Bool .


var R R1 R2 : X$Elt .
vars I D : ABB{X} .
eq esta?(R, crear) = false .
eq esta?(R1, arbolBin(R2, I, D)) = if R1 == R2 then
true
else
if R1 < R2 then
esta?(R1, I)
else
esta?(R1, D)
fi
fi .

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.

Evolucin de la insercin del elemento "5" en un ABB.

Como en el caso de la bsqueda puede haber varias variantes a la hora de implementar la


insercin en el TAD (Tipo Abstracto de Datos), y es la decisin a tomar cuando el elemento (o
clave del elemento) a insertar ya se encuentra en el rbol, puede que ste sea modificado o
que sea ignorada la insercin. Es obvio que esta operacin modifica el ABB perdiendo la
versin anterior del mismo.
A continuacin se muestran las dos versiones del algoritmo en pseudolenguaje, iterativa y
recursiva, respectivamente.

PROC InsertarABB(rbol:TABB; dato:TElemento)


VARIABLES
nuevonodo,pav,pret:TABB
clavenueva:Tclave
ele:TElemento
INICIO
nuevonodo <- NUEVO(TNodoABB)
nuevonodo^.izq <- NULO
nuevonodo^.der <- NULO
nuevonodo^.elem <- dato
SI ABBVaco (rbol) ENTONCES
rbol <- nuevonodo
ENOTROCASO
clavenueva <- dato.clave
pav <- rbol

// Puntero Avanzado

pret <- NULO

// Puntero Retrasado

MIENTRAS (pav <- NULO) HACER


pret <- pav
ele = pav^.elem
SI (clavenueva < ele.clave ) ENTONCES
pav <- pav^.izq
EN OTRO CASO
pav <- pav^.dch
FINSI
FINMIENTRAS
ele = pret^.elem
SI (clavenueva < ele.clave ) ENTONCES
pret^.izq <- nuevonodo
EN OTRO CASO
pret^.dch <- nuevonodo
FINSI
FINSI

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

Se ha podido apreciar la simplicidad que ofrece la versin recursiva, este algoritmo es la


traduccin en C. El rbol es pasado por referenciapara que los nuevos enlaces a los
subrboles mantengan la coherencia.
void insertar(tArbol **a, int elem)
{
if (*a == NULL)
{
*a = (tArbol *) malloc(sizeof(tArbol));
(*a)->clave = elem;
(*a)->hIzquierdo = NULL;
(*a)->hDerecho = NULL;
}
else if ((*a)->clave < elem)
insertar(&(*a)->hDerecho, elem);
else if ((*a)->clave > elem)
insertar(&(*a)->hIzquierdo, elem);
}
En Python el mecanismo de insercin se define, por ejemplo, dentro de la clase que defina el
ABB (ver ms arriba).

Otro ejemplo en Pascal:


Procedure Insercion(var T:ABR, y:integer)
var
ultimo:ABR;
actual:ABR;
nuevo:ABR;
begin
ultimo:=nil;
actual:=T;
while (actual<>nil) do
begin
ultimo:=actual;
if (actual^.raiz<y) then
actual:=actual^.dch
else
actual:=actual^.izq;
end;
new(nuevo);
^nuevo.raiz:=y;
^nuevo.izq:=nil;
^nuevo.dch:=nil;
if ultimo=nil then
T:=nuevo
else
if ultimo^.raiz<y then
ultimo^.dch:=nuevo
else
ultimo^.izq:=nuevo;
end;
Vase tambin un ejemplo de algoritmo recursivo de insercin en un ABB en el lenguaje de
programacin Maude:

op insertar : X$Elt ABB{X} -> ABBNV{X} .


var R R1 R2 : X$Elt .
vars I D : ABB{X} .
eq insertar(R, crear) = arbolBin(R, crear, crear) .
eq insertar(R1, arbolBin(R2, I, D)) =

if R1 < R2 then
arbolBin(R2, insertar(R1,

I), D)
else

arbolBin(R2, I,
insertar(R1, D))
fi .

La operacin de insercin requiere, en el peor de los casos, un tiempo proporcional a la altura


del rbol.

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

El siguiente algoritmo en C realiza el borrado en un ABB. El procedimiento reemplazar busca


la mayor clave del subrbol izquierdo y la asigna al nodo a eliminar.
void reemplazar(tArbol **a, tArbol **aux); /*Prototipo de la funcion
''reemplazar''*/
void borrar(tArbol **a, int elem)
{
tArbol *aux;
if (*a == NULL)
return;
if ((*a)->clave < elem)
borrar(&(*a)->hDerecho, elem);
else if ((*a)->clave > elem)
borrar(&(*a)->hIzquierdo, elem);
else if ((*a)->clave == elem)
{
aux = *a;
if ((*a)->hIzquierdo == NULL)
*a = (*a)->hDerecho;
else if ((*a)->hDerecho == NULL)
*a = (*a)->hIzquierdo;
else
reemplazar(&(*a)->hIzquierdo, &aux);
free(aux);
}
}
void reemplazar(tArbol **a, tArbol **aux)
{
if ((*a)->hDerecho == NULL)
{
(*aux)->clave = (*a)->clave;
*aux = *a;

*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;

Vase tambin un ejemplo de algoritmo recursivo de borrado en un ABB en el lenguaje de


programacin Maude, considerando los generadores crear y arbolBin. Esta especificacin
hace uso de la componente clave a partir de la cual se ordena el rbol.

op eliminar : X$Elt ABB{X} -> ABB{X} .


varS R M : X$Elt .
vars I D : ABB{X} .
vars INV DNV : ABBNV{X} .
ops max min : ArbolBin{X} -> X$Elt .
eq min(arbolBin(R, crear, D)) = R .
eq max(arbolBin(R, I, crear)) = R .
eq min(arbolBin(R, INV, D)) = min(INV) .
eq max(arbolBin(R, I, DNV )) = max(DNV) .
eq eliminar(M, crear) = crear .
ceq eliminar(M, arbolBin(R, crear, D)) = D if M == clave(R) .
ceq eliminar(M, arbolBin(R, I, crear)) = I if M == clave(R) .
ceq eliminar(M, arbolBin(R, INV, DNV)) = arbolBin(max(INV),
eliminar(clave(max(INV)), INV), DNV) if M == clave(R) .
ceq eliminar(M, arbolBin(R, I, D)) = arbolBin(R, eliminar(M, I), D)
if M < clave(R) .
ceq eliminar(M, arbolBin(R, I, D)) = arbolBin(R, I, eliminar(M, D))
if clave(R) < M .

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

esABB? : ABB{X} -> Bool .

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.

Ejemplo rbol binario de bsqueda

Resultado de hacer el recorrido en:


Inorden = [6, 9, 13, 14, 15, 17, 20, 26, 64, 72].
Preorden = [15, 9, 6, 14, 13, 20, 17, 64, 26, 72].
Postorden =[6, 13, 14, 9, 17, 26, 72, 64, 20, 15].

Recorridos en Visual Basic .Net

'funcin de recorrido en PREORDEN


Public Function preorden() As String
cadenasalida = ""
rePreorden(raz)
Return cadenasalida
End Function
Private Sub rePreorden(ByVal padre As Nodo)

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

Recorridos en C con funciones recursivas


struct Nodo{
char nombre[30];
struct Nodo *izq;
struct Nodo *der;
};
typedef struct Nodo Nodo;
typedef Nodo *Arbol;
void preOrden(Arbol abb){
if(abb)
{
printf("%s\n", abb->nombre);
preOrden(abb->izq);
preOrden(abb->der);
}
}
void postOrden(Arbol abb){
if(abb)
{
postOrden(abb->izq);
postOrden(abb->der);
printf("%s\n", abb->nombre);
}
}
void inOrden(Arbol abb){
if(abb)
{
inOrden(abb->izq);
printf("%s\n", abb->nombre);
inOrden(abb->der);
}
}

Tipos de rboles binarios de bsqueda[editar]


Hay varios tipos de rboles binarios de bsqueda. Los rboles AVL, rbol rojo-negro, son
rboles autobalanceables . Los rbol biselado son rboles tambin autobalanceables con la
propiedad de que los elementos accedidos recientemente se acceder ms rpido en
posteriores accesos. En el montculo como en todos los rboles binarios de bsqueda cada
nodo padre tiene un valor mayor que sus hijos y adems es completo, esto es cuando todos

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.

Buscando el rbol binario de bsqueda ptimo[editar]


Si nosotros no tenemos en mente planificar un rbol binario de bsqueda, y sabemos
exactamente como de frecuente sern visitados cada elemento podemos construir un rbol
binario de bsqueda ptimo con lo que conseguiremos que la media de gasto generado a la
hora de buscar un elemento sea minimizado.
Asumiendo que conocemos los elementos y en qu nivel est cada uno, tambin conocemos
la proporcin de futuras bsquedas que se harn para encontrar dicho elemento. Si es as,
podemos usar una solucin basada en la programacin dinmica.
En cambio, a veces slo tenemos la estimacin de los costes de bsqueda, como pasa con
los sistemas que nos muestra el tiempo que ha necesitado para realizar una bsqueda. Un
ejemplo, si tenemos un ABB de palabras usado en un corrector ortogrfico, deberamos
balancear el rbol basado en la frecuencia que tiene una palabra en el Corpus lingstico,
desplazando palabras como "de" cerca de la raz y palabras como "vesnico" cerca de las
hojas. Un rbol como tal podra ser comparado con los rboles Huffman que tratan de
encontrar elementos que son accedidos frecuentemente cerca de la raz para producir una
densa informacin; de todas maneras, los rboles Huffman slo puede guardar elementos que
contienen datos en las hojas y estos elementos no necesitan ser ordenados.

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.

Especificacin del rbol Binario


Crear
Arbol
Es vaco
Construir
Raz
Inicia el rbol como vaco
Crea un rbol con un elemento raz y dos ramas, izquierda y derecha que son, a su
vez, rboles
Comprueba si el rbol no tiene nodos
Devuelve el nodo raz
14. Especificacin del rbol Binario
Pertenece
Borrar
Derecho
Izquierdo
Obtiene la rama subrbol izquierdo de un rbol dado
Obtiene la rama subrbol Derecho de un rbol dado
Elimina del rbol el nodo con un elemento determinado
Determina si un elemento se encuentra en el rbol

Estructuras de datos dinmicas


rboles
< Estructuras de datos dinmicas

Contenido
[ocultar]

1 rboles

1.1 Definicin no recursiva

1.2 Definicin recursiva

1.3 Definiciones

1.4 Operaciones bsicas

1.5 Implementacin primer hijo - siguiente hermano

1.6 rboles binarios


1.6.1 rboles binarios de bsqueda

1.6.1.1 Operacin buscar

1.6.1.2 Operacin insertar

1.6.1.3 Operacin recorrer

1.6.1.4 Operacin borrado

1.6.2 rboles binarios perfectamente equilibrados

1.6.3 rboles equilibrados

1.6.3.1 Factor de equilibrio (FE) de un nodo

1.6.3.2 Inserciones en los mrgenes

1.6.3.3 Inserciones por dentro


1.6.4 rboles rojinegros

1.6.4.1 Altura de un ARN

1.6.4.1.1 Demostracin
1.6.4.2 Operaciones

1.6.4.3 Reparacin del balance del rbol

1.6.4.4 Insercin ascendente


1.6.4.4.1 Reparacin del balance

1.6.4.5 Insercin descendente

1.7 rboles B

1.7.1 Relacin entre los rboles B y los rboles rojinegros

1.7.2 Bsqueda

1.7.3 Insercin

1.7.4 Borrado
1.8 rboles B+

1.8.1 Bsqueda por clave

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:

Se distingue un nodo raz (no tiene padre).

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]

Los nodos que no tienen hijos se denominan hojas.

Un rbol con N nodos debe tener (N-1) aristas.

La profundidad de la raz es 0 y la de cualquier nodo es la de su padre ms 1.

La altura de un nodo es 1 ms que la mayor altura de un hijo suyo. La altura de un


rbol es la altura de la raz.

Los nodos que tienen el mismo padre son hermanos.

Si hay un camino del nodo u al nodo v, u es ascendiente de v y v es descendiente de


u. Si u

v son propios.

El tamao de un nodo es el nmero de descendientes (incluido l mismo). El tamao


de un rbol es el tamao de su raz.

Operaciones bsicas[editar]

Insertar

Buscar

Eliminar

Ir a la raz

Recorrer

Implementacin primer hijo - siguiente hermano[editar]


Consiste en mantener los hijos de cada nodo en una lista enlazada. Cada nodo tiene dos
referencias: una a su hijo ms a la izquierda y otra a su hermano de la derecha.

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.

rboles binarios de bsqueda[editar]


Para todo nodo A del rbol:

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

Dentro de la clase NodoBinarioVacio:

public NodoBinario insertar(Comparable o)


{
return new NodoBinario(o);
}

Operacin recorrer[editar]
Los recorridos pueden ser en preorden, postorden o inorden (orden simtrico). Todos son
O(N).

public void preOrder(SList aList)


{
aList.addElement(value);
left.preOrder(aList);
right.preOrder(aList);
}
public void inOrder(SList aList)
{
left.inOrder(aList);
aList.addElement(value);
right.inOrder(aList);
}
public void posOrder(SList aList)
{
left.posOrder(aList);
right.posOrder(aList);
aList.addElement(value);
}

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 primera consiste en conservar la estructura del subrbol, y colgar del elemento


ubicado en el extremo (el elemento menor o mayor) correspondiente al subrbol donde se
encuentra el elemento a promover hacia la raz (en este ejemplo, el subrbol izquierdo,
por lo cual se buscar el elemento ms a la izquierda), lo cual es consistente, porque
todos los elementos en el subrbol promovido sern mayores que los del subrbol del
cual estaban colgados a la derecha. El inconveniente que presenta esta solucin es que
debe utilizarse una funcin encontrarMnimo() o encontrarMximo().

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 binarios perfectamente equilibrados[editar]


La eficiencia de las operaciones depende exclusivamente de la altura del rbol. Para un rbol
de N nodos perfectamente equilibrado el coste de acceso es de orden logartmico: O(log N).
Sin embargo, se dice que si el rbol crece o decrece descontroladamente, el rendimiento
puede disminuir considerablemente, siendo para el caso ms desfavorable (insertar un
conjunto de claves ordenadas en forma ascendente o descendente) el coste de acceso: O(N).
En un rbol binario perfectamente equilibrado, el nmero de nodos en el subrbol izquierdo y
el nmero de nodos en el subrbol derecho, difieren como mucho en una unidad, y los
subrboles son tambin equilibrados

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).

Factor de equilibrio (FE) de un nodo[editar]


El FE es la altura del subrbol izquierdo menos la altura del subrbol derecho. Los valores que
puede tomar son -1, 0, 1. Si llegara a tomar los valores -2 o 2 debe reestructurarse el rbol.
Todos los rboles perfectamente equilibrados son AVL. La longitud de camino media es
prcticamente idntica a la de un rbol perfectamente equilibrado. En un AVL se puede
realizar con complejidad del O(log N) las siguientes operaciones:

Encontrar un nodo con una clave dada.

Insertar un nodo con una clave dada.

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:

Agregar el nodo como en un rbol binario de bsqueda.

En el regreso por el camino de bsqueda se comprueba el FE de los nodos.

Si un nodo presenta un FE incorrecto (2 o -2) se reestructura el rbol y se contina el


ascenso hasta llegar a la raz. Casos en situacin de reestructurar:
1. Una insercin en el subrbol izquierdo del hijo izquierdo de X.
2. Una insercin en el subrbol derecho del hijo izquierdo de X.
3. Una insercin en el subrbol izquierdo del hijo derecho de X.
4. Una insercin en el subrbol derecho del hijo derecho de X.

Inserciones en los mrgenes[editar]


1 y 4: inserciones en los mrgenes: rotacin simple: intercambia los papeles de los padres y
de los hijos, manteniendo la ordenacin.

// Rotacin izquierda - izquierda


private static NodoAVL rotarConHijoIzq(NodoAVL A)
{
NodoAVL B = (NodoAVL) A.getIzq(); //Asigna nombre
A.setIzq(B.getDer());

B.setDer(A);
return B;
}

Inserciones por dentro[editar]


2 y 3: inserciones por dentro: rotacin doble. Notar que una rotacin simple no resuelve el
problema, ya que la rama que provoc el desequilibrio se descuelga del nodo promovido y se
cuelga al nodo que desciende un nivel, de manera que se mantiene con la misma profundidad,
que es la que provoc el desequilibrio. Por lo tanto, antes de rotar, debe desplazarse el
desequilibrio a la rama correspondiente, es decir, transformamos el caso de una insercin por
dentro, a un caso de insercin en el margen, utilizando una rotacin.

// Rotacin izquierda - derecha


private static NodoAVL rotarDobleConHijoIzq(NodoAVL A)
{
NodoAVL B = (NodoAVL) A.getIzq(); //Asigna nombre
A.setIzq(rotarConHijoDer((NodoAVL) B));
return rotarConHijoIzq(A);
}

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:

Suprimir el nodo como en un rbol binario de bsqueda.

En el regreso por el camino de supresin se comprueba el FE de los nodos.

Si un nodo presenta un FE incorrecto (2 o -2) se reestructura el rbol y se contina el


ascenso hasta llegar a la raz. La reestructuracin se efecta cuando al regresar por el
camino de bsqueda despus de una insercin o una supresin se comprueba que la
condicin del FE se ha violado. Una supresin puede provocar varias reestructuraciones.
En la prctica se utilizan otros esquemas de equilibrio como los rboles rojinegros: como
en los AVL las operaciones son logartmicas en el peor caso. La ventaja es que las
inserciones y eliminaciones pueden realizarse con un nico recorrido descendente.

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]

Mientras que la altura de un rbol binario completo es, aproximadamente,


de un rbol M-ario completo es, ms o menos,
M-ario que verifica:

, la altura

. Un B-rbol de orden M es un rbol

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.

La pgina raz, o es una hoja o tiene entre 2 y M descendientes.

Las pginas hojas estn todas al mismo nivel.

Relacin entre los rboles B y los rboles rojinegros [editar]


Si juntamos un nodo negro con sus hijos rojos, si los hubiere, en un mismo nodo, se obtiene
un rbol no binario con altura igual a la altura negra, con un mximo de 3 elementos y 4 hijos,
y un mnimo de un elemento; en definitiva, es un rbol B de orden 4.

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:

para 1 i < n. La bsqueda contina en la pgina

. La bsqueda contina en la pgina

. La bsqueda contina en la pgina

.
. Si en algn caso la referencia es nula,

es decir, si no hay pgina descendiente, entonces no hay ningn elemento x en todo el


rbol y se acaba la bsqueda.

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:

Se inserta en forma secuencial la clave. Si la cantidad de elementos es 2n:

Los 2n+1 elementos se dividen en dos pginas, excluyendo la clave del medio.

La clave del medio se inserta en el nodo padre.

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.

Bsqueda por clave[editar]


Buscar en la raz el valor
ms pequeo mayor que la clave x. La bsqueda sigue por el
puntero
hasta que llegue a un nodo hoja, que ser donde est el puntero al bloque o
cubeta (cuando un elemento se encuentre en una pgina raz o interior la bsqueda
continuar por la rama derecha de dicha clave, hasta llegar a una hoja).

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

void main (void) { int op, num; cab=NULL;

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

} void insertar(int num) {

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

void Eliminar(int num) {

nodo *aux,*aux2, *prev;


int c=0;
aux=cab;
while(c!=1)
{
if(aux->valor==num)
{
c=1;
}
else{
prev=aux;
aux=aux->sig;
}
}

if(c==1)
{
if(prev->sig==NULL)
{
cab=cab->sig;
delete aux;
}
else
{
aux2 = aux->sig;
prev->sig = aux2;
delete aux;
}
}

void insertord(int num) {

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

void main (void) { int op, num; cab=NULL;

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

} void insertar(int num) {

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

void Eliminar(int num) {

nodo *aux,*aux2, *prev;


int c=0;
aux=cab;
while(c!=1)
{
if(aux->valor==num)
{
c=1;
}
else{
prev=aux;
aux=aux->sig;
}
}
if(c==1)
{
if(prev->sig==NULL)
{
cab=cab->sig;
delete aux;
}
else

{
aux2 = aux->sig;
prev->sig = aux2;
delete aux;
}
}

void insertord(int num) {

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

Вам также может понравиться