You are on page 1of 76

rbol B

rbol B de orden m
Acotacin de altura
Insercin con Particin-1/2
Anlisis de la insercin con Particin-1/2
Insercin con rotaciones
Nmero mximo de accesos por insercin con rotaciones
Insercin con Particin-2/3
Nmero mximo de accesos por insercin con Particin-2/3
Extraccin con rotaciones
Extraccin con recombinaciones
Implementacin en Java de un contenedor con un rbol B
rbol B
rbol B de orden m
Inicio
rbol B de orden m
Multirrama compacto de grado m
Perfectamente equilibrado en altura
Crece hacia arriba

Objetivo:
Realizar inserciones, extracciones y bsquedas
con el menor nmero de accesos a disco
Definicin de rbol B de orden m

Cada nodo tiene, como mucho, m hijos


Cada nodo, excepto la raz, tiene, al menos m/2 hijos
La raz tiene al menos 2 hijos, si no es hoja
Todos los nodos hojas todos sus enlaces nulos se
ubican en el mismo nivel

Por ejemplo, en un rbol B de orden 7:


Cada nodo tiene entre
7 2 y 7 h ijo s
Puede tener 3, 4, 5 6 valores de clave
El nodo raz puede contener de 1 a 6 valores de
clave
Ejemplo: rbol B de
orden 5
l

d g o s w

a b c e f h i j k m n p q r t u v x y z

Los rboles B de orden 2 no son posibles:


Se considerar solamente el caso de m3
Los rboles 2-3-4 son rboles B de orden 4
Contexto del rbol B
rboles multirrama de orden m

Auto-ajustables
B
i Biselados
n
a Equilibrados
ri
o
s AVL
B
Rojo-Negro
2-3-4
rbol B o multirrama
ptimo?
20 40 30

20 40
10 15 25 30 45 50

10 15 25 35 45 50

35

El nmero de nodos de un rbol B puede ser mayor que el mejor rbol de


bsqueda multirrama posible para ese orden
Las propiedades del rbol B son ms fciles de mantener que las del ptimo
frente a inserciones y extracciones
rbol B
Insercin con Particin-1/2
Inicio
Insercin con Particin-
1/2
Se inserta en el nodo hoja apropiado el par
(dato,Nulo)
Si tras la insercin el nodo contiene:
m valores de clave, finaliza el proceso
menos de

m valores de clave se dice que se ha


sobrecargado y es necesario dividirlo en dos
Ejemplo de insercin
(m=5)
47 47 49 47 49

30 30 47 49 60 30 47 49 60

nodo
10 10 30 47 49 60 sobrecargad
o
Particin-1/2
El nodo sobrecargado, Nodo, se divide en dos nodos:
Nodo y Nuevo
Se distribuyen las claves de forma equitativa entre ambos
El par (clave central, direccin del nuevo nodo)
Se inserta en el nodo padre de Nodo
Puede dar lugar a una nueva Particin-1/2

Padre

Nodo Nuevo

nodo
sobrecargado
Particin-1/2
Si es necesario dividir el nodo raz
Se crea una nueva raz que contendr
nicamente el valor de clave central y dos
direcciones la de la antigua raz y la del
nuevo nodo.
El rbol aumenta de altura un nivel

Raz
Nodo Nuevo

raz
sobrecargada
Particin-1/2
Si Nodo contiene m valores de clave est sobrecargado
Nodo [m, Enlace0, Clave1, Enlace1,..., Clavem,Enlacem]
Clavei<Clavei+1 1<=i<m
Se va a dividir en dos nodos:

Nodo [ m/2 -1, Enlace0, Clave1, Enlace1,..., Clave m/2 -1, Enlace m/2 -1]
Nuevo [m- m/2 ,Enlace m/2 ,Clave m/2 +1,Enlace m/2 +1,...,Clavem, Enlacem]

El par (Clave m/2 ,DirNuevo) se inserta en el padre de Nodo

En el peor caso se propaga hasta la raz


Ejemplo de insercin con Particin-
1/2 (m=5)
10 nodo
divisin de la raz 10 30 47 49 60 sobrecargad
o

47

10 30 49 60
Particin-
1/2

35, 55, 50, 15 47

10 15 30 35 49 50 55 60
Ejemplo de insercin con Particin-
1/2 (m=5)
nodo
58 47
sobrecargad
o
10 15 30 35 49 50 55 58 60

47 55 Particin-
1/2
10 15 30 35 49 50 58 60
Ejemplo de insercin con Particin-
1/2 (m=5)nodo
37
sobrecarg 47 55
ado
10 15 30 35 37 49 50 58 60

Particin- 30 47 55
1/2
10 15 35 37 49 50 58 60
Ejemplo de insercin con Particin-
1/2 (m=5)
nodo
68, 40, 65, 36, 66

30 47 55
sobrecarg
ado
10 15 35 36 37 40 49 50 58 60 65 66 68

30 47 55 65 Particin-
1/2
10 15 35 36 37 40 49 50 58 60 66 68
Ejemplo de insercin con Particin-
1/2 (m=5)
nodo
43
sobrecarg 30 47 55 65
ado
10 15 35 36 37 40 43 49 50 58 60 66 68

nodo
divisin de la raz 30 37 47 55 65
sobrecargado

10 15 35 36 40 43 49 50 58 60 66 68

Particin-
1/2
Ejemplo de insercin con Particin-
1/2 (m=5)
nodo
divisin de la raz 30 37 47 55 65
sobrecargado

10 15 35 36 40 43 49 50 58 60 66 68

47

Particin-
30 37 55 65
1/2

10 15 35 36 40 43 49 50 58 60 66 68
rbol B
Insercin con rotaciones
Inicio
Insercin con rotaciones
Mejora el algoritmo de insercin
Objetivo: reducir la frecuencia de particin de los
nodos usando una rotacin local

Padre es el nodo padre de dos nodos consecutivos del


siguiente nivel, Izq y Der

Antes de aplicar Padre


una Particin-1/2 Tiene menos
Izq Der de m-1 valores
de clave?
nodo
sobrecargado
Insercin con rotaciones
Si el nodo sobrecargado es Izq contiene m valores de clave
y m+1 enlaces
puede rotar con su hermano inmediato derecho, Der?
Es posible si el nmero de claves de Der es menor que
m-1
No es posible si:
El nodo Izq no tiene hermano inmediato derecho

El hermano inmediato derecho est completo

Si no es posible realizar una rotacin hacia la derecha o de


izquierda a derecha
Se procede, si es posible, a realizar una rotacin hacia la
izquierda de derecha a izquierda
Rotacin hacia la derecha
En Izq se dejan (m+NC)/2 valores de clave (NC=n
claves Der)
En Padre se reemplaza la clave intermedia entre los
enlaces que referencian a Izq y Der, CI, por la
Clave (m+NC)/2 +1 de Izq
En Der se ponen (m+NC)/2 valores de clave, includa
Padre
CI, y los correspondientes enlaces

Izq Der

nodo
sobrecargado
El nodo sobrecargado fluye hacia su hermano inmediato
derecho
Rotacin hacia la
izquierda
En Der se dejan (m+NC)/2 valores de clave (NC=n
claves Izq)
En Padre se reemplaza la clave intermedia entre los
enlaces que referencian a Izq y Der, CI, por la Clavem-
(m+NC)/2 de Der

En Izq se ponen (m+NC)/2 valores de clave, includa CI,


y los correspondientes
Padre enlaces

Izq Der

nodo
El nodo sobrecargado fluyesobrecargado
hacia su hermano inmediato
izquierdo
Ejemplo de insercin con rotaciones
(m=5)
nodo
43
sobrecarg 30 47
40 55 65
ado
10 15 35353636373740 43 49 49
43 47 50 50 58 60 66 68

Rotacin hacia la derecha


Ejemplo de insercin con rotaciones
(m=5)
nodo
31,38
sobrecarg 30 40 55 65
35
ado
10 15
10 15 30 31 31363537363837 38 43 47 49 50 58 60 66 68

hermano derecho lleno


Rotacin hacia la
izquierda
Ejemplo de insercin con rotaciones
(m=5) nodo
70,75,80
35 40 55 65
68 sobrecarg
ado
10 15 30 31 36 37 38 43 47 49 50 58 65
58 60 60 66 66706875708075 80

Rotacin hacia la no tiene hermano derecho


izquierda
rbol B
Insercin con Particin-2/3
Inicio
Insercin con particin-
2/3
Se parten dos nodos en tres, cada uno contiene
(2*m-2)/3 (2*m-1)/3 2*m/3 valores de clave
Si no tiene hermano izquierdo y el derecho est
lleno se aplica Particin-2/3 con el hermano
derecho
Si el hermano izquierdo y el derecho estn
llenos se aplica Particin-2/3 con el hermano
izquierdo
Si es necesario dividir el nodo raz se aplica
Particin-1/2
En el peor caso se propaga hasta la raz
Diferencias entre la Particin-2/3
y la 1/2
Ambas particiones producen un nuevo nodo
La Particin-2/3 no evita la propagacin al
nivel superior
Inserta dos valores de clave en el Padre y pasa uno
del Padre a Nuevo
La Particin-2/3 difiere de la Particin-1/2
Deja sus valores de clave mejor distribuidos entre
los tres nodos
Redunda beneficiosamente en posteriores
inserciones
Particin-2/3
con el hermano inmediato derecho

Padre

Izq Der

nodo Nuevonodo lleno


sobrecargado
Particin-2/3
con el hermano inmediato izquierdo

Padre

Izq Der

Nuevo nodo
nodo lleno
sobrecargado
Ejemplo de insercin con Particin-2/3 (m=7)
03
no tiene hermano
izquierdo 09 20 35 58 71

01 02 03 04 05 06 08 73 74 77 79

10 11 13 14 16 19 59 60 63 64 66 68
nodo
sobrecargado 21 23 25 28 43 45 46 47 48 49

hermano derecho lleno

05 11 20 35 58 71
Particin-2/3
01 02 03 04 73 74 77 79

Nuev 06 08 09 10 59 60 63 64 66 68
o
13 14 16 19 43 45 46 47 48 49

21 23 25 28
La diferencia entre aplicar una Particin-2/3 en vez de la Particin-
1/2 est en que los valores de clave estn mejor distribuidos entre los tres
nodos
05 11 20 35 58 71
Particin-2/3
01 02 03 04 73 74 77 79

06 08 09 10 59 60 63 64 66 68

13 14 16 19 43 45 46 47 48 49

21 23 25 28

Particin-1/2 04 09 20 35 58 71

01 02 03 73 74 77 79

05 06 08 59 60 63 64 66 68

10 11 13 14 16 19 43 45 46 47 48 49

21 23 25 28
Ejemplo de insercin con Particin-
2/3 (m=7)
53 09 20 35 50 58 71

01 02 04 05 06 08 73 74 77 79

10 11 13 14 16 19 59 60 63 64 66 68

21 23 25 28 51 52 53 54 55 56 57

43 45 46 47 48 49 nodo sobrecargado
hermano derecho lleno
hermano izquierdo lleno nodo
Particin-2/3 09 20 35 48 53 58 71 sobrecargad
o
01 02 04 05 06 08 73 74 77 79

10 11 13 14 16 19 59 60 63 64 66 68

21 23 25 28 54 55 56 57

43 45 46 47 49 50 51 52 Nuev
o
Ejemplo de insercin con Particin-
2/3 (m=7) nodo
divisin de la raz 09 20 35 48 53 58 71 sobrecargad
o
01 02 04 05 06 08 73 74 77 79

10 11 13 14 16 19 59 60 63 64 66 68

21 23 25 28 54 55 56 57

43 45 46 47 49 50 51 52

48

Particin-
09 20 35 53 58 71
1/2
01 02 04 05 06 08 73 74 77 79

10 11 13 14 16 19 59 60 63 64 66 68

21 23 25 28 54 55 56 57

43 45 46 47 49 50 51 52
Resumen de la insercin
Tras la bsqueda, el nodo se inserta en una hoja.Nmero de accesos
igual a la altura del
rbol.
Si no se sobrecarga se escribe y termina.
Un
acceso.
Si se sobrecarga y no es la raz: Un acceso si tiene
hermano. Tres accesos ms
Si tiene hermano izquierdo se intenta Rotacin hacia la izquierda.
si la hace. FIN

Si tiene hermano derecho se intenta Rotacin hacia la derecha.


Si no se ha podido realizar una Rotacin: Un acceso si tiene
hermano. Tres accesos ms
Si no tiene hermano izquierdo Particin-2/3 con el derecho. si la hace. FIN
Tres
Si tiene hermano izquierdo Particin-2/3 con el izquierdo. accesos.
Tres
Si tras la particin el padre no se sobrecarga se escribe y termina.
accesos.
Un
Si el padre resulta sobrecargado, segn sea o no raz, se continaacceso. con la
resolucin de la situacin de sobrecarga hacia arriba.
Si el nodo sobrecargado es la raz:
Se realiza una Particin-1/2 y se escribe la nueva raz.
Tres accesos: dos de la
particin y uno para
actualizar la raz.
rbol B
Extraccin con rotaciones
Inicio
Extraccin
Distinguir la extraccin de un valor de clave situado
en
1. un nodo hoja
2. un nodo no hoja
Se busca el sucesor, se sustituye por l y se reduce al caso 1
Un nodo est bajo mnimo si tiene menos de m/2 -1
valores de clave
Si despus de la extraccin un nodo est bajo mnimo
.Si su hermano inmediato derecho tiene ms de m/2 -1
valores de clave se realiza una rotacin hacia la izquierda
.Si no tiene hermano inmediato derecho o est al mnimo se
intenta una rotacin hacia la derecha con el hermano
inmediato izquierdo
.Si no es posible la rotacin se aplica una recombinacin
Rotacin hacia la
izquierda
En Der se dejan (NC+ m/2 -2 )/2 valores de clave (NC=n claves
Der)
En Padre se reemplaza la clave intermedia entre los enlaces que
referencian a Izq y Der, CI, por la Clave (NC+ m/2 -2 )/2 +1 de Der
En Izq se ponen (NC+ m/2 -2 )/2 valores de clave, includa CI, y
los correspondientes enlaces

Padre

Izq Der

nodo bajo
mnimo
El nodo bajo mnimo recibe claves de su hermano inmediato
derecho
Rotacin hacia la derecha
En Izq se dejan (NC+ m/2 -2 )/2 valores de clave (NC=n claves
Izq)
En Padre se reemplaza la clave intermedia entre los enlaces que
referencian a Izq y Der, CI, por la Clave (NC+ m/2 -2 )/2 +1 de Izq
En Der se ponen (NC+ m/2 -2 )/2 valores de clave, includa CI, y
los correspondientes enlaces

Padre

Izq Der

nodo bajo
El nodo bajo mnimo recibe claves demnimo
su hermano inmediato
izquierdo
Ejemplo de extraccin sin
consecuencias (m=5)
47
80
30 37 55 65 70

10 15 49 50
35 36 58 60
40 43 66 68
72 75 80 85
47

30 37 55 65 70

10 15 49 50
35 36 58 60
40 43 66 68
72 75 85

superior al mnimo nmero de valores de clave (2)


Ejemplo de extraccin con rotaciones
(m=5)
47
66
30 37 55 65 70

10 15 49 50
35 36 58 60
40 43 66 68
72 75 85
47

30 37 55 65 70

10 15 49 50
35 36 nodo 58 60
40 43 bajo 68
mnim 72 75 85
Tiene ms de m/2 -1 (=2)ovalores de
clave?
Ejemplo de extraccin con rotaciones
(m=5)
47

30 37 55 65 70

10 15 49 50
35 36 nodo 58 60
40 43 bajo 68
mnim 72 75 85

Tiene ms de m/2 -1 (=2) o


valores de clave
47

30 37 55 65 72

10 15 49 50
35 36 58 60
40 43 68 70
75 85
Rotacin hacia la izquierda
rbol B
Extraccin con recombinaciones
Inicio
Recombinacin-2/1
Reg est bajo mnimo nmero de claves m/2 -2, no tiene
hermano inmediato izquierdo y Der tiene un nmero de claves
igual a m/2 -1
Se sitan en un solo nodo, Reg, los valores de clave y los
enlaces de Reg y Der y la clave del Padre que los separaba
Nmero de valores de clave de Reg despus de la

Recombinacin-2/1 es:
( m/2 -2)+( m/2 -1)+1=2* m/2 -2<=m-1
nodo
bajo Padre
mnimo
Reg Der
Recombinacin-2/1
Reg est bajo mnimo nmero de claves < m/2 -1), no
tiene hermano inmediato derecho y su Izq con un nmero de
claves igual a m/2 -1
Se sitan en un solo nodo, Izq, los valores de clave y los enlaces
de Izq y Reg y la clave del Padre que los distingua
Nmero de valores de clave de Izq despus de la

Recombinacin-2/1 es:
( m/2 -2)+( m/2 -1)+1=2* m/2 -2<=m-1
nodo
Padre bajo
mnimo
Izq Reg
Ejemplo de extraccin con Recombinacin-2/1 (m=5)
47
49
30 37 55 65 72

10 15 49 50
35 36 58 60
40 43 68 70
75 85
47

30 37 55 65 72

10 15 50
35 36 58 60
40 43 68 70
nodo
75 85
bajo
mnimo
nmero de claves= m/2 -1
Ejemplo de extraccin con Recombinacin-2/1 (m=5)
47

30 37 55 65 72

10 15 50
35 36 58 60
40 43 nodo 68 70
bajo 75 85
mnimo
47 nmero de claves= m/2 -1

30 37 65 72
Recombinacin-2/1

10 15 50 55 58 60

35 36 68 70

40 43 75 85
Recombinacin-3/2
Reg est bajo mnimo nmero claves m/2 -2, Izq y Der
estn al mnimo nmero de claves = m/2 -1
Se sitan en Izq y Der los valores de clave y los enlaces de Izq,
Reg y Der junto con las dos claves del Padre situadas entre los
enlaces de Izq y Der
El nmero de valores de clave de Izq y Der despus de la
Recombinacin-3/2 es:
(3* m/2 -3)/2 y (3* m/2 -3)/2
El valor de clave central de los tres nodos se sita en el padre
Padre

Izq Der

nodo
Reg bajo
Ejemplo de extraccin con Recombinacin-3/2 (m=5)

47
60
30 37 55 65 72

10 15 49 50
35 36 58 60
40 43 68 70
75 85
47

30 37 55 65 72

10 15 49 50
35 36 58
40 43 68 70
nodo 75 85
bajo
mnimo
nmero de claves= m/2 -1
Ejemplo de extraccin con Recombinacin-3/2 (m=5)
47

30 37 55 65 72

10 15 49 50
35 36 58
40 43 68 70
nodo 75 85
bajo
mnimo
nmero de claves= m/2 -1
47

30 37 58 72

10 15 49 50 55
35 36 65 68 70
40 43 Recombinacin- 75 85

3/2
Ejemplo de extraccin desde un nodo no
hoja (m=5)
47 47

30 37 55 65 72

10 15 49 50

35 36 58 60

40 43 68 70
Sucesor
75 85
Ejemplo de extraccin desde un nodo no
hoja (m=5)
49

30 37 55 65 72

10 15 50

35 36 58 60
nodo
40 43 bajo 68 70
mnimo
75 85
nmero de claves= m/2 -1
Ejemplo de extraccin desde un nodo no
hoja (m=5)
49

30 37 55 65 72

10 15 50
35 36 58 60
40 43 nodo 68 70
bajo 75 85
mnimo
nmero de claves= m/2 -1
49

30 37 65 72

10 15 50 55 58 60
35 36 68 70
40 43 75 85

Recombinacin-
2/1
Resumen de la
extraccin
Tras la bsqueda, el nodo o en su caso su sucesor, se extrae
de una hoja.
Nmero de accesos igual a la altura
del rbol.
Si no se queda bajo mnimo lo escribe y termina.
Un
acceso.
Si se queda bajo mnimo y no es la raz: Un acceso si tiene
hermano. Tres accesos ms
Si tiene hermano derecho se intenta Rotacin hacia la izquierda. si la hace. FIN

Si tiene hermano izquierdo se intenta Rotacin hacia la derecha.


Un acceso si tiene
Si no se ha podido realizar una Rotacin: hermano. Tres accesos ms
si la hace. FIN
Si tiene los dos hermanos inmediatos Recombinacin-3/2Tres . accesos (uno para liberar la
pgina)
Si tiene hermano izquierdo Recombinacin-2/1 con el izquierdo.Dos accesos (uno

Si no Recombinacin-2/1 con el derecho. para liberar la


Dos accesos (uno para liberar la pgina)
Si el padre no resulta bajo mnimo se escribe
pgina) y finaliza el proceso.
Un
Si el padre resulta bajo mnimo, segn sea o no raz, se contina acceso. con la
resolucin de la situacin de bajo mnimo hacia arriba.
Si la raz se vaca se sustituye por su nico hijo.
Un
acceso.
rbol B
Implementacin en Java de un contenedor con un
rbol B
Inicio
Clase ArbolB: mtodos internos
import java.util.LinkedList; Clase rbolB concrecin de la abstracta
import java.util.Stack;
Multirrama que implementa la interfaz
public class ArbolB extends Multirrama { ContenedorPersistente mediante un rbol B
int minimoclaves;
private class ParejaInsertar {
public byte[] clave;
public int direccin; Clase auxiliar pareja clave/enlace
}
ParejaInsertar particion_1_2(Nodo nodo) { ... }
void particion_2_3(Nodo padre, int posizq, Nodo izq, Nodo der) { ... }
void rotacionizqder(Nodo padre, int posizq, Nodo izq, Nodo der) { ... }
void rotacionderizq(Nodo padre, int posizq, Nodo izq, Nodo der) { ... }
void recombinacion_2_1(Nodo padre, int posizq Nodo izq, Nodo der) { ... }
void recombinacion_3_2(Nodo padre, int posReg, Nodo izq, Nodo reg, Nodo der) { ... }

...
Se desarrollan las operaciones propias de un rbol B:
}
particiones, rotaciones y recombinaciones
Clase ArbolB: mtodos pblicos
...
public void crear(String ruta, int tamaoDatos, int Orden) { ... }
public void crear(String ruta, int tamaoDatos) {
crear(ruta, tamaoDatos, 100); Crea un rbol B con
} orden 100 por defecto
public void abrir(String ruta) { ... }
public void cerrar() {
fichero.cerrar(); Operacin heredada de ContenedorPersistente que
} cierra el fichero asociado con el contenedor
public void vaciar() {
fichero.cerrar(); Operacin heredada de Contenedor que
crear(nombreFichero, tamaoDatos , Orden); vaca el fichero asociado con el contenedor
}
public void insertar(Object o) { ... }
public void extraer(Object o) { ... }
public boolean est(Object o) { ... }
public boolean esVaco() {
return tamao() == 0;
}
public int tamao() { Estos mtodos son los de las interfaces
return numElem;
}
Contenedor y ContenedorPersistente
}
Esquema de clases: ContenedorOrdenado
public interface ContenedorOrdenado
public interface ContenedorOrdenado {{
public
public void insertar(Comparable e);
void insertar(Comparable e);
public void
public void extraer(Comparable
extraer(Comparable e);
e);
public
public void
void vaciar(Comparable
vaciar(Comparable e);
e);
public
public boolean est(Comparable
boolean est(Comparable e);
e);
public
public boolean
boolean esVaco();
esVaco();
public int
public int tamao();
tamao();
}
}

public class rbolBinarioBsqueda


public class rbolBinarioBsqueda implements
implements ContenedorOrdenado
ContenedorOrdenado {
{
protected int numElem;
protected int numElem;
protected
protected NodoBinario
NodoBinario raz;
raz;
public void
public void insertar(Comparable
insertar(Comparable valor);
valor);
public
public void
void extraer(Comparable
extraer(Comparable valor);
valor);
public
public void
void vaciar(Comparable
vaciar(Comparable valor);
valor);
public boolean
public boolean est(Comparable
est(Comparable valor);
valor);
public
public boolean
boolean esVaco();
esVaco();
public
public int
int tamao();
tamao();
}
}

public
public class
class rbolBinarioAjustable
rbolBinarioAjustable extends
extends rbolBinarioBsqueda
rbolBinarioBsqueda {
{
protected
protected NodoBinario
NodoBinario rotacinSimple(NodoBinario
rotacinSimple(NodoBinario nodo,int
nodo,int rama);
rama);
protected
protected NodoBinario
NodoBinario rotacinDoble(NodoBinario
rotacinDoble(NodoBinario nodo,int
nodo,int rama);
rama);
protected
protected NodoBinario
NodoBinario rotacinDobleInversora(NodoBinario
rotacinDobleInversora(NodoBinario nodo,int
nodo,int rama);
rama);
}
}

rbolBiselado rbolAVL
Esquema de clases: ContenedorPersistente
public
public interface
interface Contenedor {{ public interface ContenedorPersistente
public interface
public void
ContenedorPersistente extends extends Contenedor
Contenedor {
{
public public void crear(String
crear(String nombre,
nombre, int
int tamaodatos);
tamaodatos);
public void
void insertar(Object
insertar(Object e);
e); public
public void
void abrir(String
abrir(String nombre);
nombre);
public void
void extraer(Object
extraer(Object e); public
public e); public void cerrar();
void cerrar();
public
public void
void vaciar();
vaciar(); }
}
public
public boolean
boolean est(Object
est(Object e);
e);
public
public boolean esVaco();
boolean esVaco(); public class
public class
FicheroAvanzado
FicheroAvanzado
public
public int
int tamao();
tamao();
extends Fichero {
extends Fichero
public
public
public void
{
void posicionar(int
int posicionar(int
pos);
tomarPgina(); pos);
public void
int liberarPgina(int
tomarPgina();
}
public pos);

}
liberarPgina(int
public void crear(String pos);
nombre, int lp);
public void
public void crear(String
crear(String nombre,
nombre, int
int lp,
lp);int adj);
crear(String nombre);
public void abrir(String nombre, int lp, int adj);
public int
public void adjunto(int
abrir(Stringpos);
nombre);
public void
public int adjunto(int
adjunto(int pos);
pos, int valor);
void tamao();
public long adjunto(int pos, int valor);
public byte[]
public long tamao();
leer(int pos);
public byte[] leer(int pos);dato, int pos);
void escribir(byte[]
} public void escribir(byte[] dato, int pos);
}

Trie rbolB concreta un ContenedorPersistente implementado


como una extensin de Multirrama que usa un rbol B public
public abstract class Multirrama
abstract class Multirrama implements
implements
ContenedorPersistente
ContenedorPersistente { {
protected int
protected int raiz;
raiz;
protected int
protected int numEle;
numEle;

public
public class
class rbolB extends
extends Multirrama
Multirrama {{
protected
protected int
protected
int Orden;
protected int
Orden;
int tamaoDatos;
tamaoDatos;
int protected
protected String nombreFichero;
String
int mnimoClaves;
mnimoClaves; protected
nombreFichero;
private protected FicheroAvanzado fichero;
FicheroAvanzado fichero;
private class
class ParejaInsertar
ParejaInsertar {...}
{...} protected
protected AlmacenabeComparable conv;
AlmacenabeComparable conv;
ParejaInsertar
ParejaInsertar particin_1_2(Nodo
particin_1_2(Nodo nodo)
nodo) {...}
{...} protected class Nodo{...};
protected class Nodo{...};
void particin_2_3(Nodo
void particin_2_3(Nodo padre,
padre, int
int posizq,
posizq, Nodo
Nodo izq,
izq, Nodo
Nodo der)
der) {...}
{...} class InfoPila {...};
class InfoPila {...};
int
int cardinal();
void
void rotacinizqder(Nodo
rotacinizqder(Nodo padre,
padre, int
int posizq,
posizq, Nodo
Nodo izq,
izq, Nodo
Nodo der)
der) {...}
{...} cardinal();
void comprueba(Nodo
void comprueba(Nodo n);
n);
void
void rotacinderizq(Nodo
rotacinderizq(Nodo padre,
padre, int
int posizq,
posizq, Nodo
Nodo izq,
izq, Nodo
Nodo der)
der) {...}
{...} Nodo leer(int
leer(int dir);
dir);
Nodo
void recombinacin_2_1(Nodo
void recombinacin_2_1(Nodo padre,
padre, int
int posizq,
posizq, Nodo
Nodo izq,
izq, Nodo
Nodo der)
der) {...}
{...} void
void escribir(Nodo
escribir(Nodo n);
n);
void boolean
boolean buscar(AlmacenableComparable
buscar(AlmacenableComparable e,e, stack
stack pila);
void recombinacin_3_2(Nodo
recombinacin_3_2(Nodo padre,
padre, int
int posReg,
posReg, Nodo
Nodo izq
izq ,
, Nodo
Nodo reg,
reg, Nodo
Nodo der){}
der){} boolean
pila);
boolean encuentra(AlmacenableComparable e);
encuentra(AlmacenableComparable e);
public Multirrama();
public Multirrama();
public
public void
void crear(String
crear(String ruta,
ruta, int
int tamaoDatos,
tamaoDatos, int
int Orden)
Orden) {...}
{...} }
}
public
public void
void crear(String
crear(String ruta,
ruta, int
int tamaoDatos)
tamaoDatos) {...}
{...}
public
public void
void abrir(String
abrir(String ruta)
ruta) {...}
{...}
public
public void cerrar() {...}
void cerrar() {...}
public
public void
void vaciar()
vaciar() {...}
{...}
public
public void
void insertar(Object
insertar(Object o)o) {...}
{...} Multirrama es clase
public void
void extraer(Object o) {...}
extraer(Object o)
public
public boolean est(Object
{...} abstracta base para las
public boolean est(Object o)o) {...}
{...}
public
public boolean
boolean esVaco()
esVaco() {...}
{...} variantes del multirrama.
public
public int
int tamao()
tamao() {...}
{...}
}
}
rbolB: crear Operacin heredada de ContenedorPersistente que
crea un fichero cuyo nombre es ruta, lo asocia al
contenedor e inicializa los atributos correspondientes
public void crear(String ruta, int tamaoDatos, int Orden) {
cerrar();
this.tamaoDatos = tamaoDatos;
this.Orden = Orden;
if (Orden < 5)
throw new ExcepcinContenedor("Orden inferior a 5 en rbol B");
Nodo nodo = new Nodo(); El fichero (tipo FicheroAvanzado) se crea con 4 adjuntos
nombreFichero = ruta;
fichero.crear(nombreFichero, nodo.tamao(), 4);
raiz = Fichero.dirNula;
El tamao de nodo depende de Orden y tamaoDatos
numElem = 0;
mnimoClaves = (Orden + 1) / 2 - 1; El mnimo nmero de claves es funcin de Orden
fichero.adjunto(0, raiz);
fichero.adjunto(1, numElem); En el adjunto 0 se sita la direccin de la raz
fichero.adjunto(2, tamaoDatos);
fichero.adjunto(3, Orden); En el adjunto 1 se sita el nmero de elementos
}
En el adjunto 2 se sita el tamao de los datos

En el adjunto 3 se sita el orden


rbolB: abrir Operacin heredada de ContenedorPersistente que
asocia el fichero cuyo nombre es ruta con el
contenedor e inicializa los atributos correspondientes
public void abrir(String ruta) {
fichero.abrir(ruta); Del adjunto 0 se lee la direccin de la raz
raiz = fichero.adjunto(0);
Del adjunto 1 se lee el nmero de elementos
numElem = fichero.adjunto(1);
tamaoDatos = fichero.adjunto(2); Del adjunto 2 se lee el tamao de los datos
Orden = fichero.adjunto(3);
mnimoClaves = (Orden + 1) / 2 - 1; Del adjunto 3 se lee el orden del rbol B
}
El nmero mnimo de claves en un
nodo se calcula a partir del orden
particin_1_2 Realiza la Particin-1/2 de nodo y devuelve
ParejaInsertar: el par clave/direccin que
deber insertarse en el padre
ParejaInsertar particin_1_2(Nodo nodo) {
ParejaInsertar pa = new ParejaInsertar();
Nodo nuevoNodo = new Nodo();
Establece el nmero de claves del nuevo nodo
int ncnuevo = Orden / 2;
int ncnodo = Orden - ncnuevo - 1;
int dirNuevo = fichero.tomarPgina();
nuevoNodo.direccin(dirNuevo);
nuevoNodo.cardinal(ncnuevo); Primer enlace de nuevoNodo
nuevoNodo.enlace(0, nodo.enlace(ncnodo + 1));
// [xxxxx] [ ] => [xx ] [xx ] Transfiere las claves y el resto de
for (int i = 1; i <= nuevoNodo.cardinal(); i++) { los enlaces de nodo a nuevoNodo
nuevoNodo.clave(i, nodo.clave(ncnodo + 1 + i));
nuevoNodo.enlace(i, nodo.enlace(ncnodo + 1 + i));
}
pa.clave = nodo.clave(ncnodo + 1); Clave que ascender al padre
pa.direccin = nuevoNodo.direccin();
nodo.cardinal(ncnodo); Enlace que acompaar a la clave en el padre
escribir(nodo);
escribir(nuevoNodo); Reduccin de la cardinalidad de nodo
return pa;
}
particin_2_3 Realiza la Particin-2/3 a partir de los nodos padre, izq
y der; y la posicin del enlace que apunta a izq, posizq
void particin_2_3(Nodo padre, int posizq, Nodo izq, Nodo der) {
int clavesRepartir = izq.cardinal() + der.cardinal() - 1;
Nodo reg = new Nodo();
int ncizq = (clavesRepartir) / 3; Fija el nmero de claves para los tres nodos
int ncreg = (clavesRepartir + 1) / 3;
int ncder = (clavesRepartir + 2) / 3;
int antncder = der.cardinal(); Crea la pgina del nuevo nodo, reg
int antncizq = izq.cardinal();
reg.direccin(fichero.tomarPgina());
padre.insertar(izq.clave(ncizq + 1), reg.direccin(), posizq + 1); Se inserta en el padre la clave y
reg.cardinal(ncreg); la direccin correspondientes
reg.enlace(0, izq.enlace(ncizq + 1));
for (int i = ncizq + 2; i <= antncizq; i++) {
reg.clave(i - ncizq - 1, izq.clave(i)); Se pasan de izq a reg los enlaces
reg.enlace(i - ncizq - 1, izq.enlace(i));
}
y las claves correspondientes
izq.cardinal(ncizq);
reg.clave(antncizq - ncizq, padre.clave(posizq + 2)); Se pasa de padre a reg la clave correspondiente
int posl = antncizq - ncizq;
reg.enlace(posl, der.enlace(0));
for (int i = posl + 1; i <= ncreg; i++) { Se pasan de der a reg los enlaces
reg.clave(i, der.clave(i - posl));
reg.enlace(i, der.enlace(i - posl));
y las claves correspondientes
}
int ncpas = antncder - ncder;
Se sustituye en padre por la clave correspondiente de der
padre.clave(posizq + 2, der.clave(ncpas));
der.enlace(0, der.enlace(ncpas));
for (int i = ncpas + 1; i <= antncder; i++) { Primer enlace de der
der.clave(i - ncpas, der.clave(i));
der.enlace(i - ncpas, der.enlace(i));
}
der.cardinal(ncder); Se desplazan las claves y el resto de los enlaces de der
escribir(izq);
escribir(reg);
escribir(der);
}
Realiza la rotacin hacia la derecha a partir

rotacionizqder
de los nodos padre, izq y der; y la posicin
del enlace que apunta a izq, posizq
void rotacinizqder(Nodo padre, int posizq, Nodo izq, Nodo der) {
int clavesRepartir = izq.cardinal() + der.cardinal();
int ncizq = (clavesRepartir) / 2;
Fija el nmero de claves para los dos nodos
int ncder = clavesRepartir - ncizq;
int ncpas = ncder - der.cardinal();
int antncder = der.cardinal();
der.cardinal(ncder);
for (int i = antncder; i >= 1; i--) { Se abre hueco por desplazamiento
der.clave(i + ncpas, der.clave(i)); de las claves y los enlaces de der
der.enlace(i + ncpas, der.enlace(i));
}
der.enlace(ncpas, der.enlace(0)); Se pasa a der la clave correspondiente de padre
der.clave(ncpas, padre.clave(posizq + 1));
for (int i = ncizq + 2; i <= izq.cardinal(); i++) {
der.clave(i - (ncizq + 1), izq.clave(i)); Se pasan de izq a reg los enlaces
der.enlace(i - (ncizq + 1), izq.enlace(i));
y las claves correspondientes
}
der.enlace(0, izq.enlace(ncizq + 1)); Primer enlace de der
padre.clave(posizq + 1, izq.clave(ncizq + 1));
izq.cardinal(ncizq);
escribir(padre); Pasa a padre la clave correspondiente de izq
escribir(izq);
escribir(der);
Se ajusta la cardinalidad de izq
}
Realiza la rotacin hacia la izquierda a partir

rotacionderizq
de los nodos padre, izq y der; y la posicin
del enlace que apunta a izq, posizq
void rotacinderizq(Nodo padre, int posizq, Nodo izq, Nodo der) {
int clavesRepartir = izq.cardinal() + der.cardinal();
int ncder = (clavesRepartir) / 2;
Fija el nmero de claves para los dos nodos
int ncizq = clavesRepartir - ncder;
int ncpas = der.cardinal() - ncder;
int antncizq = izq.cardinal(); Se pasa a izq la clave correspondiente de padre
izq.cardinal(ncizq);
izq.clave(antncizq + 1, padre.clave(posizq + 1));
izq.enlace(antncizq + 1, der.enlace(0));
for (int i = 1; i < ncpas; i++) {
izq.clave(antncizq + 1 + i, der.clave(i)); Se pasan de der a izq los enlaces
izq.enlace(antncizq + 1 + i, der.enlace(i)); y las claves correspondientes
}
padre.clave(posizq + 1, der.clave(ncpas));
der.enlace(0, der.enlace(ncpas)); Pasa a padre la clave correspondiente de der
for (int i = 1; i <= ncder; i++) {
der.clave(i, der.clave(i + ncpas)); Primer enlace de der
der.enlace(i, der.enlace(i + ncpas));
}
Se desplazan las claves y los enlaces de der
der.cardinal(ncder);
escribir(padre);
escribir(izq);
escribir(der);
Se ajusta la cardinalidad de der
}
Realiza la Recombinacin-2/1 a partir de
recombinacion_2_1 los nodos padre, izq y der; y la posicin
del enlace que apunta a izq, posizq
void recombinacin_2_1(Nodo padre, int posizq, Nodo izq, Nodo der) {
int antncizq = izq.cardinal();
izq.cardinal(izq.cardinal() + 1 + der.cardinal()); Se baja la clave discriminante
izq.clave(antncizq + 1, padre.clave(posizq + 1)); en el padre al final del izquierdo
izq.enlace(antncizq + 1, der.enlace(0));
for (int i = 1; i <= der.cardinal(); i++) { Se pasa el enlace 0 de der a izq
izq.clave(antncizq + 1 + i, der.clave(i));
Se pasan de der a izq los enlaces
izq.enlace(antncizq + 1 + i, der.enlace(i));
y las claves correspondientes
}
padre.extraer(posizq + 1);
Se extraen de padre la clave y el enlace a der
escribir(izq);
fichero.liberarPgina(der.direccin()); Se actualiza en el fichero izq
}

Se libera der
Realiza la Recombinacin-3/2 a partir de

recombinacion_3_2 los nodos padre, izq, reg y der; y la posicin


del enlace que apunta a reg, posReg
void recombinacin_3_2(Nodo padre, int posReg, Nodo izq, Nodo reg, Nodo der) {
int aRepartir = izq.cardinal() + reg.cardinal() + der.cardinal() + 1;
int ncder = aRepartir / 2;
int ncizq = aRepartir - ncder; Fija el nmero de claves
int antncizq = izq.cardinal(); para los dos nodos
int antncder = der.cardinal();
izq.cardinal(ncizq);
izq.clave(antncizq + 1, padre.clave(posReg));
Se completa izq con la clave del
izq.enlace(antncizq + 1, reg.enlace(0));
for (int i = antncizq + 2; i <= ncizq; i++) { padre, el enlace 0 de reg y el
izq.clave(i, reg.clave(i - antncizq - 1)); resto de claves y enlaces de reg
izq.enlace(i, reg.enlace(i - antncizq - 1));
}
der.cardinal(ncder); Se abre hueco por desplazamiento
int ncpas = ncder - antncder; de las claves y los enlaces de der
for (int i = antncder; i >= 1; i--) {
der.clave(i + ncpas, der.clave(i));
der.enlace(i + ncpas, der.enlace(i));
} Se pasa a der la clave correspondiente de padre
der.enlace(ncpas, der.enlace(0));
der.clave(ncpas, padre.clave(posReg + 1));
for (int i = ncpas - 1; i >= 1; i--) { Se pasan de reg a der los enlaces
der.clave(i, reg.clave(reg.cardinal() + i - ncpas + 1)); y las claves correspondientes
der.enlace(i, reg.enlace(reg.cardinal() + i - ncpas + 1));
}
der.enlace(0, reg.enlace(reg.cardinal() - ncpas + 1)); Primer enlace de der
fichero.liberarPgina(reg.direccin());
Se libera reg
escribir(izq);
escribir(der); Se actualizan en el fichero izq y der
padre.extraer(posReg); Se extraen de padre la clave y el enlace a reg
padre.clave(posReg, reg.clave(reg.cardinal() - ncpas + 1));
}

Pasa a padre la clave correspondiente de reg


rbolB: insertarHeredada de Contenedor: Inserta el
objeto o en el contenedor rbolB
public void insertar(Object o) {
AlmacenableComparable alma = (AlmacenableComparable) o;
byte[] dato = alma.aByte();
conv = alma; //permite conversiones byte[] => AlmacenableComparable
Stack pila = new Stack();
if (buscar(alma, pila)) return; //No se admiten repetidos
Nodo nodoActual = new Nodo();
InfoPila info;
Incrementa el nmero
ParejaInsertar pa = new ParejaInsertar();
de elementos en el
pa.clave = dato;
atributo y en el fichero
pa.direccin = Fichero.dirNula;
fichero.adjunto(1, ++numElem);
if (!pila.empty()) { //El rbol no est vaco Inserta en nodoActual la pareja clave, enlace en la
info = (InfoPila) pila.pop(); posicin siguiente a la proporcionada por buscar
nodoActual = info.nodo;
int pos = info.pos;
nodoActual.insertar(pa.clave, pa.direccin, pos + 1);
if (nodoActual.cardinal() < Orden) { //No hay sobrecarga
escribir(nodoActual);
return;
Se actualiza en el fichero el nodo en
}
el que se ha realizado la insercin
...
rbolB: insertar Se toma el padre
...
while (!pila.empty()) { //Arreglar sobrecarga
info = (InfoPila) pila.pop();
Nodo der, izq; pos indica el enlace que lleva al nodo sobrecargado
Se produce
Nodo padre = info.nodo;
sobrecarga
pos = info.pos; Tiene hermano izquierdo
if (pos > 0) { Hay espacio en izq
izq = leer(padre.enlace(pos - 1));
if (izq.cardinal() < Orden - 1) { La rotacin hacia la izquierda
rotacinderizq(padre, pos - 1, izq, nodoActual); resuelve la sobrecarga
return;
}
}
Tiene hermano derecho
if (pos < padre.cardinal()) {
der = leer(padre.enlace(pos + 1)); Hay espacio en der
No se puede rotar, if (der.cardinal() < Orden - 1) {
por tanto, se parte rotacinizqder(padre, pos, nodoActual, der);
La rotacin hacia la derecha
return;
resuelve la sobrecarga
} No tiene hermano izquierdo
}
if (pos == 0) particin_2_3(padre, pos, nodoActual, der);
else particin_2_3(padre, pos - 1, izq, nodoActual); Tiene hermano izquierdo
if (padre.cardinal() < Orden) {
escribir(padre);
return;
Se detiene la propagacin de la sobrecarga en padre
}
nodoActual = padre; El problema de la sobrecarga se propaga al padre
}
...
rbolB: insertar La raz resulta sobrecargada
y por tanto se ha de partir.
...
pa = particin_1_2(nodoActual);
} Se crea una nueva raz: o por estar el rbol vaco o por haberse partido la anterior
nodoActual.cardinal(1);
nodoActual.enlace(0, raiz); La nueva raz tendr una sola clave
nodoActual.clave(1, pa.clave);
nodoActual.enlace(1, pa.direccin); El enlace 0 seala a la anterior raz
nodoActual.direccin(fichero.tomarPgina());
Se reserva una nueva pgina para la nueva raz
raiz = nodoActual.direccin();
escribir(nodoActual);
Se establece la direccin de la nueva raz
fichero.adjunto(0, raiz);
} Se guarda en el fichero la nueva raz

Se guarda en el fichero la
direccin de la nueva raz
rbolB: extraer
public void extraer(Object o) {
Heredada de Contenedor: Extrae
el objeto o del contenedor rbolB
AlmacenableComparable alma = (AlmacenableComparable) o;
conv = alma; Si no se encuentra no se hace nada
Stack pila = new Stack();
if (!buscar(alma, pila)) return; Se decrementa el nmero de elementos
fichero.adjunto(1, --numElem);
InfoPila info = (InfoPila) pila.pop();
Nodo nodoActual = info.nodo; Reduccin de la extraccin en un nodo no hoja al caso de un nodo hoja
int pos = info.pos;
if (nodoActual.enlace(0) != Fichero.dirNula) {
Hay que buscar su sucesor, para que
pila.add(new InfoPila(info.nodo, info.pos));
LinkedList cola = new LinkedList();
ocupe su lugar y extraerlo en la hoja
int dir = nodoActual.enlace(pos);
do { Se desciende por las ramas izquierdas del subrbol del sucesor
nodoActual = leer(dir);
dir = nodoActual.enlace(0);
Se guarda el camino en una cola
if (dir == Fichero.dirNula) pos = 1;
else pos = 0;
cola.addLast(new InfoPila(nodoActual, pos));
Se sustituye la clave a extraer por la de su sucesor
} while (dir != Fichero.dirNula);
info = (InfoPila) pila.pop();
info.nodo.clave(info.pos, nodoActual.clave(1));
escribir(info.nodo);
Se actualiza por si no hay ms modificaciones
pila.add(info);
while (!cola.isEmpty()) {
pila.add(cola.getFirst()); Se aaden a la pila los elementos del
cola.removeFirst(); camino que se encuentran en la cola
}
info = (InfoPila) pila.pop();
Se establece el nodo del que hay que extraer la clave
nodoActual = info.nodo;
pos = info.pos;
} Y la posicin donde se encuentra
...
rbolB: extraer
...
Extraccin en un nodo hoja
nodoActual.extraer(pos);
nodoActual contiene el nodo en el
while (nodoActual.cardinal() < mnimoClaves
&& nodoActual.direccin() != raiz) {
que se ha de extraer la clave pos
Nodo padre, der = new Nodo(), izq = new Nodo();
info = (InfoPila) pila.pop(); Se toma de la pila el padre
padre = info.nodo;
pos = info.pos;
if (pos < padre.cardinal()) { Tiene hermano derecho, der
der = leer(padre.enlace(pos + 1));
if (der.cardinal() > mnimoClaves) { Si der est sobre mnimo se hace
rotacinderizq(padre, pos, nodoActual, der); una rotacin hacia la izquierda
return;
}
}
if (pos > 0) { Tiene hermano izquierdo, izq
izq = leer(padre.enlace(pos - 1));
if (izq.cardinal() > mnimoClaves) {
Si izq est sobre mnimo se hace
rotacinizqder(padre, pos - 1, izq, nodoActual);
una rotacin hacia la derecha
return;
}
} Cuando no se puede rotar se ha de recombinar
if (pos > 0 && pos < padre.cardinal())
recombinacin_3_2(padre, pos, izq, nodoActual, der);
La Recombinacin-3/2 se hace siempre
else if (pos > 0)
que tenga hermanos por ambos lados
recombinacin_2_1(padre, pos - 1, izq, nodoActual);
else recombinacin_2_1(padre, pos, nodoActual, der);
nodoActual = padre;
}
... Las recombinaciones pueden propagar
la situacin de bajo mnimo al padre
rbolB: extraer Se ha resuelto la situacin bajo mnimo o se ha llegado a la raz

...
if (nodoActual.cardinal() > 0) { Cuando se ha resuelto la situacin bajo
escribir(nodoActual); mnimo, se actualiza nodoActual
}
else {
raiz = nodoActual.enlace(0); La raz se ha quedado sin datos,
fichero.liberarPgina(nodoActual.direccin()); se sustituye por su nico hijo
fichero.adjunto(0, raiz);
}
}
rbolB: est Heredada de Contenedor: Devuelve
si el objeto e est o no en el rbolB

Convierte el objeto a AlmacenableComparable


para poder llamar a buscar del Multirrama
public boolean est(Object e) {
AlmacenableComparable alma = (AlmacenableComparable) e;
conv = alma;
Lo guarda en conv para poder
return buscar(alma, new Stack());
hacer las conversiones necesarias
}

Invoca a buscar de Multirrama

You might also like