29.01.2015 Views

Cap. 17. B-Trees - Inicio

Cap. 17. B-Trees - Inicio

Cap. 17. B-Trees - Inicio

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Cap</strong>ítulo <strong>17.</strong><br />

1<br />

B-<strong>Trees</strong>.<br />

<strong>17.</strong>1 Definición de B-<strong>Trees</strong> de grado t.<br />

Un árbol T es un B-Tree de grado t si:<br />

a) Todas las hojas de T tienen igual profundidad.<br />

b) Todos los nodos tienen a lo menos (t-1) claves almacenadas, excepto la raíz.<br />

c) Todos los nodos tienen a lo más (2t-1) claves almacenadas.<br />

d) La raíz tiene a lo menos una clave.<br />

e) Un nodo con (2t-1) claves tiene (2t) hijos.<br />

<strong>17.</strong>2. Cálculo de la altura de un B-Tree.<br />

Si n 1 y t 2, un B-Tree con n claves tiene altura h acotada según:<br />

n 1<br />

log<br />

2t( n 1) 1 h log<br />

t( )<br />

2<br />

Demostración.<br />

En el caso de que todos los nodos, incluida la raíz tengan el menor número de nodos, se tiene<br />

2<br />

que la raíz tiene dos hijos; un nodo con (t-1) claves tiene t hijos y t nietos. La Figura <strong>17.</strong>1,<br />

ilustra el crecimiento del B-Tree con t=4. El menor número de claves que puede tener la raíz es<br />

una.<br />

1<br />

2<br />

3<br />

Figura <strong>17.</strong>1 B-tree con (t-1) claves en un nodo. Cada nodo tiene t hijos.<br />

La siguiente serie geométrica, genera el número de nodos en uno de los subárboles de la raíz. En<br />

2<br />

el primer nivel hay un nodo, en el segundo se tienen t nodos, y en el tercero t ; por inducción se<br />

h 1<br />

tendrán t en el nivel h.<br />

k h h<br />

k 1 2 1 1<br />

1 ... h t<br />

t t t t<br />

t 1<br />

k 1<br />

Profesor Leopoldo Silva Bijit 20-01-2010


2 Estructuras de Datos y Algoritmos<br />

Como la raíz tiene una clave y dos descendientes; y cada nodo tiene a lo menos (t-1) claves, el<br />

número total n de claves almacenadas en los nodos, incluida la raíz, en un B-Tree de altura h<br />

será:<br />

t 1<br />

n t t t t<br />

t 1<br />

k h h<br />

1<br />

1 2( 1) k<br />

1 2( 1)( ) 2 h<br />

1<br />

k 1<br />

Sacando logaritmo en base t, se obtiene:<br />

n 1<br />

h log<br />

t<br />

( )<br />

2<br />

Para acotar h por abajo:<br />

Si los nodos tienen a lo más (2t-1) claves, tendrán 2t hijos.<br />

En la raíz se tendrán (2t-1) claves, y ésta tendrá 2t hijos, cada uno con (2t-1) claves. Se tienen<br />

2<br />

(2 t ) nodos nietos, en el nivel 2 del B-Tree. Finalmente en el nivel h, se tendrán: (2 t ) h nodos.<br />

Figura <strong>17.</strong>2 B-tree con máximo número de claves en cada nodo, con t=4.<br />

La suma total de nodos del B-Tree, en este caso, puede expresarse según:<br />

k h 1<br />

k 1 2<br />

h<br />

(2 t) 1 2 t (2 t) ... (2 t)<br />

k 1<br />

h 1<br />

(2 t) 1<br />

2t<br />

1<br />

Entonces el número total de claves almacenadas en un B-Tree de altura h, debe ser menor que:<br />

k h 1<br />

h 1<br />

k 1 (2 t) 1 h 1<br />

n (2t 1) (2 t) (2t 1)( ) (2 t) 1<br />

2t<br />

1<br />

k 1<br />

Sacando logaritmo en base 2t, se obtiene la cota inferior de h.<br />

log<br />

2t ( n 1) 1 h<br />

La Figura <strong>17.</strong>3 muestra el acotamiento de la altura de un B-Tree de grado t=4.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 3<br />

B-Tree<br />

Binario balanceado<br />

Figura <strong>17.</strong>3 Altura de B-tree con t=4.<br />

El número de total de claves en un B-Tree de grado t, con altura h está en el siguiente intervalo.<br />

1<br />

(2 ) h<br />

h<br />

t 1 n 2t<br />

1<br />

Figura <strong>17.</strong>4 Claves máximas y mínimas almacenadas en B-tree con t=4.<br />

<strong>17.</strong>3. Requerimientos de espacio y relaciones de ordenamiento de las claves.<br />

Los requerimientos de espacio para un nodo dependen de t. Para t=2, se requiere un<br />

nodo que pueda almacenar 3 claves y que tenga espacio para 4 punteros. Si t=4, se<br />

requiere nodo con espacio para 7 claves y espacio para 8 punteros.<br />

El esquema de la Figura <strong>17.</strong>5, muestra que si se tienen 3 claves, el nodo debe contener el<br />

número de claves más uno, de tal forma que puedan definirse donde se almacenaran las claves<br />

menores y mayores que cada una de las claves del nodo.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


4 Estructuras de Datos y Algoritmos<br />

a 0 a 1 a 2<br />

p 0<br />

p 1<br />

p 2<br />

p 3<br />

b 0 b 1 b 2 c 0 c 1 c 2 d 0 d 1 d 2 e 0 e 1 e 2<br />

Figura <strong>17.</strong>5 Esquema de B-tree con t=2.<br />

El ordenamiento de las claves, en los nodos, en forma similar a un árbol binario de búsqueda,<br />

cumple las relaciones, para el caso de la Figura <strong>17.</strong>5:<br />

e2 e1 e0 a2 d2 d1 d0 a1 c2 c1 c0 a0 b2 b1 b<br />

0<br />

Se tiene que p<br />

0<br />

apunta a descendientes con valores de claves menores que a 0<br />

; y p<br />

1<br />

apunta a<br />

descendientes con valores de claves menores que a<br />

1<br />

, y mayores que a<br />

0<br />

.<br />

El requerimiento del mínimo número de claves almacenadas en un nodo, se aclarará cuando se<br />

analicen las operaciones de inserción y descarte.<br />

<strong>17.</strong>4. Complejidad en la búsqueda.<br />

Para buscar una clave en un B-Tree de grado t, el peor caso es cuando se tienen (t-1) claves en<br />

cada nodo, ya que en este caso se tiene la mayor altura. Si buscamos la clave en un nodo,<br />

mediante una búsqueda binaria, aprovechando que el arreglo de claves está ordenado, y luego<br />

repetimos esta búsqueda en cada uno de los nodos de la ruta de descenso, que es el peor caso en<br />

búsqueda, tendremos:<br />

T( n) h TBB( t 1)<br />

Una búsqueda binaria entre n elementos tiene una complejidad:<br />

T ( n) (log ( n ) 1)<br />

BB<br />

2<br />

La altura en peor caso es:<br />

h<br />

n 1<br />

log<br />

t<br />

( )<br />

2<br />

Reemplazando, se obtiene:<br />

n 1<br />

T( n) log<br />

t<br />

( ) (log<br />

2( t 1) 1)<br />

2<br />

Puede efectuarse la siguiente aproximación, para t mayor que 100:<br />

log ( t 1) 1 log ( t )<br />

2 2<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 5<br />

Y cambiando el logaritmo de base t a base 2, se tiene:<br />

n 1<br />

log<br />

2( )<br />

n 1<br />

log ( ) 2<br />

t<br />

2 log ( t)<br />

Lo que finalmente permite obtener la complejidad de buscar una clave en un B-Tree de grado t:<br />

n 1<br />

T( n) log<br />

2( ) (log( n ))<br />

2<br />

Que muestra que la búsqueda de una clave, en peor caso, en un B-Tree, tiene complejidad<br />

logarítmica.<br />

<strong>17.</strong>5 Análisis de la operación inserción.<br />

<strong>17.</strong>5.1 Ejemplo de inserción en un 2-4-Tree.<br />

Asumiremos un nodo con 4 claves máximo y 2 claves mínimo. Insertaremos las claves en forma<br />

ascendente a partir del número 1, lo cual es el peor caso para un árbol binario de búsqueda. Esta<br />

estructura es una variación del B-Tree de grado t; en el caso del ejemplo se denomina 2-4-Tree.<br />

Luego de crear el nodo raíz, se pueden agregar 4 claves. Cuando se agrega el número 5, se<br />

produce un rebalse del nodo raíz; y es preciso dividir las claves del nodo raíz en dos nodos<br />

descendientes, de esta manera el B-Tree crece un nivel. La altura crece por rebalse de las hojas.<br />

Se activan dos punteros en el nodo raíz, como se muestra al centro de la Figura <strong>17.</strong>6.<br />

Como tenemos 5 claves, podemos dejar los nodos descendientes con dos claves cada una, y de<br />

este modo quedan con el mínimo posible; y además mover la clave 3, del nodo que rebalsó, a la<br />

raíz. Quedando ésta con una sola clave, cumpliendo las propiedades de un B-tree. Luego se<br />

procede al ingreso de las claves 6 y 7, completando las claves de ese nodo, lo cual se muestra en<br />

la Figura <strong>17.</strong>6 a la derecha.<br />

2<br />

Figura <strong>17.</strong>6. B-Tree después de ingresar la clave 4, 5 y 7.<br />

Las claves siempre se insertan en las hojas, para cumplir la propiedad de que un B-Tree tiene<br />

hojas de igual profundidad.<br />

Luego, al introducir la clave 8, se rebalsa el nodo, y se lo divide en dos, pasando una clave a la<br />

raíz, ahora ésta tiene tres punteros activos. Luego de ingresadas las claves 9 y 10, se completan<br />

las claves de ese nodo, lo cual se ilustra en la Figura <strong>17.</strong>7, a la derecha.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


6 Estructuras de Datos y Algoritmos<br />

Figura <strong>17.</strong>7. B-Tree después de ingresar la clave 8, y 10.<br />

Luego de ingresar la clave 11, se activa un nuevo puntero en la raíz, debido a la división de un<br />

nodo en dos, el ascenso del 9 y la redistribución de claves. La Figura <strong>17.</strong>8, a la derecha muestra<br />

el nodo con todas sus claves, luego de ingresadas las claves 12 y 13.<br />

Figura <strong>17.</strong>8. B-Tree después de ingresar la clave 11, y 13.<br />

Al insertar la clave 14, se activa el último puntero de la raíz, y además ésta queda con todas sus<br />

claves ocupadas.<br />

Figura <strong>17.</strong>9. B-Tree después de ingresar la clave 14.<br />

Se pueden ingresar las claves 15 y 16, completando las claves del nodo ubicado más a la<br />

derecha, lo que se muestra en la Figura <strong>17.</strong>10.<br />

Figura <strong>17.</strong>10 B-Tree después de ingresar la clave 16.<br />

Al introducir la clave 17, se divide el nodo ascendiendo la clave 15, pero ésta no puede ser<br />

almacenada en la raíz, y se procede a la división del nodo raíz, ascendiendo la clave 9, que se<br />

deposita en una nueva raíz; de este modo se vuelve a incrementar la altura del B-Tree.<br />

Figura <strong>17.</strong>11 B-Tree después de ingresar la clave <strong>17.</strong><br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 7<br />

La Figura <strong>17.</strong>12, muestra que después de ingresada la clave 25, se han agregado dos nodos al<br />

subárbol izquierdo, quedando completos los nodos de más a la derecha del segundo y tercer<br />

nivel.<br />

Figura <strong>17.</strong>12 B-Tree después de ingresar la clave 25.<br />

Después de ingresar la clave 26, asciende la clave 24, y posteriormente la clave 18.<br />

Figura <strong>17.</strong>13 B-Tree después de ingresar la clave 26.<br />

Cada vez que asciende una clave, se activan nuevos puntero, y se dividen los nodos.<br />

<strong>17.</strong>5.2 Análisis de inserción en un B-Tree de grado t.<br />

Otra forma de diseñar la operación es insertar siempre la nueva clave en una hoja que no esté<br />

completa; para lograr esto a medida que se desciende desde la raíz, buscando la posición para<br />

insertar, si se encuentra un nodo completo, se procede a la división de éste, repartiendo<br />

equitativamente las claves; y repitiendo este procedimiento hasta insertar finalmente la clave en<br />

una hoja que no está completa.<br />

Es importante destacar que antes de invocar a insertar, debe asegurarse que la clave no esté<br />

presente, ya que en el descenso se modifica la estructura del B-Tree, y es posible que la hoja<br />

donde debería insertarse la clave quede con menos de (t-1) claves, violando las propiedades de<br />

un B-Tree.<br />

a) Árbol vacío.<br />

Se crea un nodo vacío y se le agrega el valor en la primera posición, el nodo se marca como<br />

hoja.<br />

b) Inserción en hoja con menos de (2t-1) claves.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


8 Estructuras de Datos y Algoritmos<br />

p<br />

i n-1<br />

a 0 … a i … a n-1<br />

Figura <strong>17.</strong>14 Inserción en hoja que no está llena.<br />

Se ubica el índice i, cuya clave ai<br />

es menor que el valor v que debe insertarse. Se desplazan las<br />

claves, a partir de la clave a<br />

i 1<br />

, en una posición hacia la derecha. Se inserta la clave v, a la<br />

derecha de la clave a<br />

i<br />

. Se aumenta el número de claves activas en p.<br />

p<br />

i<br />

n<br />

a 0 … a i v a i+1 … a n-1<br />

Figura <strong>17.</strong>15 Después de insertar v en hoja que no estaba llena.<br />

Buscar el índice i, tal que ai<br />

v, mediante búsqueda binaria tiene un costo de O(log(2t 1)) .<br />

En el peor caso, cuando i 1, es decir cuando a 0<br />

v, hay que desplazar (2t 2) claves y<br />

además copiar la clave v, entonces el costo de esta operación es:<br />

c) Inserción en nodo interno.<br />

O(log(2t 1)) O(2t 2) O(1) O( t )<br />

Se ubica la clave ai<br />

que es menor que el valor v que debe insertarse. Sea p<br />

i 1<br />

la dirección del<br />

nodo donde debe insertarse la clave v, que puede denominarse ancestro de v.<br />

c1) Si ancestro no está completo<br />

Si el nodo apuntado por p<br />

i 1<br />

no está completo, se procede a insertar recursivamente v en el<br />

nodo apuntado por p<br />

i 1<br />

, descendiendo un nivel en el B-Tree. Esta operación tiene el costo de la<br />

búsqueda de la clave menor que v, que es O(log(2t 2)) .<br />

c2) Si el ancestro de v, está completo.<br />

Para mantener la condición de descender a un nodo que no está completo, debe partirse el nodo<br />

apuntado por pi<br />

1<br />

en dos.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 9<br />

p<br />

i<br />

a 0 … a i a i+1 … a na-1<br />

p i+1<br />

c 0 … c t-2 c t-1 c t … c 2t-2<br />

Figura <strong>17.</strong>16 Descender a un nodo que está completo.<br />

La clave central c<br />

t 1<br />

se inserta a la derecha de a<br />

i<br />

, previo a esto deben desplazarse una posición<br />

a la derecha, las claves y los punteros desde ai<br />

1<br />

hasta el final, incrementando en uno el número<br />

de claves activas en nodo p. Esto es posible siempre que p apunte a un nodo que no está<br />

completo. Se crea un nuevo nodo, que se muestra como p<br />

i 2<br />

en la Figura <strong>17.</strong>17, y se copian las<br />

( t 1) claves mayores del nodo p<br />

i 1<br />

en las primeras posiciones del nuevo nodo. Además se<br />

disminuye a ( t 1) el número de claves activas de p<br />

i 1<br />

. Si el ancestro de v es una hoja, también<br />

será hoja el nuevo nodo; y si el ancestro de v es un nodo interno, el nuevo nodo también debe<br />

ser nodo interno. En este último caso es preciso copiar también los punteros a descendientes en<br />

las primeras posiciones del nuevo nodo.<br />

p<br />

i<br />

a 0 … a i c t-1 a i+1 … a na-1<br />

p i+1<br />

p i+2<br />

c 0 … c t-2<br />

c t … c 2t-2<br />

Figura <strong>17.</strong>17 Después de partir ancestro de v.<br />

Se continua invocando recursivamente a insertar valor v en el nodo p<br />

i 1<br />

que no está lleno si se<br />

tiene que: ai<br />

v c<br />

t 1; y si se tiene que: ai<br />

1<br />

v c<br />

t 1, el descenso debe ser insertar clave v en<br />

nodo apuntado por p<br />

i 2<br />

. Pero ahora ambos hijos de p, son nodos que no están completos.<br />

El costo de la operación debe considerar la búsqueda del puntero p<br />

i 1<br />

, de costo<br />

O(log(2t 2)) ; debe considerar el desplazamiento de (2t-2) claves en nodo p, además debe<br />

copiar (t-1) claves en p<br />

i 2<br />

, y si este nodo no es hoja debe copiar adicionalmente t punteros;<br />

finalmente tiene que copiar una clave y un puntero en p. Entonces esta operación tiene un costo:<br />

O(log(2t 2)) O(2t 2) O( t 1) O( t) O(2) O( t )<br />

Profesor Leopoldo Silva Bijit 20-01-2010


10 Estructuras de Datos y Algoritmos<br />

c3) Si p es la raíz y está completa.<br />

Un caso particular es si el nodo p es la raíz y si está completa. Demás esta decir que v no puede<br />

estar en el nodo raíz, ya que no se aceptan claves duplicadas en un B-Tree.<br />

raíz<br />

c 0 … c t-2 c t-1 c t … c 2t-2<br />

p<br />

Figura <strong>17.</strong>18 Inserción en raíz completa.<br />

En este caso se crea un nuevo nodo raíz, y en la primera clave se coloca la clave central de p. Se<br />

crea un nuevo nodo en el cual se colocan las (t-1) claves mayores de p. Se actualiza la raíz, y se<br />

procede a insertar v, en la nueva raíz, pero ahora ésta no está completa. Esto da inicio al proceso<br />

de insertar la clave en un nodo ( p<br />

0<br />

o p<br />

1<br />

) que no esté completo.<br />

raíz<br />

0<br />

c t-1<br />

…<br />

p<br />

p 0<br />

p 1<br />

c 0 … c t-2<br />

c t … c 2t-2<br />

<strong>17.</strong>5.3 Costo de la inserción.<br />

Figura <strong>17.</strong>19 Después de intentar insertar en raíz completa.<br />

Si se asume que el costo de insertar una clave en un nodo que no esté lleno, en el peor caso es<br />

de costo Ot (); y como esto se repetirá h veces, uno por cada descenso desde la raíz hasta la<br />

hoja en que se insertará efectivamente la clave. Siendo h la altura del B-Tree, la complejidad de<br />

la operación insertar, será O( th ).<br />

n 1<br />

Antes se demostró que: O( h) O(log t( )) O(log t( n ))<br />

2<br />

Entonces finalmente, la operación insertar tiene complejidad: O( t log<br />

t<br />

( n )) , siendo n el número<br />

de claves almacenadas en el B-Tree.<br />

<strong>17.</strong>6 Análisis de la operación descartar.<br />

En un multiárbol, se puede borrar la clave en cualquier nodo; sin embargo, si el nodo en el cual<br />

se encuentra la clave que será descartada tenía el número mínimo de claves, dejará de cumplirse<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 11<br />

una de las propiedades del B-Tree, y será preciso corregir la estructura. La estrategia es<br />

descartar la clave en una hoja que tenga más del número mínimo de claves.<br />

La operación como se verá a continuación es bastante más compleja que la inserción, sin<br />

embargo como en un B-Tree, el mayor número de claves se encuentran en las hojas, es más alta<br />

la probabilidad de descartar una clave que se encuentre en una hoja.<br />

<strong>17.</strong>6.1. Descarte en hoja con más claves que el mínimo número.<br />

Veremos primero el caso de descartar la clave en una hoja, y siempre que ésta tenga más del<br />

número mínimo de claves almacenadas.<br />

p<br />

a 0 a 1 a 2 … a n-1<br />

Figura <strong>17.</strong>20. Hoja con más de (t-1) claves.<br />

En este caso sólo es preciso desplazar las claves en una posición hacia la izquierda, a partir de la<br />

siguiente a la descartada, y disminuir en uno el número de claves activas en el nodo. No es<br />

preciso copiar los punteros, pues éstos almacenan valores iguales a nulos.<br />

Un caso particular es si el nodo es la raíz y tiene un solo elemento; en este caso el B-Tree queda<br />

vacío.<br />

Buscar la clave dentro del nodo, en el peor caso, es de complejidad O(2t-1) si se emplea<br />

búsqueda secuencial y O(log(2t-1)) si se emplea búsqueda binaria. Se requiera además mover,<br />

en el peor caso, (2t-2) claves lo cual implica complejidad O(2t-2).<br />

Si se emplea búsqueda binaria, esta operación tiene un costo:<br />

O(log(2t 1)) O(2t 2) O( t )<br />

Para lograr que el nodo que contenga la clave que será descartada, tenga más del número<br />

mínimo de elementos, puede procederse al descenso desde la raíz hasta la hoja que contenga el<br />

nodo con la clave buscada, realizando modificaciones para asegurar que siempre se producirá un<br />

descenso a un nodo que tenga más de (t-1) claves, cuya solución se acaba de describir.<br />

<strong>17.</strong>6.2. Descarte en nodo p que no es hoja y que contiene la clave v.<br />

Se asume que nodo p, tiene más de ( t 1) claves, y que i es el índice de la clave v.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


12 Estructuras de Datos y Algoritmos<br />

p<br />

i<br />

a 0 … v a i+1 … a na-1<br />

p i p i+1<br />

b 0 … b i … b nb-1 c 0 … c i … c nc-1<br />

Figura <strong>17.</strong>21. Nodo interno con más de (t-1) claves, y clave con hijo izquierdo y derecho.<br />

Hijo izquierdo con más claves que la mínima.<br />

Si nb<br />

( t 1) se copia la clave b<br />

nb 1<br />

, que es el mayor descendiente del subárbol izquierdo, en<br />

lugar de v; y se continua recursivamente descartando la clave bnb<br />

1<br />

en el nodo apuntado por p<br />

i<br />

.<br />

p<br />

i<br />

a 0 … a i+1 … a na-1<br />

b nb-1<br />

p i<br />

b 0 … b i … b nb-1<br />

Figura <strong>17.</strong>21a. Se recurre a borrar el predecesor de v.<br />

Debe notarse que en este caso, se desciende un nivel, y se está borrando una clave en un nodo<br />

que tiene más de (t-1) claves. Esta operación incurre en el costo de encontrar la clave, y luego<br />

efectuar una copia; entonces se tiene, para búsqueda binaria:<br />

Hijo derecho con más claves que la mínima.<br />

O(log(2t 1)) O(1) O(log( t )) .<br />

Si lo anterior no se cumple, pero nc<br />

( t 1) , se copia la clave c<br />

0<br />

, que es el menor descendiente<br />

del subárbol derecho, en el lugar de v; y se continua descartado la clave c<br />

0<br />

en el nodo apuntado<br />

por p<br />

i 1<br />

. Debe notarse que en este caso se está borrando una clave en un nodo que tiene más de<br />

(t-1) claves. Con igual costo que la anterior.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 13<br />

p<br />

i<br />

a 0 … a i+1 … a na-1<br />

c 0<br />

p i+1<br />

c 0 … c i … c nc-1<br />

Figura <strong>17.</strong>21b. Se recurre a borrar el sucesor de v.<br />

Ambos hijos con número de claves mínimas.<br />

Si no se cumplen las dos condiciones anteriores, y el nodo p no es la raíz, se asume que debe<br />

tener más de (t-1) claves, en este caso se agrega al nodo apuntado por p , la clave v, y las claves<br />

del hermano derecho, el nodo apuntado por p<br />

i 1<br />

, quedando éste completo con (2t-1) claves. Se<br />

libera el espacio del nodo apuntado por p<br />

i 1<br />

, y se procede a descartar recursivamente v, en el<br />

nodo apuntado por p<br />

i<br />

.<br />

p<br />

i<br />

na-2<br />

a 0 … a i+1 … a na-1<br />

i<br />

nb<br />

p i<br />

2t-2<br />

p i+1<br />

b 0 … v … c nc-1 c 0 … c i … c nc-1<br />

Figura <strong>17.</strong>22. Mezcla del hijo izquierdo y derecho.<br />

Esto implica desplazar las claves y los punteros en el nodo apuntado por p. Además deben<br />

copiarse las nc claves en p , a continuación de v; y si p no es hoja, los punteros del nodo<br />

i<br />

pi<br />

1<br />

deben también copiarse al nodo p<br />

i<br />

.<br />

Si consideramos que el costo de encontrar la clave es O(log(2t 1)) , en el peor caso; y que<br />

además deben moverse (2t 2) claves y (2t<br />

1) punteros en p; y que también deben moverse t<br />

claves, ( t 1) desde p<br />

i 1<br />

y la clave v desde p; y finalmente t punteros desde p<br />

i 1<br />

, se tiene un<br />

costo de: O(log(2t 1)) O(2t 2) O(2t 1) O( t) O( t ) .<br />

Nodo raíz con claves mínimas.<br />

Si el nodo p es la raíz, puede quedar luego de la operación con menos de (t-1) claves. Esto se<br />

ilustra en la Figura <strong>17.</strong>23, con t=3, cuando se desea descartar la clave 15. En este caso la clave<br />

i<br />

Profesor Leopoldo Silva Bijit 20-01-2010


14 Estructuras de Datos y Algoritmos<br />

está en el nodo apuntado por p, y luego de la operación, propuesta antes, se obtiene la Figura<br />

<strong>17.</strong>24. En la cual se cumple que luego de la operación descrita antes, el nodo apuntado por p<br />

i<br />

tiene (2t-1) claves.<br />

p<br />

1<br />

10 15<br />

p i p i+1<br />

4 6 18 20<br />

Figura <strong>17.</strong>23. Hijos con claves mínimas, raíz con dos elementos.<br />

p<br />

0<br />

10<br />

t-1 p i p i+1<br />

4 6 15 18 20 18 20<br />

Nodo raíz con una sola clave.<br />

Figura <strong>17.</strong>24. Fusión de hijos.<br />

Si el nodo p es la raíz, y tiene una sola clave, esto se muestra en la Figura <strong>17.</strong>25, y se desea<br />

borrar la clave 10, se procede de igual forma, sin embargo es preciso cambiar la raíz, y liberar<br />

adicionalmente el nodo p. Esta es la única forma en que el B-Tree disminuye su altura.<br />

raíz<br />

p 0<br />

10<br />

p i p i+1<br />

4 8 14 18<br />

Figura <strong>17.</strong>25. Hijos con claves mínimas, raíz con un elemento.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 15<br />

raíz<br />

p i<br />

p<br />

t-1<br />

0<br />

10<br />

p i+1<br />

4 8 10 14 18 14 18<br />

Figura <strong>17.</strong>26. Nueva raíz, y fusión de hijos.<br />

<strong>17.</strong>6.3. Descarte en nodo p que no es hoja y que no contiene la clave v.<br />

Si se ubica, con la posición i, la clave ai<br />

que es menor que el valor v buscado para descartar, se<br />

tendrá que pi<br />

1<br />

apunta al nodo que contiene el valor, o a alguno de sus descendientes, que<br />

contiene efectivamente el valor v.<br />

p<br />

i<br />

a 0 … a i a i+1 … a na-1<br />

p i p i+1<br />

p i+2<br />

b 0 … b i … b nb-1<br />

c 0 … c i … c nc-1<br />

d 0 … d i … d nd-1<br />

Figura <strong>17.</strong>27. Descarte en nodo interno que no contiene la clave buscada.<br />

Se asume que p tiene más de ( t 1) claves, excepto que sea la raíz. Y lo que desea asegurar es<br />

que se descenderá a un nodo con más de ( t 1) claves.<br />

Ancestro de v, tiene más de (t-1) claves.<br />

Si pi<br />

1<br />

tiene más de ( t 1) claves, se procede a descartar recursivamente v, en el nodo apuntado<br />

por p<br />

i 1<br />

, descendiendo un nivel.<br />

Esta operación tiene el costo de encontrar la clave: O(log(2t 1)) .<br />

Si pi<br />

1<br />

tiene (t-1) claves, pueden suceder tres casos:<br />

Hermano izquierdo de ancestro de v, tiene más de (t-1) claves.<br />

Es decir: nb<br />

t 1. Se desplazan las claves y punteros de pi<br />

1<br />

en una posición hacia la derecha;<br />

los punteros sólo si pi<br />

1<br />

no es hoja,. Luego se mueve a<br />

i<br />

al inicio de p<br />

i 1<br />

, el lugar que antes<br />

ocupaba c<br />

0<br />

, a continuación se toma b<br />

nb 1<br />

y se lo coloca en el lugar que ocupaba a<br />

i<br />

.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


16 Estructuras de Datos y Algoritmos<br />

Finalmente, para mantener la estructura del B-Tree, se copia el puntero que apunta a claves<br />

mayores que b<br />

nb 1<br />

en la posición inicial de p<br />

i 1<br />

; es decir apuntando al nodo con claves menores<br />

que a<br />

i<br />

. Se disminuye en uno el número de claves activas en p<br />

i<br />

. Luego se procede a descartar v<br />

en el nodo apuntado por p<br />

i 1<br />

, que ahora es seguro que tiene más de ( t 1) claves.<br />

Debe notarse que no hay hermano izquierdo de p<br />

i 1<br />

, si v a<br />

0<br />

.<br />

p<br />

i<br />

a 0 … a i+1 … a na-1<br />

b nb-1<br />

p i p i+1<br />

p i+2<br />

b 0 … b i … b nb-2<br />

a i c 0 … … c nc-1<br />

d 0 … d i … d nd-1<br />

Figura <strong>17.</strong>28. Préstamo del hermano izquierdo.<br />

Si consideramos que el costo de encontrar la clave es O(log(2t 1)) , en el peor caso; y que<br />

además deben moverse ( t 1) claves y t punteros en p<br />

i 1<br />

; y que también deben efectuarse dos<br />

copias de claves y una de puntero, se tiene un costo de:<br />

O(log(2t 1)) O( t 1) O( t) O(3) O( t )<br />

Esta operación puede aplicarse si el nodo p es la raíz.<br />

Hermano derecho de ancestro de v, tiene más de (t-1) claves.<br />

Es decir: nd<br />

t 1. Se agrega al final de pi<br />

1<br />

la clave ai<br />

1<br />

y el puntero que apunta al nodo con<br />

claves menores que d<br />

0<br />

, se coloca apuntado a nodos con claves mayores que a<br />

i 1<br />

; y se<br />

incrementa en uno las claves activas de p<br />

i 1<br />

, quedando de este modo el ancestro de v, con más<br />

de ( t 1) claves. Luego d<br />

0<br />

se coloca en el lugar que antes ocupaba a<br />

i 1<br />

. Se desplazan en una<br />

posición a la izquierda las claves del nodo p<br />

i 2<br />

; y si ese nodo no es hoja también se desplazan<br />

los punteros; finalmente se disminuye en uno las claves activas de p<br />

i 2<br />

. Luego se procede a<br />

descartar v en el nodo apuntado por p<br />

i 1<br />

, que ahora tiene más de ( t 1) claves, descendiendo<br />

un nivel.<br />

Debe notarse que no hay hermano derecho de p<br />

i 1<br />

, si v a<br />

na 1.<br />

El costo es similar al caso anterior.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 17<br />

p<br />

i<br />

b 0 … b i … b nb-1<br />

a 0 … … a na-1<br />

a i<br />

p i p i+1<br />

1<br />

d 0<br />

p i+2<br />

c 0 … … c nc-1 a i+1<br />

d 1 … d i … d nd-2<br />

Figura <strong>17.</strong>29. Préstamo del hermano derecho.<br />

Esta operación puede aplicarse si el nodo p es la raíz, sin que ésta cambie.<br />

Hermanos de ancestro de v, tienen (t-1) claves.<br />

Al menos uno de los hermanos del ancestro de v debe existir, ya que p no contiene la clave con<br />

valor v.<br />

Si existe el hermano izquierdo<br />

Se baja la clave a<br />

i<br />

, al final del nodo p i<br />

, y se colocan las claves del ancestro de v a continuación;<br />

y si éste no es hoja se copian también los punteros. Quedando de este modo el nodo p<br />

i<br />

con<br />

(2t 1) claves activas. A partir de ai<br />

1<br />

se desplazan hacia la izquierda las claves y punteros en p,<br />

disminuyendo en uno el número de claves activas. Se libera el espacio apuntado por p<br />

i 1<br />

. Se<br />

continua descartando recursivamente v en el nodo apuntado por p<br />

i<br />

.<br />

p<br />

i<br />

a 0 … a i+1 … a na-1<br />

a i+2<br />

d 0 … d nd-1<br />

p i p i+1<br />

p i+2<br />

b 0<br />

… b nb-1 a i c 0<br />

..<br />

c nc-1<br />

c 0 … … c nc-1<br />

d i<br />

…<br />

Figura <strong>17.</strong>30. Fusión del ancestro con el hermano izquierdo.<br />

Si consideramos que el costo de encontrar la clave es O(log(2t 1)) , en el peor caso; y que<br />

además deben copiarse t claves y ( t 1) punteros en p i<br />

; y que también deben efectuarse<br />

( t 2) movimientos de clave y ( t 1) de punteros en nodo p, se tiene un costo de:<br />

O(log(2t 1)) O( t) O( t 1) O( t 2) O( t 1) O( t )<br />

Profesor Leopoldo Silva Bijit 20-01-2010


18 Estructuras de Datos y Algoritmos<br />

Si no existe el hermano izquierdo.<br />

Se baja clave a<br />

i 1<br />

, al final del nodo p<br />

i 1<br />

, a continuación se copian las claves de p<br />

i 2<br />

, y los<br />

punteros si éste no es hoja. El nodo ancestro de v, queda con (2t 1) claves activas. A partir de<br />

ai<br />

2<br />

se desplazan las claves y punteros en p, disminuyendo en uno el número de claves activas.<br />

Se libera el espacio apuntado por p<br />

i 2<br />

. Se continua descartando v en el nodo apuntado por p<br />

i 1<br />

.<br />

De similar costo a la anterior.<br />

p<br />

i<br />

a 0 … a i … a na-1<br />

a i+2<br />

d 0 … d nd-1<br />

p i+1<br />

p i+2<br />

c 0<br />

… c nc-1 a i+1 d 0 .. d nd-1<br />

d i<br />

…<br />

Figura <strong>17.</strong>31. Fusión del ancestro con el hermano derecho.<br />

Si el nodo p es la raíz, y tiene una sola clave, debe cambiarse la raíz al nodo que queda con<br />

(2t 1) claves, y liberar además el antiguo nodo raíz.<br />

<strong>17.</strong>6.4. Complejidad de la operación descarte.<br />

Si se asume que el costo de descartar una clave en un nodo con al menos t elementos, en el peor<br />

caso es de costo Ot (); y como esto se repetirá h veces, uno por cada descenso desde la raíz<br />

hasta la hoja en que se descarta efectivamente una clave. Siendo h la altura del B-Tree, la<br />

complejidad de la operación descartar, será O( th ).<br />

n 1<br />

Antes se demostró que: O( h) O(log t( )) O(log t( n ))<br />

2<br />

Entonces finalmente, la operación descartar tiene complejidad: O( t log<br />

t<br />

( n )) , siendo n el<br />

número de claves almacenadas en el B-Tree.<br />

<strong>17.</strong>7. Árboles coloreados.<br />

Corresponden a un B-Tree de grado 2. Con un máximo de tres claves en un nodo, y un mínimo<br />

de una clave en cada nodo.<br />

Para convertir un árbol coloreado en un B-Tree se emplean las siguientes reglas:<br />

a) Si el nodo contiene 3 claves, la central es negra, la primera y última son rojas.<br />

b) Si el nodo contiene una clave, ésta es negra.<br />

c) Si el nodo contiene dos claves, puede interpretarse de dos formas: Una es que la primera<br />

clave es negra con hijo derecho rojo con la segunda clave; la otra es que la segunda clave es<br />

negra con hijo rojo izquierdo con la primera clave.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 19<br />

Una buena interpretación de los nodos rojos en un árbol coloreado, es dibujarlos en un nivel<br />

horizontal, de este modo se refleja que no alteran las alturas negras de los nodos. Esto se<br />

muestra en la Figura <strong>17.</strong>33, para el árbol coloreado de la Figura <strong>17.</strong>32.<br />

9<br />

4<br />

15<br />

2<br />

5<br />

12<br />

20<br />

7<br />

Figura <strong>17.</strong>32. Árbol binario coloreado.<br />

En la representación con rojos en nivel horizontal, debe cuidarse que cada nodo tenga dos hijos,<br />

para que el árbol sea binario. En el par 4-9, el primero se considera rojo; y en el par 5-7 el<br />

segundo se considera rojo. La representación muestra que todas las hojas están en el mismo<br />

nivel.<br />

4<br />

9<br />

2<br />

5<br />

7<br />

12 15<br />

20<br />

Figura <strong>17.</strong>33. Coloreado con rojos horizontales.<br />

Luego los nodos que están unidos por horizontales se consideran pertenecientes a un nodo de un<br />

B-tree de grado dos, lo cual se muestra en la Figura <strong>17.</strong>34.<br />

4 9<br />

p 0<br />

p 1<br />

p 2<br />

2 5 7 12 15 20<br />

Figura <strong>17.</strong>34. B-tree de grado dos, equivalente del coloreado de la Figura <strong>17.</strong>32.<br />

Con esta interpretación pueden diseñarse las operaciones de inserción y descarte en árboles<br />

coloreados, agrupando las claves que pertenezcan a un nodo de un B-Tree y realizando las<br />

operaciones de mezcla y separación que se realizan en esta estructura, pero es preferible<br />

especializar las operaciones, debido a que la estructura interna de un nodo de un árbol coloreado<br />

es bastante más simple que la de un B-Tree.<br />

Profesor Leopoldo Silva Bijit 20-01-2010


20 Estructuras de Datos y Algoritmos<br />

<strong>17.</strong>8. Estructura de datos y funciones básicas.<br />

<strong>17.</strong>8.1. Estructura de datos.<br />

#define N 5 //2t-1 . t es el grado del B-tree<br />

#define eshoja 1<br />

#define esnodointerno 0<br />

typedef struct nn<br />

{<br />

int clave[N];<br />

struct nn *pn[N+1];<br />

int act;<br />

int hoja;<br />

} nodo, *pnodo;<br />

//con N claves en el Nodo<br />

//número de claves activas en el nodo<br />

// 1 es hoja; 0 en nodo interno<br />

<strong>17.</strong>8.2. Creación de un nodo.<br />

pnodo CreaNodo()<br />

{ int i;<br />

pnodo p=malloc(sizeof(nodo));<br />

if (p!=NULL)<br />

{ p->act=0;p->hoja=esnodointerno;<br />

for(i=0;ipn[i]=NULL;<br />

for(i=0;iclave[i]=0;<br />

}<br />

return(p);<br />

}<br />

<strong>17.</strong>8.4. Mostrar nodo y el B-Tree en niveles.<br />

void PrtNodo(pnodo p)<br />

{ int i;<br />

if(p->act==0) printf("Nodo vacío\n");<br />

else for(i=0; iact;i++) printf("%d ", p->clave[i]);<br />

//putchar('\n');<br />

}<br />

void PrtBtree(pnodo p, int level)<br />

{ int i;<br />

if (p!=NULL)<br />

{ for(i=1;ipn[0],level+1);<br />

for(i=1;iact+1;i++) PrtBtree(p->pn[i],level+1);<br />

}<br />

}<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 21<br />

<strong>17.</strong>8.5. Búsqueda de un valor.<br />

En casos prácticos el número de claves en un nodo es elevado, por lo que suele emplearse<br />

búsqueda binaria.<br />

int search(pnodo p, int valor)<br />

{ int i,l,r;<br />

while (p!=NULL)<br />

{<br />

l=0; r=p->act-1;<br />

while (r>=l) //búsqueda binaria<br />

{ i=(l+r)/2;<br />

if (valorclave[i]) r=i-1;<br />

if (valor>= p->clave[i]) l=i+1;<br />

}<br />

/* Si (valor < p->clave[0]) r=-1, l=0, (l-r)=1<br />

Si (valor > p->clave[p->act-1]) r=p->act-1, l=p->act, (l-r)=1<br />

Si Si (valor == p->clave[i]) r=i-1, l=i+1, (l-r)=2<br />

*/<br />

r++;<br />

/* Lo encontró en posición r. ( l-r=1 => l+1=r => l>r )<br />

Si no lo encontró: r=0 si (valor < p->clave[0])<br />

r=p->act si (valor > p->clave[p->act-1])<br />

*/<br />

if(l>r) return(1); //lo encontró en posición r del arreglo.<br />

else p=p->pn[r]; //busca en descendiente<br />

}<br />

return(0);//no lo encontró<br />

}<br />

<strong>17.</strong>8.6. Partir un nodo.<br />

//en la posición i-esima de x ingresa la clave central de y.<br />

//Pega el nuevo nodo z, en la posición (i+1) de x.<br />

void split(pnodo x, int i, pnodo y)<br />

{ int j;<br />

pnodo z = CreaNodo();<br />

if (z==NULL){printf("Error creación de nodo. Split"); exit(1);}<br />

z->hoja=y->hoja; z->act=N/2; //z es hermana de y. Y se le copian los (t-1) superiores de y.<br />

for(j=0;jclave[j]=y->clave[j+N/2+1];//copia claves en z<br />

if(y->hoja ==esnodointerno) //si no es hoja<br />

for(j=0;jpn[j]=y->pn[j+(N/2)+1];//copia punteros en z<br />

y->act=N/2; //se desactivan las claves de la mitad superior de y<br />

for(j=x->act+1;j>i ;j--) x->pn[j]=x->pn[j-1];//desplaza punteros en x<br />

x->pn[i+1]=z;<br />

Profesor Leopoldo Silva Bijit 20-01-2010


22 Estructuras de Datos y Algoritmos<br />

for(j=x->act;j>i ;j--) x->clave[j]=x->clave[j-1];//desplaza claves en x<br />

x->clave[i]=y->clave[N/2]; //asciende clave central del lleno<br />

x->act++;<br />

}<br />

<strong>17.</strong>8.7. Inserción en nodo que no está lleno.<br />

void insertenolleno(pnodo x,int valor)<br />

{ int i;<br />

if (x->hoja==eshoja)<br />

{ for(i=x->act-1;i>=0 && valor < x->clave[i];i--)<br />

x->clave[i+1]=x->clave[i];//crea un espacio<br />

//i apunta a clave menor que el valor<br />

x->clave[i+1]=valor;x->act++; //solo se inserta en hojas<br />

}<br />

else<br />

{ for(i=x->act-1;i>=0 && valorclave[i];i--); //búsqueda secuencial<br />

i++; //pn[i] apunta a la hoja donde debe insertarse. Ahora i es mayor o igual que cero<br />

if(x->pn[i]->act==N)<br />

{<br />

split(x,i,x->pn[i]);<br />

if(valor> x->clave[i])i++; //fija puntero en el descenso.<br />

}<br />

insertenolleno(x->pn[i],valor); //recursiva por el fondo<br />

}<br />

}<br />

<strong>17.</strong>9. Inserción.<br />

//Debe buscarse antes de insertar. Si la clave ya estaba, cambia B-Tree.<br />

void inserte(pnodo *pbt, int valor)<br />

{ pnodo p=*pbt,s;<br />

if (p ==NULL)<br />

{ p=CreaNodo();//si árbol vacío, crea la raíz<br />

if (p==NULL) {printf("Error creación de nodo raíz"); exit(1);}<br />

else {p->act=1;p->hoja=eshoja;p->clave[0]=valor;*pbt=p;}<br />

}<br />

else if(p->act==N)//nodo raíz lleno<br />

{ s=CreaNodo();if (s==NULL) {printf("Error creación de nueva raíz"); exit(1);}<br />

*pbt=s; s->hoja=esnodointerno; s->pn[0]=p;<br />

split(s,0,p);<br />

insertenolleno(s,valor);<br />

}<br />

else insertenolleno(p,valor);<br />

}<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 23<br />

<strong>17.</strong>10. Descartar.<br />

La función descartar puede descomponerse en funciones primitivas como desplazar a la derecha<br />

o izquierda y mezclar dos nodos. Se muestran expandidas, para evitar el llamado a funciones.<br />

int descartar(pnodo *pbt, int valor)<br />

{ int i,j,kp;<br />

pnodo y,z,c,x=*pbt;<br />

if(x==NULL) {printf("Error en descartar: Arbol vacío\n"); return(1);}<br />

if(x->hoja==eshoja)<br />

{//borrar valor;<br />

for(i=x->act-1;i>=0 && valor< x->clave[i];i--);<br />

//i es la clave mayor o igual al valor<br />

if( valor==x->clave[i] )<br />

{<br />

for(j=i;jact-1;j++) x->clave[j]=x->clave[j+1]; //mover claves en x;<br />

x->act--;<br />

if (debug) printf("Borrando %d en hoja\n", valor);<br />

if(x->act==0) //B-Tree queda vacío<br />

{ if (debug) printf("B-Tree queda vacío\n");<br />

*pbt=NULL;<br />

}<br />

return(0);<br />

}<br />

else {printf("Error en descartar: clave %d no existe\n",valor); return(1);}<br />

}<br />

else //no es hoja<br />

{<br />

for(i=x->act-1;i>=0 && valorclave[i];i--);<br />

//v está en x ssi:<br />

if( i>=0 && valor==x->clave[i] ) //valor está en x->clave[i]. i está entre 0 y x->cnt-1<br />

{ y=x->pn[i]; // y apunta al hermano izquierdo<br />

z=x->pn[i+1]; // z apunta al hermano derecho.<br />

if (y->act>N/2)<br />

{ kp=y->clave[(y->act)-1]; //mayor descendiente hijo izquierdo<br />

x->clave[i] =kp;<br />

if (debug) printf("Borrando con préstamo izquierdo en nodo %d\n",kp);<br />

descartar(&y,kp);<br />

}<br />

else if (z->act>N/2)<br />

{kp=z->clave[0]; //menor descendiente hijo derecho<br />

x->clave[i]=kp;<br />

if (debug) printf("Borrando con préstamo derecho en nodo %d\n",kp);<br />

descartar(&z,kp);<br />

}<br />

else //merge y con z<br />

{y->clave[y->act]=x->clave[i]; y->act++;<br />

Profesor Leopoldo Silva Bijit 20-01-2010


24 Estructuras de Datos y Algoritmos<br />

//copiar los de z a continuación en y;<br />

for(j=0;jact;j++) {y->clave[y->act+j]=z->clave[j];}<br />

if (y->hoja==esnodointerno)<br />

for(j=0;jact+1;j++) {y->pn[y->act+j]=z->pn[j];}//copia punteros<br />

y->act+=z->act;<br />

for(j=i;jact-1;j++) x->clave[j]=x->clave[j+1]; //mover claves en x;<br />

for(j=i;jact;j++) x->pn[j]=x->pn[j+1];//desplaza punteros en x<br />

x->act--;free(z);<br />

if(x->act==0) //B-Tree disminuye altura<br />

{free(x);<br />

if (debug) printf("Disminuye altura B-Tree\n");<br />

*pbt=y;<br />

}<br />

if (debug) printf("Borrando con fusión de derecho en nodo izquierdo %d\n",valor);<br />

descartar(&y,valor);<br />

}<br />

}<br />

else //valor está en un descendiente de x<br />

//pn[i] apunta a la página en la que está el valor, o cuyos descendientes contienen el valor.<br />

{i++; // ahora i es mayor o igual que cero<br />

c=x->pn[i];<br />

if(c->act==N/2) //nodo descendiente con claves mínimas<br />

{<br />

if(i==0) y=NULL; else y=x->pn[i-1]; //si c no tiene hermano izquierdo: y=NULL<br />

if(i==x->act) z=NULL; else z=x->pn[i+1]; //si c no tiene hermano derecho: z=NULL<br />

if(y!=NULL && y->act>N/2)<br />

{ for(j=c->act; j>0;j--) c->clave[j]=c->clave[j-1]; //mueve c a la derecha<br />

if(c->hoja==esnodointerno)<br />

for(j=c->act+1;j>0;j--) c->pn[j]=c->pn[j-1]; //mueve punteros de c a la derecha<br />

c->clave[0]=x->clave[i-1];//baja uno de x a c<br />

c->act++; //c queda con mas de N/2.<br />

x->clave[i-1]=y->clave[y->act-1]; //mayor de y lo sube a x<br />

c->pn[0]=y->pn[y->act]; //hijo de y se cuelga como hijo de c<br />

y->act--;<br />

if (debug)<br />

{ printf("Deja descendiente con más del mínimo\n");<br />

PrtBtree(btree,1);<br />

printf("Borrando %d en nodo descendiente con prestamo de izquierdo \n",valor);<br />

}<br />

descartar(&c,valor);<br />

}//y es nulo o y no tiene (t-1)<br />

else if (z!=NULL && z->act>N/2)<br />

{ c->clave[c->act]=x->clave[i];//baja central de x a c.<br />

c->act++; //c queda con mas de N/2.<br />

c->pn[c->act]=z->pn[0]; //pega menores de z a mayores del mayor de c<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 25<br />

x->clave[i]=z->clave[0]; //el menor de z lo sube a x.<br />

for(j=0;jact-1;j++) z->clave[j]=z->clave[j+1]; //mueve claves de z a la izquierda<br />

if (z->hoja==esnodointerno)<br />

for(j=0;jact;j++) z->pn[j]=z->pn[j+1];//mueve punteros de z a la izquierda<br />

z->act--;<br />

if (debug)<br />

{ printf("Deja descendiente con más del mínimo\n");<br />

PrtBtree(btree,1);<br />

printf("Borrando %d en nodo descendiente con préstamo de derecho \n",valor);<br />

}<br />

descartar(&c,valor);<br />

}<br />

else //merge<br />

{ if(y==NULL) //merge c con z;<br />

{ c->clave[c->act]=x->clave[i]; c->act++;<br />

for(j=0;jact;j++) {c->clave[c->act+j]=z->clave[j]; }<br />

if(c->hoja==esnodointerno)<br />

for(j=0;jact+1;j++) {c->pn[c->act+j]=z->pn[j]; }<br />

c->act+=z->act;<br />

//correr x (que no es hoja, tiene descendientes)<br />

for(j=i;jact-1;j++) x->clave[j]=x->clave[j+1]; //mover claves a la izquierda en x;<br />

for(j=i+1;jact;j++) x->pn[j]=x->pn[j+1];//desplaza punteros a la izquierda en x<br />

x->pn[i]=c;<br />

x->act--;<br />

if(x->act==0) //B-Tree disminuye altura<br />

{ free(x);<br />

*pbt=c;<br />

if (debug) printf("Disminuye altura\n");<br />

}<br />

free(z);<br />

if (debug)<br />

{ printf("mezcla c con z. Deja descendiente con más del mínimo por fusión\n");<br />

PrtBtree(btree,1);<br />

printf("Borrando %d en nodo descendiente con fusión de derecho \n",valor);<br />

}<br />

descartar(&c,valor);<br />

}<br />

else // merge c con y; Código es similar al del if.<br />

{<br />

y->clave[y->act]=x->clave[i-1]; y->act++;<br />

for(j=0;jact;j++) {y->clave[y->act+j]=c->clave[j]; }<br />

if (y->hoja==esnodointerno)<br />

for(j=0;jact+1;j++) {y->pn[y->act+j]=c->pn[j]; }<br />

y->act+=c->act;<br />

//correr x<br />

for(j=i-1;jact-1;j++) x->clave[j]=x->clave[j+1]; //mover claves en x;<br />

Profesor Leopoldo Silva Bijit 20-01-2010


26 Estructuras de Datos y Algoritmos<br />

for(j=i;jact;j++) x->pn[j]=x->pn[j+1];//desplaza punteros en x<br />

x->pn[i-1]=y;<br />

x->act--;<br />

if(x->act==0) //B-Tree disminuye altura<br />

{ free(x);<br />

*pbt=y;<br />

if (debug) printf("Disminuye altura\n");<br />

}<br />

free(c);<br />

if (debug)<br />

{ printf("mezcla c con y\n");<br />

PrtBtree(btree,1);<br />

printf("Borrando %d en nodo descendiente con fusión en izquierdo \n",valor);<br />

}<br />

descartar(&y,valor);<br />

}<br />

}<br />

}<br />

else //nodo descendiente con claves mayores que el número mínimo. ( >= t)<br />

{<br />

if (debug) printf("Borrando %d en nodo descendiente con más claves que el<br />

mínimo\n",valor);<br />

descartar(&c,valor);<br />

}<br />

}<br />

return(0); //finalizan recursiones por el fondo.<br />

}<br />

}<br />

<strong>17.</strong>11. Test de las funciones.<br />

pnodo btree=NULL;<br />

int main(void)<br />

{ int i;<br />

/* Test básico<br />

PrtNodo(btree);<br />

descartar(&btree,1);<br />

inserte(&btree,1);<br />

PrtNodo(btree);<br />

descartar(&btree,1);<br />

PrtNodo(btree);<br />

*/<br />

for(i=1;i0;i--) descartar(&btree,i);<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 27<br />

for(i=1;i0;i--) descartar(&btree,i);<br />

//test de búsquedas<br />

for(i=1;i


28 Estructuras de Datos y Algoritmos<br />

Índice general.<br />

CAPÍTULO <strong>17.</strong> ........................................................................................................................................... 1<br />

B-TREES. .................................................................................................................................................... 1<br />

<strong>17.</strong>1 DEFINICIÓN DE B-TREES DE GRADO T. .............................................................................................. 1<br />

<strong>17.</strong>2. CÁLCULO DE LA ALTURA DE UN B-TREE. ......................................................................................... 1<br />

<strong>17.</strong>3. REQUERIMIENTOS DE ESPACIO Y RELACIONES DE ORDENAMIENTO DE LAS CLAVES.......................... 3<br />

<strong>17.</strong>4. COMPLEJIDAD EN LA BÚSQUEDA. ..................................................................................................... 4<br />

<strong>17.</strong>5 ANÁLISIS DE LA OPERACIÓN INSERCIÓN. ........................................................................................... 5<br />

<strong>17.</strong>5.1 Ejemplo de inserción en un 2-4-Tree. ....................................................................................... 5<br />

<strong>17.</strong>5.2 Análisis de inserción en un B-Tree de grado t. ......................................................................... 7<br />

a) Árbol vacío. ................................................................................................................................................. 7<br />

b) Inserción en hoja con menos de (2t-1) claves. ............................................................................................. 7<br />

c) Inserción en nodo interno. ............................................................................................................................ 8<br />

c1) Si ancestro no está completo ................................................................................................................. 8<br />

c2) Si el ancestro de v, está completo. ......................................................................................................... 8<br />

c3) Si p es la raíz y está completa.............................................................................................................. 10<br />

<strong>17.</strong>5.3 Costo de la inserción. .............................................................................................................. 10<br />

<strong>17.</strong>6 ANÁLISIS DE LA OPERACIÓN DESCARTAR. ....................................................................................... 10<br />

<strong>17.</strong>6.1. Descarte en hoja con más claves que el mínimo número. ...................................................... 11<br />

<strong>17.</strong>6.2. Descarte en nodo p que no es hoja y que contiene la clave v. ............................................... 11<br />

Hijo izquierdo con más claves que la mínima. ............................................................................................... 12<br />

Hijo derecho con más claves que la mínima. ................................................................................................. 12<br />

Ambos hijos con número de claves mínimas. ................................................................................................ 13<br />

Nodo raíz con claves mínimas. ...................................................................................................................... 13<br />

Nodo raíz con una sola clave.......................................................................................................................... 14<br />

<strong>17.</strong>6.3. Descarte en nodo p que no es hoja y que no contiene la clave v. .......................................... 15<br />

Ancestro de v, tiene más de (t-1) claves. ........................................................................................................ 15<br />

Hermano izquierdo de ancestro de v, tiene más de (t-1) claves. ..................................................................... 15<br />

Hermano derecho de ancestro de v, tiene más de (t-1) claves. ....................................................................... 16<br />

Hermanos de ancestro de v, tienen (t-1) claves. ............................................................................................. 17<br />

Si existe el hermano izquierdo .................................................................................................................. 17<br />

Si no existe el hermano izquierdo. ............................................................................................................ 18<br />

<strong>17.</strong>6.4. Complejidad de la operación descarte. .................................................................................. 18<br />

<strong>17.</strong>7. ÁRBOLES COLOREADOS. ................................................................................................................. 18<br />

<strong>17.</strong>8. ESTRUCTURA DE DATOS Y FUNCIONES BÁSICAS. ............................................................................ 20<br />

<strong>17.</strong>8.1. Estructura de datos. .............................................................................................................. 20<br />

<strong>17.</strong>8.2. Creación de un nodo. ............................................................................................................ 20<br />

<strong>17.</strong>8.4. Mostrar nodo y el B-Tree en niveles. ..................................................................................... 20<br />

<strong>17.</strong>8.5. Búsqueda de un valor. ............................................................................................................ 21<br />

<strong>17.</strong>8.6. Partir un nodo. ....................................................................................................................... 21<br />

<strong>17.</strong>8.7. Inserción en nodo que no está lleno. ...................................................................................... 22<br />

<strong>17.</strong>9. INSERCIÓN. ..................................................................................................................................... 22<br />

<strong>17.</strong>10. DESCARTAR.................................................................................................................................. 23<br />

<strong>17.</strong>11. TEST DE LAS FUNCIONES. ............................................................................................................. 26<br />

REFERENCIAS. ......................................................................................................................................... 27<br />

Profesor Leopoldo Silva Bijit 20-01-2010


B-<strong>Trees</strong> 29<br />

ÍNDICE GENERAL. ................................................................................................................................... 28<br />

ÍNDICE DE FIGURAS. ................................................................................................................................ 29<br />

Índice de figuras.<br />

FIGURA <strong>17.</strong>1 B-TREE CON (T-1) CLAVES EN UN NODO. CADA NODO TIENE T HIJOS. ....................................... 1<br />

FIGURA <strong>17.</strong>2 B-TREE CON MÁXIMO NÚMERO DE CLAVES EN CADA NODO, CON T=4. ..................................... 2<br />

FIGURA <strong>17.</strong>3 ALTURA DE B-TREE CON T=4. .................................................................................................. 3<br />

FIGURA <strong>17.</strong>4 CLAVES MÁXIMAS Y MÍNIMAS ALMACENADAS EN B-TREE CON T=4. ....................................... 3<br />

FIGURA <strong>17.</strong>5 ESQUEMA DE B-TREE CON T=2. ................................................................................................ 4<br />

FIGURA <strong>17.</strong>6. B-TREE DESPUÉS DE INGRESAR LA CLAVE 4, 5 Y 7. ................................................................. 5<br />

FIGURA <strong>17.</strong>7. B-TREE DESPUÉS DE INGRESAR LA CLAVE 8, Y 10. .................................................................. 6<br />

FIGURA <strong>17.</strong>8. B-TREE DESPUÉS DE INGRESAR LA CLAVE 11, Y 13. ................................................................ 6<br />

FIGURA <strong>17.</strong>9. B-TREE DESPUÉS DE INGRESAR LA CLAVE 14. ......................................................................... 6<br />

FIGURA <strong>17.</strong>10 B-TREE DESPUÉS DE INGRESAR LA CLAVE 16. ........................................................................ 6<br />

FIGURA <strong>17.</strong>11 B-TREE DESPUÉS DE INGRESAR LA CLAVE <strong>17.</strong> ........................................................................ 6<br />

FIGURA <strong>17.</strong>12 B-TREE DESPUÉS DE INGRESAR LA CLAVE 25. ........................................................................ 7<br />

FIGURA <strong>17.</strong>13 B-TREE DESPUÉS DE INGRESAR LA CLAVE 26. ........................................................................ 7<br />

FIGURA <strong>17.</strong>14 INSERCIÓN EN HOJA QUE NO ESTÁ LLENA. .............................................................................. 8<br />

FIGURA <strong>17.</strong>15 DESPUÉS DE INSERTAR V EN HOJA QUE NO ESTABA LLENA. .................................................... 8<br />

FIGURA <strong>17.</strong>16 DESCENDER A UN NODO QUE ESTÁ COMPLETO. ...................................................................... 9<br />

FIGURA <strong>17.</strong>17 DESPUÉS DE PARTIR ANCESTRO DE V. ..................................................................................... 9<br />

FIGURA <strong>17.</strong>18 INSERCIÓN EN RAÍZ COMPLETA. ........................................................................................... 10<br />

FIGURA <strong>17.</strong>19 DESPUÉS DE INTENTAR INSERTAR EN RAÍZ COMPLETA. ........................................................ 10<br />

FIGURA <strong>17.</strong>20. HOJA CON MÁS DE (T-1) CLAVES. ........................................................................................ 11<br />

FIGURA <strong>17.</strong>21. NODO INTERNO CON MÁS DE (T-1) CLAVES, Y CLAVE CON HIJO IZQUIERDO Y DERECHO. ..... 12<br />

FIGURA <strong>17.</strong>21A. SE RECURRE A BORRAR EL PREDECESOR DE V. .................................................................. 12<br />

FIGURA <strong>17.</strong>21B. SE RECURRE A BORRAR EL SUCESOR DE V. ........................................................................ 13<br />

FIGURA <strong>17.</strong>22. MEZCLA DEL HIJO IZQUIERDO Y DERECHO. ......................................................................... 13<br />

FIGURA <strong>17.</strong>23. HIJOS CON CLAVES MÍNIMAS, RAÍZ CON DOS ELEMENTOS. .................................................. 14<br />

FIGURA <strong>17.</strong>24. FUSIÓN DE HIJOS. ................................................................................................................ 14<br />

FIGURA <strong>17.</strong>25. HIJOS CON CLAVES MÍNIMAS, RAÍZ CON UN ELEMENTO. ...................................................... 14<br />

FIGURA <strong>17.</strong>26. NUEVA RAÍZ, Y FUSIÓN DE HIJOS. ........................................................................................ 15<br />

FIGURA <strong>17.</strong>27. DESCARTE EN NODO INTERNO QUE NO CONTIENE LA CLAVE BUSCADA. .............................. 15<br />

FIGURA <strong>17.</strong>28. PRÉSTAMO DEL HERMANO IZQUIERDO. ............................................................................... 16<br />

FIGURA <strong>17.</strong>29. PRÉSTAMO DEL HERMANO DERECHO. .................................................................................. 17<br />

FIGURA <strong>17.</strong>30. FUSIÓN DEL ANCESTRO CON EL HERMANO IZQUIERDO. ....................................................... 17<br />

FIGURA <strong>17.</strong>31. FUSIÓN DEL ANCESTRO CON EL HERMANO DERECHO. ......................................................... 18<br />

FIGURA <strong>17.</strong>32. ÁRBOL BINARIO COLOREADO. ............................................................................................. 19<br />

FIGURA <strong>17.</strong>33. COLOREADO CON ROJOS HORIZONTALES............................................................................. 19<br />

FIGURA <strong>17.</strong>34. B-TREE DE GRADO DOS, EQUIVALENTE DEL COLOREADO DE LA FIGURA <strong>17.</strong>32. .................. 19<br />

Profesor Leopoldo Silva Bijit 20-01-2010

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!