Sunteți pe pagina 1din 7

Arbol

de Busqueda y Balanceado
Joseph L. Kahn Casapa
Facultad de Ciencias, Universidad Nacional de Ingeniera, Lima, Per
u
Escuela Profesional de Matem
atica
juiskahn@gmail.com

20 de diciembre de 2014

Resumen

El presente texto realiza un estudio de las propiedades de arboles binarios, en especifico de b


usqueda y
balanceado, adem
as de como mantener la estructura de datos al agregar o borrar elementos. Se implementa
en python 2.7 utilizando un arreglo simple, ademas implementar el grafico de un arbol binario.

Palabras clave: Arbol


binario, Arbol
de b
usqueda, Arbol
Balanceado, Grafica.

1.

Introducci
on

2.

Arbol
binario

Se define un arbol binario(Figura 1) como un conjunto


finito de elementos que bien esta vaco o esta formado
por una raz con dos arboles binarios disjuntos, es decir,
dos descendientes directo llamados subarbol izquierdo
y subarbol derecho, tambien se define con la teora de
grafos como un grafo conexo, acclico y no dirigido tal
que el grado de cada vertice no es mayor a 2.

La estructura de datos llamada


arboles binario
tienen una especial importancia en la utilizacion de
informaci
on, las aplicaciones de los arboles binarios
son muy variadas ya que se les puede utilizar para
representar una estructura en la cual es posible tomar
decisiones con dos opciones o m
as en distintos puntos.
Se introducir
a las nociones b
asicas de que es un
arbol, en particular un
arbol binario a la cual agregando condiciones podremos definir un
arbol de b
usqueda
el cual nos permite encontrar datos almacenados en la
estructura r
apidamente, por la misma organizaci
on que
tendr
an los datos. Posteriormente definiremos un arbol
balanceado a partir de un
arbol de b
usqueda el cual
nos permite tener los hijos a una misma altura, es decir
se maximiza los nodos interiores haciendo decrecer
la altura del
arbol lo que reduce las operaciones de
b
usqueda, lo cual lograremos utilizando las rotaciones
de un
arbol.

Figura 1: Arbol
Binario
Se define los siguientes terminos para el manejo de
arboles binarios, utilizaremos A y B dos elementos del
arbol:
Hijo: A es hijo de B, si y solo si el nodo A es descendiente directo de B.

Las implementaciones se realizaran en python un lenguaje muy sencillo y legible para cualquier usuario, utilizando la versi
on estable 2.7. Se utilizara la noci
on basica
de arreglos como almacenamiento de la informacion en
memoria est
atica, haciendo la observaci
on que las implementaciones tambien se pueden realizar en memoria
din
amica, donde la posici
on en el arreglo le determina
un lugar especifico en el
arbol.

Padre: A es padre de B, si y solo si el nodo A es


antecesor de B.
Hermano: Dos nodos seran hermanos si son descendientes directos de un mismo nodo.
Raiz: Es aquel nodo que no tiene antecesor.
1

Hoja: Son aquellos que no tienen hijos.

Como mantenemos la estructura de


arbol de
b
usqueda al agregar un elemento?

Nodo interior: Es un nodo que no es raz ni hoja.

Si queremos agregar un nuevo elemento en el


arbol
y que siga manteniendo la estructura de
arbol de
b
usqueda, no podemos agregarlo en cualquier posici
on
disponible por lo ya mencionado.

Nivel: Es el n
umero de arcos que deben ser recorridos para llegar a un determinado nodo.
Altura: Es el m
aximo n
umero de niveles de todos
los nodos del
arbol.

2.1.

Para solucionar esta peque


na dificultad debemos
verificar que la posicion a la que se agregara es correcta,
la cual se lograra haciendo un camino en el
arbol, es
decir, comparamos si el nuevo elemento es mayor o
menor que la raz, si es menor comparamos con el hijo
al lado izquierdo, de lo contrario si es mayor con el hijo
del lado derecho. Realizamos el mismo procedimiento
en el subarbol correspondiente hasta llegar a una hoja
en donde se agregara el nuevo elemento como hijo a izquierda o derecha dependiendo de si sea mayor o menor.

Propiedades

1. Si conocemos n el numero de nodos, la altura h del


arbol completo es

h = log2 (n + 1) 1
.
2. Si conocemos h la altura del
arbol, entonces la cantidad de nodos N m
axima es
N = 2h+1 1

Implementaci
on

2.2.

Realizaremos la implementacion en un array, donde


podremos manipular los elementos conociendo los indices la posicion en que se encuentren. Debemos implementar como inicializar un arbol como un array(crear),
el padre para cada elemento en el arbol(padre),
los hijos a izquierda o derecha(izq y der), altura del arbol(altura), cantidad de elementos en el
arbol(elemen) y verificar si el arbol esta vaco(vacio).
Ademas implementaremos las funciones de agregar un
elemento(agregar), y mantener la estructura de
arbol
binario de b
usqueda. La funcion mas importante de
b
usqueda de un elemento en el arbol(busqueda), que
por la estructura del arbol el tiempo es de orden n.

Arbol
de B
usqueda

Un
arbol binario de b
usqueda(figura 2) es un tipo
particular de
arbol binario muy importante ya que
buscar alg
un dato dentro del
arbol se realiza en un
tiempo menor. Se define de la siguiente manera:
Un
arbol binario no vaco, de raz A, es un arbol
binario de b
usqueda si cumple los siguientes enunciados:
En caso de tener sub
arbol izquierdo, la raz A debe
ser mayor que el valor m
aximo almacenado en el
sub
arbol izquierdo, y que el sub
arbol izquierdo sea
un
arbol binario de b
usqueda.

Crea un arbol binario vaco, pidiendo al usuario que


ingrese una cantidad inicial de espacio donde almacenar los dato.

En caso de tener sub


arbol derecho, la raz A debe
ser menor que el valor mnimo almacenado en el
sub
arbol derecho, y que el sub
arbol derecho sea un
arbol binario de b

usqueda.

1
2

3
4
5

def crear():
print Cuanto espacio desea que tenga
inicialmente la cola
maxi = int(raw_input(?:))
arbol = []*maxi
return arbol

La posicion del padre de un nodo que no sea raz,


sera el maximo entero de la mitad de la posici
on
en que se encuentra.
1

Figura 2: Arbol
binario de b
usqueda

2
3

Si agregamos cualquier elemento, de mayor valor que


la raz, en alg
un lugar del sub
arbol izquierdo se pierde
la estructura de
arbol de b
usqueda.

4
5

def padre(arbol,i):
if arbol[i] != :
return i/2
else:
#EL ELEMENTO EN LA POSICION i, NO
EXISTE
return False

La posici
on del hijo a izquierda de un nodo, sera
el doble de la posici
on, aumentado en 1.
1
2
3
4
5
6

7
8
9

10

Verifica si un arbol esta vaco, si no hay raz entonces no hay datos.

def izq(arbol,i):
if 2*i+1 < len(arbol):
if arbol[2*i+1] != :
return 2*i+1
else:
#EL ELEMENTO EN LA POSICION i, NO
TIENE HIJO A IZQUIERDA
return False
else:
#EL ELEMENTO EN LA POSICION i, NO
TIENE HIJO A IZQUIERDA
return False

1
2
3
4
5

Agrega x al arbol, analizando el caso si x es de


mayor o menor que la raz, sucesivamente en los
subarboles dependiendo en el caso en que se encuentre y si no hay espacio en el array para agregar
el elemento se adiciona el espacio necesario para
guardar correctamente el elemento.

La posici
on del hijo a derecha de un nodo, sera el
doble de la posici
on aumentado en 1.

1
2

1
2
3
4
5
6

7
8
9

10

def der(arbol,i):
if 2*(i+1) < len(arbol):
if arbol[2*(i+1)] != :
return 2*(i+1)
else:
#EL ELEMENTO EN LA POSICION i, NO
TIENE HIJO A DERECHA
return False
else:
#EL ELEMENTO EN LA POSICION i, NO
TIENE HIJO A DERECHA
return False

4
5
6
7
8
9
10
11
12
13
14
15
16
17

La altura de un
arbol, considerando el dato en la
mayor posici
on en el array con el cual calculamos
la altura mediante h = log2 (n) + 1.

18
19
20
21

1
2
3
4
5
6
7

def altura(arbol):
for i in range(len(arbol)-1,0,-1):
if arbol[i] != :
n = i
break
alt = int(m.log(n,2))+1
return alt

22
23
24
25
26

2
3
4
5
6
7

def agregar(arbol,x):
if elemen(arbol) == 0:
arbol[0] = x
else:
i = 0
bolean = True
while bolean:
if x <= arbol[i]:
if izq(arbol,i) == False:
if 2*i+1 >= len(arbol):
m = 2*(i+1)-len(arbol)
arbol += []*m
arbol[2*i+1] = x
bolean = False
else:
i = izq(arbol,i)
elif x > arbol[i]:
if der(arbol,i) == False:
if 2*(i+1) >= len(arbol):
m = 2*i+3-len(arbol)
arbol += []*m
arbol[2*(i+1)] = x
bolean = False
else:
i = der(arbol,i)
return arbol

B
usqueda del elemento bus en el arbol, analiza si
la raz es igual a bus si no son iguales entonces al
igual que el programa anterior se puede analizar si
es mayor o menor que la raz y asi poder seguir su
b
usqueda solo en un subarbol.

Cantidad de elementos en el
arbol, realiza un recorrido en el
arbol para verificar cuantos datos contiene el
arbol.
1

def vacio(arbol):
bolean = True
if arbol[0] != :
bolean = False
return bolean

def elemen(arbol):
n =len(arbol)
cant = 0
for i in range(n):
if arbol[i] != :
cant += 1
return cant

1
2
3
4
5
6
7

def busqueda(arbol,bus):
i = 0
bolean = True
while bolean:
if bus == arbol[i]:
bolean = False
print El elemento %d se encuentra
en la posicion %d %(bus,i)

un nivel al arbol. La estructura es posible que no se


pierda al agregar un elemento. Un ejemplo es en el
arbol de la figura 3, al agregar un elemento al nodo 34
no se pierde la estructura de arbol balanceado pero si
agregamos un elemento en el nodo 30 o 24 el
arbol ya
no sera balanceado.

else:
if bus < arbol[i]:
if izq(arbol,i) == False:
bolean = False
print El elemento %d no se
cuentra en el arbol %bus
else:
i = izq(arbol,i)
if bus > arbol[i]:
if der(arbol,i) == False:
bolean = False
print El elemento %d no se
cuentra en el arbol %bus
else:
i = der(arbol,i)

8
9
10
11
12

13
14
15
16
17
18

19
20

2.3.

Como mantenemos la estructura del


arbol
balanceado al agregar un elemento?
Por lo ya mencionado es posible que al agregar el
nuevo elemento, el arbol ya no sea balanceado.
Analizaremos cuando agregamos el nodo en el
subarbol izquierdo como en la figura 4 en donde A es
la raz, B el hijo a izquierda de A, T 1 el sub
arbol a
izquierda de B, T 2 el subarbol a derecha de B y T 3
el subarbol a derecha de A. Notemos ademas que los
arboles T 1, T 2 y T 3 tienen altura n natural.

Arbol
Balanceado

Un
arbol balanceado(figura 3), al igual que el arbol
binario de b
usqueda, es un tipo particular de arbol
binario que se define de la siguiente manera:
Un
arbol binario T no vaco con Ti y Td sus
sub
arboles izquierdo y derecho respectivamente, es un
arbol balanceado si cumple los siguientes enunciados:

Ti es un
arbol balanceado
Td es un
arbol balanceado

Figura 4: Arbol
balanceado

La altura de Ti , H(Ti ), y la altura de Td , H(Td ),


cumplen
|H(Td ) H(Ti )| 6 1

El valor asignado al nodo A es 1, si agregamos un


nodo C en el subarbol derecho el balance se mantendra,
pero si el nodo C se agrega al subarbol T 1 o T 2 se
perdera el balanceo ya que se agregara un nivel m
as y
el valor asignado al nodo A sera 2(figura A y B)

Figura 3: Arbol
binario balanceado
Figura A: Caso 1
Se utiliza una notaci
on muy sencilla para verificar
que es un
arbol binario balanceado, para cada nodo
se le asigna el valor h igual a la altura del subarbol
derecho menos la altura del sub
arbol izquierdo, si
para cualquier nodo su valor asignado h es 1, 0 o 1,
entonces podemos afirmar que es un
arbol balanceado.
En principio todo arbol balanceado puede ordenar sus
elementos de cualquier manera, pero en este texto se
considera que todo
arbol balanceado tambien es de
b
usqueda.

Figura B: Caso 2

Solucionaremos el desbalance mediante rotaciones a


izquierda, derecha o combinaciones de ambas dependiendo del caso.
Caso 1
Realizamos una rotacion a derecha reordenando los
nodos y subarboles de la siguiente manera:
1. El nodo B es la raz desplazando al nodo A
como su hijo a derecha.

Si agregamos cualquier elemento en el sub


arbol con
mayor altura desde la raz, puede que aumentemos en

2. El subarbol T 1 se mantiene como parte del


hijo a izquierda del nodo B.
4

3. El sub
arbol T 2 pasa a ser parte del hijo a izquierda del nodo A.
obteniendo despues de la rotaci
on la figura 5

Figura 8: Rotacion a derecha

Implementaci
on
Figura 5: Rotaci
on a derecha

Realizaremos las implementaciones de las rotaciones


a derecha e izquierda.

Caso 2
Al intentar solo la rotaci
on a derecha como en el
caso 1, el
arbol sigue desbalanceado solo que ahora
el valor asignado es 2. As que realizaremos una
rotaci
on a izquierda en el sub
arbol a izquierda del
nodo A de la siguiente manera

Establece el balanceo que se debe realizar en los


cuatro posibles casos, y realiza la rotacion respectiva utilizando las funciones ya establecidas de rotacion.
1

1. Consideramos al
arbol como en la figura 6

2
3
4
5
6

8
9

Figura 6: Doble rotaci


on

10

11

2. Aplicamos una rotaci


on a izquierda en el
sub
arbol a izquierda del nodo A, es decir, desde el sub
arbol que tiene como raz al nodo B,
obteniendo la figura 7

12

13

def balanceo(arbol):
index = indices(arbol)
vali = validar(index)
if vali[0]:
#caso mover izquierda
if deraltu(arbol,vali[1]) izqaltu(arbol,vali[1])>0:
sarbol,arbol =
subarbol(arbol,vali[1],True)
#mover derecha de ser necesario
if deraltu(sarbol,0) izqaltu(sarbol,0)<0:
auxarbol,sarbol =
subarbol(sarbol,2,True)
auxarbol = rotader(auxarbol)
sarbol =
agregarsub(sarbol,auxarbol)
sarbol = rotaizq(sarbol)

14
15
16
17

18
19

20

21
22

Figura 7: Rotaci
on a izquierda

23

3. Aplicamos una rotaci


on a derecha sobre el nodo A, obteniendo la figura 8

24
25
26

Analogamente hacemos el an
alisis cuando agregamos
el elemento en el sub
arbol a derecha del nodo A, con
lo cual cubrimos todos los posibles casos en los que el
arbol se puede desbalancear.

27

#caso mover derecha


else:
sarbol,arbol =
subarbol(arbol,vali[1],True)
#mover a izquerda de ser necesario
if deraltu(sarbol,0) izqaltu(sarbol,0)>0:
auxarbol,sarbol =
subarbol(sarbol,1,True)
auxarbol = rotaizq(auxarbol)
sarbol =
agregarsub(sarbol,auxarbol)
sarbol = rotader(sarbol)
arbol = agregarsub(arbol,sarbol)
else:
print El arbol esta balanceado
return arbol

Realiza la rotacion a izquierda del arbol sub.

1
2
3
4
5
6
7
8
9
10
11
12

3.

def rotaizq(sub):
T1,sub = subarbol(sub,1,True)
aux,sub = subarbol(sub,2,True)
T2,aux = subarbol(aux,1,True)
T3,aux = subarbol(aux,2,True)
rotasub = []*10
rotasub = agregar(rotasub,aux[0])
rotasub = agregar(rotasub,sub[0])
rotasub = agregarsub(rotasub,T1)
rotasub = agregarsub(rotasub,T2)
rotasub = agregarsub(rotasub,T3)
return rotasub

El fin de graficar un arbol binario, es la comodidad


para el usuario de conocer como esta almacenando los
datos, mediante la facilidad de manipular los datos del
arbol binario al conocer su posicion mirando el gr
afico.
Las figuras 1, 2 y 3 son ejemplos de graficos que nos
ayudan a deslumbrar la idea de como es la estructura
de datos utilizada.
Si P es un arbol binario cualquiera, consideramos a T
como el menor arbol completo que contiene al
arbol P .
Obteniendo la correspondencia de la impresion de cada
nivel del arbol con el espaciado que se le debe dar entre
nodos de un nivel, para un arbol completo, tendremos
la impresion para el arbol P .

Realiza la rotaci
on a derecha del
arbol sub.
1
2
3
4
5
6
7
8
9
10
11
12

Gr
afica de un
arbol

def rotader(sub):
T1,sub = subarbol(sub,2,True)
aux,sub = subarbol(sub,1,True)
T2,aux = subarbol(aux,2,True)
T3,aux = subarbol(aux,1,True)
rotasub = []*10
rotasub = agregar(rotasub,aux[0])
rotasub = agregar(rotasub,sub[0])
rotasub = agregarsub(rotasub,T1)
rotasub = agregarsub(rotasub,T2)
rotasub = agregarsub(rotasub,T3)
return rotasub

Figura 9: Analisis
de grafica
Por la propiedad de un arbol completo con altura h
podemos calcular el ancho del arbol, que sera el n
umero
de elementos que tiene el arbol(figura 9). La correspondencia de los elementos con la posicion en el ancho es
de la siguiente manera:

Las siguientes funciones comentare su procedimiento, se


deja al lector:
1. subaltura(arbol,i):
La altura de un sub
arbol, donde su raz se encuentra
en la posici
on i.

1. El primer nivel tenemos que la raz tendra que ir


en el centro lo que equivale a

2. izqaltu(arbol,i)::
La altura a izquierda de un sub
arbol, donde su raz
se encuentra en la posici
on i.

i0 =

3. deraltu(arbol,i):
La altura a derecha de un sub
arbol, donde su raz
se encuentra en la posici
on i.

2h 1
.
2

2. Los los nodos en el nivel n tendra que ir espaciados


por el siguiente valor

4. agregarsub(arbol,subarbol):
Agrega un sub
arbol al
arbol, utilizando la funcion
agregar cada elemento del sub
arbol, as se mantiene la estructura.

in =

in1 1
2

excepto en los indices en los que ya se ha impreso


alg
un nodo.

5. indices(arbol):
Asigna a cada nodo el valor de la diferencia entre
su altura a derecha menos la altura a izquierda.

Veamos el ejemplo de la figura 9, el arbol tiene altura


igual a 4 por ende la posicion de la raz va en

6. validar(arbol):
Valida si es necesario el balanceo.

i0 =

7. subarbol(arbol,i,elim):
En el
arbol determina un sub
arbol tal que su raz
se encuentra en la posici
on i, y si elim es True se
elimina los datos del
arbol.

24 1
= 7.
2

Para el nivel 1 tenemos que estaran espaciados por


i1 =
6

71
=3
2

que son 3 y 11, pero 7 no esta considerado ya que se ha


impreso la raz, as sucesivamente para los dem
as niveles.

Implementaci
on
La funci
on grafica determina la altura del
arbol, el
ancho del
arbol y en cada nivel imprime el espaciado
con la correspondencia entre cada nodo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

def graficar(arbol):
n = altura(arbol)
anc = (2**n)-1
index = []
num = 0
print \n*******GRAFICA*******
for i in range(n):
print %.2d %(i+1),
cant = 2**i
espa = (anc-2*cant+1)/(2*cant)
auxindex = []
for k in range(espa,anc,espa+1):
auxindex.append(k)
for j in range(anc):
if j not in index and j in auxindex:
if num < len(arbol):
if arbol[num] != :
print %.2d %arbol[num],
else:
print --,
else:
print --,
num += 1
else:
print --,
index = index + auxindex
print
print

Figura 10: Ejemplo de problemas

Figura 11: Ejemplo de problemas

5.
4.

Posibles problemas

Soluciones

Podemos solucionar el problemas considerando los casos en donde se debe rotar elementos iguales, ya que la
funcion agregar siempre mandara el elemento igual hacia el subarbol izquierdo. Si consideramos dos casos: si
es rotacion a derecha tenemos que mandar el elemento
igual hacia el subarbol a derecha, pero si es rotaci
on a
izquierda mandar el elemento igual hacia el sub
arbol a
izquierda.
Para solucionar el problema del grafico es mucho mas
complejo su solucion ya que tendremos que analizar con
mas detenimiento las variables la cantidad de nodos n
su altura y el ancho del arbol.

El problema que se detecto, al hacer un testeo de los


programas, es que al ingresar elementos repetidos las
funciones de b
usqueda funcionan correctamente pero en
las de balanceo existen problemas al momento de realizar la rotaci
on(o izquierda o derecha). Como en el siguiente ejemplo: 10, 15, 3, 2, 3
El problema en la gr
afica de un
arbol es la altura que
puede tener un
arbol(pero sin balancearlo), ya que si es
muy grande tratara de imprimir el caso en que todos los
nodos est
an disponibles y puede que la resoluci
on de la
pantalla no pueda mostrar correctamente todo el grafico.
Un ejemplo es que cada nodo tenga un solo hijo y con
altura 10, la funci
on tratara de imprimir el mayor arbol
sin que la mayor cantidad de nodos tenga informacion.
ahora veamos un ejemplo concreto: 20, 19, 18, 17, 16,
15 ....

Referencias
[1] thomas h. cormen y charles e. leiserson, Introduction to Algorithms, tercera edicion, 2009.
7

S-ar putea să vă placă și