Arboles resumen

26
Universidad de Guadalajara Centro Universitario de los Altos Estructura de Archivos Resumen sobre チrboles

Transcript of Arboles resumen

Page 1: Arboles resumen

Universidad de GuadalajaraCentro Universitario de los Altos

∞Estructura de Archivos ∞

Resumen sobre Árboles

Page 2: Arboles resumen

1

ÍndiceTeoría General de Árboles................................................................................................................... 3

Definiciones............................................................................................................................. 3

T D A Árboles de Búsqueda Binaria ..................................................................................................... 4

Representación Dinámica y Modelo Matemático del TDA Árbol ................................................... 7

Búsqueda..................................................................................................................................... 7

Insertar ........................................................................................................................................ 8

Recorridos ................................................................................................................................... 9

Recorrido En-Orden............................................................................................................... 10

Recorrido Pre-Orden ............................................................................................................. 10

Recorrido Post-Orden............................................................................................................ 11

Eliminar...................................................................................................................................... 11

Árboles Balanceados (AVL)................................................................................................................ 13

Implementación de Operaciones en Árboles AVL......................................................................... 15

Inserción en un AVL................................................................................................................... 15

Eliminación en un AVL............................................................................................................... 19

Rotaciones de un AVL................................................................................................................ 21

Rotación simple..................................................................................................................... 21

Rotación doble ...................................................................................................................... 22

Bibliografía ........................................................................................................................................ 25

Page 3: Arboles resumen

2

Índice de FigurasFigura 1: Ejemplo de Árbol .................................................................................................................. 3Figura 2: Árbol Binario......................................................................................................................... 5Figura 3: Árbol de Búsqueda Binaria ................................................................................................... 5Figura 4: Inserción en un árbol binario ............................................................................................... 8figura 5: Árboles AVL y no AVL .......................................................................................................... 14Figura 6: Inserción AVL, caso 1.......................................................................................................... 16figura 7: Inserción AVL, caso 2 .......................................................................................................... 16Figura 8: Inserción AVL, caso 3.......................................................................................................... 17Figura 9: Inserción AVL, caso 4.......................................................................................................... 17Figura 10: Eliminación en árbol AVL.................................................................................................. 20Figura 11: Rotación simple AVL......................................................................................................... 22Figura 12: Rotación doble AVL .......................................................................................................... 23

Índice de CódigosCuadro 1: Creación de un nodo en árbol binario ................................................................................ 6Cuadro 2: Código en C de la función Buscar ....................................................................................... 8Cuadro 3: Código en C de la función insertar...................................................................................... 9Cuadro 4: Recorrido en-orden .......................................................................................................... 10Cuadro 5: Recorrido en pre-orden .................................................................................................... 11Cuadro 6: Recorrido en post-orden .................................................................................................. 11Cuadro 7: Función eliminar ............................................................................................................... 12Cuadro 8: Función reemplazar .......................................................................................................... 13Cuadro 9: Estructura de un nodo AVL............................................................................................... 14Cuadro 10: Código de inserción AVL ................................................................................................. 18Cuadro 11: Código de eliminación AVL ............................................................................................. 20Cuadro 12: Rotaciones ...................................................................................................................... 23

Page 4: Arboles resumen

3

Teoría General de Árboles

En la ciencia de la computación definimos un árbol como un conjunto denodos y líneas. Un nodo es un elemento de información que reside en el árbol. Una líneaes un par de nodos ordenado (u, v), y a la secuencia de líneas se le denomina ruta (path).

Podemos citar muchos ejemplos de datos que en la vida real se encuentran comoestructuras de árbol. Debido a que pueden servir como fundamento para modelarmúltiples clases de problemas, los árboles se han convertido en un tema de estudiosignificativo en la ciencia de la computación. Como veremos, podemos usarlos parabuscar, ordenar y dar prioridad a los datos.

Definiciones

Figura 1: Ejemplo de Árbol

Antes de que prosigamos nuestro estudio de los árboles, debemos definir variostérminos fundamentales. (Todos los ejemplos se refieren a la figura 1)

El término nodo, que ya usamos en capítulos anteriores, continúa indicando unelemento, o ítem, de información. Los nodos terminales son los nodos hoja del árbol (J, K,L, M, N). Denominamos a todos los demás nodos (internos) no terminales (A, B, C, D, E).

Para un nodo específico (digamos, B), los nodos raíz de sus subárboles (D, E) sonsus hijos. Si extendemos la analogía, B se considera el padre y los hijos, respecto uno delotro, son hermanos. En términos generales, un nodo puede tener una cantidad infinita dehijos; en la práctica, sin embargo, casi siempre limitamos esa cifra.

Definimos el grado de un nodo como la cantidad de subárboles (hijos) que tiene.Por ejemplo, el nodo A tiene el grado 2, el C, 4 y el J, 0. Todos los nodos con grado 0 sonterminales; los que tienen un grado mayor que cero son no terminales.

Page 5: Arboles resumen

4

La fila en la que reside un nodo es su nivel. Por definición, el nodo raíz (A) está enel nivel 1. Sus hijos, B y C, están en el nivel 2, del nodo D al I están en el nivel 3.

La altura de un árbol se define como la cantidad de líneas en una ruta que empiezaen la raíz y termina en el nodo hoja más lejana; la altura de un árbol con un solo nodo (laraíz) es 0. Por extensión, la altura de cualquier nodo de un árbol es la altura de la ruta máslarga que va desde ese nodo hasta un nodo hoja. La profundidad de un nodo es lacantidad de líneas en la ruta de la raíz a ese nodo. Un bosque es un conjunto de ceroárboles, o mejor dicho, desunidos. Por ejemplo, si elimináramos el nodo raíz de un árbol,el resultado sería un bosque.

Podemos ver al árbol como una forma especial de lista. Por poner un caso, observeel árbol que se muestra en la figura 1. Podríamos utilizar la notación de lista pararepresentarlo de este modo:

(A, (B, C, (D, (J, K), E, (L, M, N)), C, (F, G, H, I)))

Representamos cada subárbol como una sublista. Comenzamos con la lista (A), querepresenta el nodo raíz del árbol. Cuando añadimos una sublista de dos hijos de A, la listase vuelve (A (B, C)). Luego agregamos otra sublista con los nodos D y E para producir lalista (A (B, (D, E), C)). Al añadir un hijo a D, obtenemos (A, (B, (D, (J, K), E), C)). Asícontinuamos hasta que añadimos todos los nodos del árbol a la lista. Este tipo derepresentación es flexible porque nos permite mantener varios números de hijos por cadapadre.

No obstante, tiene un inconveniente: no se puede acceder directamente a los hijosdesde sus padres; esto es, tenemos que hacer una búsqueda lineal mediante una sublista.En casi ningún programa de computadora es deseable utilizar tiempo adicional para hacerbúsquedas. Pero si limitamos la cantidad de nodos hijo que puede haber, podemosimplementar árboles de un modo más eficiente.

T D A Árboles de Búsqueda Binaria

Los árboles binarios son una forma restringida de árbol. Cada nodo, la raízinclusive, puede tener un máximo de dos hijos. En la figura 2 se muestra un ejemplo.

Page 6: Arboles resumen

5

Figura 2: Árbol Binario

De modo formal, definimos un árbol binario como: un conjunto finito(posiblemente vacío) de nodos, uno de los cuales se denomina raíz. El nodo raíz puedetener un máximo de dos subárboles, cada uno de los cuales es, también, un árbol binario.Los dos subárboles de un nodo están ordenados, así que los llamamos hijo izquierdo e hijoderecho, respectivamente.

Una de las características de este tipo de árbol es aquel que dado un nodo, todoslos datos del subárbol izquierdo son menores que los datos de ese nodo, mientras quetodos los datos del subárbol derecho son mayores que sus propios datos, llamándose asíárbol de búsqueda binaria (figura 3).

Figura 3: Árbol de Búsqueda Binaria

Creación de un árbol binario de búsquedaSupongamos que se desea almacenar los números 8 3 1 20 10 5 4 en un árbol

binario de búsqueda. Siguiendo la regla, dado un nodo en el árbol todos los datos a suizquierda deben ser menores que todos los datos del nodo actual, mientras que todos losdatos a la derecha deben ser mayores que los datos. Inicialmente el árbol está vacío y sedesea insertar el 8. La única elección es almacenar el 8 en la raíz:

8

Page 7: Arboles resumen

6

A continuación viene el 3, ya que 3 es menor que 8, el 3 debe ir en el subárbolizquierdo:

A continuación se ha de insertar 1 que es menor que 8 y que 3, por consiguiente iráa la izquierda y debajo de 3:

El siguiente número es 2 0, mayor que 8, lo que implica debe ir a la derecha de 8:

Cada nuevo elemento se inserta como una hoja del árbol. Los restantes elementosse pueden situar fácilmente:

Cuadro 1: Creación de un nodo en árbol binario

Nodo* crearNodo (int id, cons char* n){

Nodo* t;t = (Nodo*) malloc(sizeof(Nodo));t -> nummat = id;strcpy(t -> nombre, n);t -> izdo = t -> dcho = NULL;return t;

}

Page 8: Arboles resumen

7

Representación Dinámica y Modelo Matemático del TDA Árbol

De lo antes mencionado se deduce que los árboles binarios tienen naturalezarecursiva y, en consecuencia las operaciones sobre los árboles son recursivas, si biensiempre se tiene la opción de realizarlas de forma iterativa.

Estas operaciones son: Búsqueda de un nodo. Inserción de un nodo. Recorrido de un árbol. Borrado (eliminación) de un nodo.

BúsquedaLa búsqueda de un nodo comienza en el nodo raíz y sigue estos pasos:1. La clave buscada se compara con la clave del nodo raíz.2. Si las claves son iguales, la búsqueda se detiene.3. Si la clave buscada es mayor que la clave raíz, la búsqueda se reanuda en el

subárbol derecha Si la clave buscada es menor que la clave raíz, la búsqueda sereanuda con el subárbol izquierdo.

Si se desea encontrar un nodo en el árbol que contenga una informacióndeterminada, la función buscar () tiene dos parámetros, un puntero al árbol y el datoque se busca.

Como resultado, la función devuelve un puntero al nodo en el que se almacena lainformación; en el caso de que información no se encuentre se devuelve el valor 0. Elalgoritmo de búsqueda es el siguiente:

1. Comprobar si el árbol está vacío. En caso afirmativo se devuelve 0. Si la raízcontiene el dato buscado, la tarea es fácil: el resultado es, simplemente, unpuntero a la raíz.

2. Si el árbol no está vacío, el subárbol específico depende de que datorequerido sea más pequeño o mayor que el dato del nodo raíz.

3. La función de búsqueda se consigue llamando recursivamente a la funciónbuscar () con un puntero al subárbol izquierdo o derecho comoparámetro.

Page 9: Arboles resumen

8

Cuadro 2: Código en C de la función Buscar

Nodo* buscar (Nodo* raiz, TipoElemento buscado){

if (!raiz)return 0;

else if (buscado == raiz -> dato)return raiz;

else if (buscado < raiz -> dato)return buscar(raiz -> izdo, buscado);

elsereturn buscar (raiz -> dcho, buscado) ;

}

InsertarUna característica fundamental que debe poseer el algoritmo de inserción es que

el árbol resultante de una inserción en un árbol de búsqueda ha de ser también debúsqueda. En esencia, el algoritmo de inserción se apoya en la localización de unelemento, de modo que si se encuentra el elemento (clave) buscado, no es necesariohacer nada; en caso contrario, se inserta el nuevo elemento justo en el lugar donde haacabado la búsqueda (es decir, en el lugar donde habría estado en el caso de existir).

Figura 4: Inserción en un árbol binario

La función insertar () que inserta nuevos nodos es sencilla. Se deben declarardos argumentos, un puntero a la raíz del árbol y el dato que tendrá el nodo. La funcióncreará un nuevo nodo y lo inserta en el lugar correcto en el árbol de modo que el árbolpermanezca como binario de búsqueda.

La operación de inserción de un nodo es una extensión de la operación debúsqueda. Los pasos a seguir son:

1. Asignar memoria para una nueva estructura nodo.2. Buscar en el árbol para encontrar la posición de inserción del nuevo nodo, que

se colocará como nodo hoja.3. Enlazar el nuevo nodo al árbol.

Page 10: Arboles resumen

9

Cuadro 3: Código en C de la función insertar

void insertar (Nodo** raiz, TipoElemento dato){

if (!(*raiz))*raiz = crearNodo(dato);

else if (dato < (*raiz) -> dato)insertar(&((*raiz) -> izdo), dato);

elseinsertar (&((*raiz) -> dcho), dato);

}

Si el árbol está vacío, es fácil insertar la entrada en el lugar correcto. El nuevo nodoes la raíz del árbol y el puntero raiz se pone apuntando a ese nodo. El parámetro raiz debeser un parámetro referencia ya que debe ser leído y actualizado, por esa razón se declarapuntero a puntero (Nodo**). Si el árbol no está vacío, se debe elegir entre insertar elnuevo nodo en el subárbol izquierdo o derecho, dependiendo de que el dato sea máspequeño o mayor que el dato en la raíz del árbol.

La función crearNodo () reserva memoria para el nuevo nodo y asigna el nuevodato. Esta función se debe adaptar a cada aplicación.

Recorridos

Después de haber construido un árbol binario, deseamos procesar (imprimir, pordecir algo) los valores de los datos que guarda dentro, es decir, queremos movernos por elárbol, visitando cada nodo una sola vez. Clasificamos este tipo de algoritmo comorecorrido (trasversal).

No obstante, como se presenta, esta idea resulta demasiado general, tenemos quedefinirla mejor. Piense que cuando nos colocamos en cualquier nodo, una función derecorrido puede:

Proseguir hacia abajo por el subárbol izquierdo. Proseguir hacia abajo por el subárbol derecho. Procesar (es decir, visitar) los datos.

Para simplificar las cosas, adoptaremos la convención de que siemprerecorreremos el subárbol izquierdo antes que el derecho, pero esto aún plantea el dilemade cuándo debemos procesar los datos. Nuestras posibilidades son:

Visitar el nodo antes de movernos hacia abajo por el subárbol izquierdo. Visitar el nodo después de recorrer el subárbol izquierdo pero antes de

recorrer el derecho. Visitar el nodo después de recorrer los dos subárboles.

Page 11: Arboles resumen

10

Estos tres métodos de recorrido tienen la misma importancia, y losdenominaremos con los nombres de pre-orden, en-orden y post-orden, respectivamente.

Recorrido En-Orden

Empecemos por describir el recorrido en-orden (morder), al que a veces se le llamaorden simétrico. De modo informal, el recorrido en-orden necesita que:

1. Nos movamos por el árbol hacia abajo a la izquierda tan lejos como podamos.2. Visitemos el nodo actual.3. Regresemos un nodo del árbol y lo visitemos.4. Nos movamos abajo a la derecha del subárbol del nodo que visitamos en el

paso tres, si lo tiene y si no lo hemos visitado antes; de otro modo,regresaremos un nodo.

5. Repitamos los pasos uno a cuatro hasta haber procesado todos los nodos.

El procedimiento en_orden (), que se muestra en el cuadro 4, ilustra estospasos.

La función trabaja de este modo: se mueve de forma recursiva hacia abajo por elsubárbol izquierdo hasta que se coloca en un nodo hoja; imprime el valor de ese nodo yluego intenta moverse hacia abajo por el subárbol derecho; después regresa al nivelanterior y repite este proceso.

Cuadro 4: Recorrido en-orden

void en_orden( struct nodo_ab *nodos ){

if( nodos ¡= NULL ){en_orden( nodos->hijo_izq );imprime_nodos( nodos->datos ); /* Visita */en_orden( nodos->hijo_der );

}}

Recorrido Pre-Orden

En el recorrido en pre-orden, visitamos los datos antes de recorrer el subárbolizquierdo. La función preorden (), que se muestra en el cuadro 5, es un ejemplo deesto.

Observe que esta función llama a imprime_nodo () antes de invocar a algunade sus llamadas recursivas.

Page 12: Arboles resumen

11

Cuadro 5: Recorrido en pre-orden

void preorden( struct nodo_ab *nodos ){

if( nodos != NULL ){imprime_nodos(nodos->datos ); /* Visita */preorden( nodos->hijo_izq );preorden( nodos->hijo_der );

}}

Recorrido Post-Orden

El recorrido en post-orden hace la visita después de dos llamadas recursivas. Elcódigo de la función posorden () se muestra en el cuadro 6.

Cuadro 6: Recorrido en post-orden

void posorden( struct nodo_ab *nodos ){

if( nodos != NULL ){posorden( nodos->hijo_izq );posorden( nodos->hijo_der );imprime_nodos( nodos->datos ); /* Visita */

}}

Eliminar

La operación de eliminación de un nodo es también una extensión de la operaciónde búsqueda, si bien más compleja que la inserción debido a que el nodo a suprimir puedeser cualquiera y la operación de supresión debe mantener la estructura de árbol binariode búsqueda después de la eliminación.

Los pasos a seguir son:1. Buscar en el árbol para encontrar la posición de nodo a eliminar.2. Reajustar los punteros de sus antecesores si el nodo a suprimir tiene menos de

2 hijos, o subir a la posición que éste ocupa el nodo más próximo en valor delcampo clave (inmediatamente superior o inmediatamente inferior) con objetode mantener la estructura de árbol binario.

Page 13: Arboles resumen

12

La función eliminar () (Cuadro 7) presenta dos casos claramente diferenciados.El primero, si el nodo a eliminar es una hoja o tiene un único descendiente, resulta unatarea fácil, ya que lo único que hay que hacer es asignar al enlace del nodo padre (según elcamino de búsqueda) el descendiente del nodo a eliminar.

El segundo caso, que el nodo tenga las dos ramas no vacías; en cuyo caso paísmantener la estructura de árbol de búsqueda se pueden seguir dos alternativas:

Reemplazar el dato del nodo por la menor de las claves mayores en su subárbolderecho.

Reemplazar el dato del nodo por la mayor de las claves menores en su subárbolizquierdo

Cuadro 7: Función eliminar

void eliminar (Nodo** r, TipoElemento dato){

if (!(*r))puts ("Nodo no encontrado!!");

else if (dato < (*r) -> dato)eliminar(&(*r) -> izdo, dato);

else if (dato > (*r) -> dato)eliminar(&(*r) -> dcho,dato);

else /* Nodo encontrado */{

Nodo* q;q = (*r);if (q -> izdo == NULL)

(*r) = q -> dcho;else if (q -> dcho == NULL)

(*r) = q -> izdo;else{

reemplazar(&q);}free(q);

}}

Se elige la segunda alternativa. Para lo cual, como las claves menores están en larama izquierda, se baja al primer nodo de la rama izquierda, y como la clave mayor estáen la rama derecha, se continúa bajando por la rama derecha hasta alcanzar el nodo hoja.

Éste es el mayor de los menores que reemplaza a la clave del nodo a eliminar. Lafunción reemplazar () (Cuadro 8) realiza la tarea descrita.

Page 14: Arboles resumen

13

Cuadro 8: Función reemplazar

void reemplazar(Nodo** act){

Nodo* a, *p;

p = *act;a = (*act) -> izdo;while (a -> dcho){

p = a;a = a -> dcho;

}(*act) -> dato = a -> dato;if (p == (*act))

p -> izdo = a -> izdo;else

p -> dcho = a -> izdo;(*act) = a;

}

Árboles Balanceados (AVL)

Es muy fácil implementar esta clase de árboles, pero pueden plantear uninconveniente: el peor caso de tiempo de ejecución de O(n). Un árbol binario ordenadopuede degradarse hasta el nivel de una lista lineal si la rutina de inserción recibeelementos en orden ascendente (o casi ascendente).

Se han desarrollado varios métodos para prevenir que los árboles resultensesgados. A algunos de los más poderosos se les llama árboles AVL (siglas que provienende los nombres de los científicos que los estudiaron primero: Adel’son-Vel’skii y Landis).

Antes de que podamos entender los árboles AVL, tenemos que definir lo quesignifica equilibrado (balanced). Antes, definamos qué es la altura de un nodo n:

0,

_1 _si n no tiene hijo izquierdo

altura izquierda naltura hijo derecho n para todos los demás nodos

0,

_1 _si n no tiene hijo derecho

altura derecha naltura hijo derecho n para todos los demás nodos

Debe recordar que la altura de cualquier nodo en un árbol es la longitud de la rutamás larga que hay de ese nodo a un nodo hoja. Con base en las definiciones anteriores, unnodo hoja tiene altura__derecha y altura_izquierda iguales a cero.

Page 15: Arboles resumen

14

Definamos ahora el equilibrio de algún nodo n como:equilibrio (n) = altura_derecha(n) — altura_izquierda(n)

Por tanto, el equilibrio de un nodo señala la altura relativa de su subárbol derechoen comparación con el izquierdo. Si ese equilibrio es positivo, el subárbol derecho tienemayor profundidad que el izquierdo; si es negativo, al revés.

Cuadro 9: Estructura de un nodo AVL

struct nodo_avl{

int bal;int datos;struct nodo_avl *hijo_izq;struct nodo_avl *hijo_der;

}

Un árbol binario es un árbol AVL si y sólo si cada uno de sus nodos tiene unequilibrio de -1, 0, o +1. En la figura 5 se muestran algunos ejemplos de árboles AVL y noAVL.

0

0 0

1

0 -1

0

00 0 1 1

0 0

1 2

0 0 0 0 1 0

0 0

Árboles AVL

2

0 1

0

0 0 1 2

0 0 -1

0

1 0

0 0

-20

-11 0

00 0

Árboles no AVL

figura 5: Árboles AVL y no AVL

Los árboles AVL poseen varios atributos que los hacen muy adecuados paraprogramas de búsqueda. Primero, porque un árbol AVL con n nodos tiene una altura de

Page 16: Arboles resumen

15

O(log2*n). Segundo, porque podemos insertar y eliminar nodos con una eficacia deO(log2*n), mientras conservamos las propiedades AVL del árbol.

Implementación de Operaciones en Árboles AVL

Al igual que en los árboles de búsqueda binaria, en este tipo de árboles también sepueden realizar diversas operaciones, las cuales son:

Inserción. Eliminación. Rotaciones.

Inserción en un AVL

Como un árbol AVL es, en esencia, un árbol binario, podemos volver a emplearnuestra estructura de nodos. Sin embargo, debemos añadir un campo que almacene elequilibrio. Como sólo hay tres valores para equilibrar, necesitamos dos bits de espacio dealmacenamiento para este elemento de datos. No obstante, con el propósito de serclaros, implementaremos este campo como un entero (int) completo. En el cuadro 9 seincluye la nueva estructura de nodos AVL.

Desde el punto de vista conceptual, insertamos nodos nuevos en un árbol AVL dela siguiente forma:

1. Usamos el mismo algoritmo que empleamos para insertar un nodo en unárbol binario ordenado; esto es, trazamos una ruta desde el nodo raíz hastaun nodo hoja (donde haremos la inserción).

2. Insertamos el nodo nuevo.3. Volvemos a trazar la ruta de regreso al nodo raíz, ajustando el equilibrio a

lo largo de ella.4. Si el equilibrio de un nodo llega a ser ±2, volvemos a ajustar los subárboles

de los nodos para que su equilibrio se mantenga acorde con loslineamientos AVL (que son ±1).

Es evidente que el paso cuatro es el más difícil. Específicamente, debemos decidirsi es posible volver a ajustar la descendencia de un nodo de tal modo que todos losequilibrios se apeguen a los lineamientos AVL. Podemos descomponer este problema encuatro casos diferentes (y sus contrapartes).

Caso 1. Un nodo llega a estar equilibrado como resultado de una inserción. Como seilustra en la figura 6, el equilibrio del nodo t disminuye de 1 a 0 como resultado dela inserción del nodo n en el árbol. No hay motivo para volver a ajustar ladisminución del nodo t porque la altura general del árbol no ha cambiado.

Page 17: Arboles resumen

16

Figura 6: Inserción AVL, caso 1

Caso 2. Un nodo se desequilibra sólo con ±1. Como se muestra en la figura 7, el equilibriodel nodo t cambia de 0 a +1 debido a la inserción. Observe que la altura del árbolse incrementa. Por tanto, también debemos ajustar el equilibrio del nodo r.

figura 7: Inserción AVL, caso 2

Caso 3. En este caso, un nodo se desequilibra en ± 2 porque el subárbol derecho de su hijoderecho incrementa su altura. Por ejemplo, cuando insertamos un elemento nuevoen el árbol descrito en la figura 8a, creamos el árbol que se muestra en la figura 8b.Observe cómo el equilibrio del nodo a se incrementa de +1 a +2.

Por desgracia, no podemos volver a ajustar el equilibro con sólo intercambiar losnodos b y e. Esta solución estropea el orden apropiado del árbol.

Sin embargo, como se ilustra en la figura 8c, podemos hacer de a el hijo izquierdode c y volver a colocar el hijo izquierdo de c (el nodo d) como hijo derecho del reciéncolocado nodo a. Denominamos a este tipo de transformación rotación sencilla a laizquierda (single left rotation).

Hay varios puntos importantes que debemos señalar respecto del proceso detransformación:

Conserva el orden apropiado del árbol. Restablece todos los nodos a equilibrios apropiados AVL.

Page 18: Arboles resumen

17

Conserva el recorrido en-orden del árbol, es decir, se accederá a los nodos conun recorrido en orden, en el mismo orden (valga la tautología) después deocurrida la transformación (como hubiera ocurrido antes de ésta).

Sólo necesitamos modificar tres apuntadores para lograr de nuevo el equilibrio.

Hay un caso de imagen de espejo (invertida) en el que un nodo se desequilibra en -2 porque el subárbol izquierdo de su hijo izquierdo incrementa su altura. En este casovolvemos a equilibrar el árbol con una rotación sencilla a la derecha equivalente.

Figura 8: Inserción AVL, caso 3

Caso 4. Un nodo se desequilibra en ± 2 porque el subárbol derecho de su hijo izquierdoaumenta su altura. Como se ilustra en las figuras 9a y 9b, cuando insertamos elnodo nuevo, n, como hijo derecho del nodo d, el equilibrio del nodo a aumenta a+2.

1

0 0

0 0

+2

0 -1

0 1

0

aa

(b)(a)

b b

d d

c c

e

N

Figura 9: Inserción AVL, caso 4

Page 19: Arboles resumen

18

Cuadro 10: Código de inserción AVL

struct nodo_avl{

int bal;int datos;struct nodo_avl *hijo_izq;struct nodo_avl *hijo_der;

};

struct nodo_avl *raiz = NULL;#define NO 0#define YES 1

#define BAL 0#define ALTURA_I -1#define ALTURA_D 1

struct nodo_avl *inser_avl( struct nodo_avl *raiz, struct nodo_avl *new,

int *cambia_alt ){

if( raiz == NULL ){raiz = new;raiz->bal = BAL;raiz->hijo_izq = NULL;raiz->hijo_der = NULL;*cambia_alt = YES;

} else if( new->datos < raiz->datos ){ /* Inserta a la izquierda */raiz->hijo_izq = inser_avl( raiz->hijo_izq, new, cambia_alt );if( *cambia_alt ){ /* Crece HIJ0_I *1

if( raiz->bal == ALTURA_I ) /* El nodo mide ahora 2 */raiz = bal_izq( raiz, cambia_alt );

else if ( raiz->bal == BAL )/* El nodo mide ahora AL1URA_I */raiz->bal = ALTURA_I;

else { /* Era ALT0RA_D ahora es BAL */raiz->bal = BAL; *cambia_alt = NO;

}} else { /* Inserta a la derecha */

raiz->hijo_der = inser_avl( raiz->hijo_der, new, cambia_alt );if( *cambia_alt ){ /* HIJO_DER crece */

if( raiz-> bal == ALTURAI ){ /* Era ALTURAI ahora es BAL */raiz->bal = BAL;*cambia_alt = NO;

} else if( raiz->bal == BAL ) /* El nodo mide ahora ALTURA_D*/raiz->bal = ALTURA X;

else /* El nodo mide ahora 2raiz = bal_der( raiz, cambia_alt );

}}return( raiz );

}

Page 20: Arboles resumen

19

Eliminación en un AVL

La eliminación de nodos en árboles AVL indica que sigamos los mismos pasosfundamentales que ya revisamos para la inserción. Específicamente, debemos hacerrotaciones sencillas y dobles.

Comenzamos una eliminación AVL siguiendo el algoritmo de eliminación para unárbol binario ordenado. Después, tras localizar el nodo que queremos eliminar, seguimoseste procedimiento:

1. Si el nodo es un nodo hoja, simplemente lo eliminamos.

2. Si el nodo sólo tiene un hijo, lo sustituimos con su hijo (es decir, hacemos queel apuntador se dirija al hijo).

3. Si el nodo eliminado tiene dos hijos, lo sustituimos con (una copia de) susucesor en-orden; luego eliminamos el (la copia original del) sucesor en- orden.Este ejemplo se ilustra comenzando en la figura 10e. Observe que esteprocedimiento conserva el orden apropiado del árbol. Ahora que hemoseliminado el nodo, tenemos que volver a equilibrar el árbol.

4. Si el equilibrio del padre del nodo eliminado cambia de 0 a ±1 (fig. 10b), elalgoritmo concluye, es decir, el árbol no necesita que lo volvamos a equilibrar.

5. Si el padre del nodo eliminado cambia de ±1 a 0 (fig. 10c), la altura del árbol hacambiado y se afectó el equilibrio del abuelo del nodo eliminado.

6. Si el equilibrio del padre del nodo eliminado cambia de ±1 a ±2 {véanse figs.10e y 10f), estamos forzados a hacer una rotación. Después de concluirla, elequilibrio del padre podría cambiar, lo que, a su vez, podría forzarnos a hacerotros cambios (y probables rotaciones) en toda la ruta hacia arriba a medidaque ascendemos hacia la raíz. De hecho, debemos volver a trazar la ruta hastaque encontremos un nodo que cambie de 0 a 1; entonces podemos terminar elalgoritmo (como se describió en el paso 4).

Aun en el peor caso, cuando una eliminación obliga a hacer rotaciones O(log2*n), lacomplejidad del algoritmo permanece en O(log2*n). Esto se debe a que podemos hacerrotaciones en un lapso constante. Se le deja a usted la tarea de terminar laimplementación.

Page 21: Arboles resumen

20

+1

0 -1

-1 0

a

Árbol Original(a)

b

f

c

0 0d e g

0h

+1

+1 -1

-1 0

a

Resultado de eliminar el nodo(b)

b

f

c

0e g

0h

0

0 0

0 0

a

Resultado de eliminar el nodo(c)

b

h

c

0 0d e g

0

0 0

0 0

a

Resultado de eliminar el nodo(d)

b

f

c

0 0d e g

+1

0 -2

-1

0

a

Eliminación del nodo c, fase 1(e)

b

f

c

0 0d e

h

0

0 0

0 0

a

Eliminación del nodo c, fase 2(f)

b

h

f

0 0d e g

Figura 10: Eliminación en árbol AVL

Cuadro 11: Código de eliminación AVL

void borrarBalanceado (Nodo** raiz, TipoElemento clave,int* cambiaAltura)

{if (!(*raiz)){

puts("!! Nodo no encontrado !!");*cambiaAltura = 0;

}else if (clave < (*raiz) -> dato){

borrarBalanceado(&((*raiz) -> izdo), clave, cambiaAltura);

Page 22: Arboles resumen

21

if (*cambiaAltura)equilibrarl(raiz,cambiaAltura);

}else if (clave > (*raiz) -> dato){

borrarBalanceado(&((*raiz) -> dcho), clave, cambiaAltura);if (*cambiaAltura)

equilibrar2(raiz,cambiaAltura);}else /* Nodo encontrado */{

Nodo* q; /* puntero al nodo a suprimirq = (*raiz);if (q -> izdo == NULL){

(*raiz) = q -> dcho;*cambiaAltura = 1;

}else if (q -> dcho == NULL){

(*raiz) = q -> izdo;*cambiaAltura = 1;

}else{ /* tiene rama izquierda y derecha */

reemplazar(&q,&(q -> izdo),cambiaAltura);if (*cambiaAltura)

equilibrar1(raiz, cambiaAltura);}free(q);

}}

Rotaciones de un AVLUna vez que se ha insertado un nodo en un árbol de búsqueda equilibrado, el

proceso de regreso termina cuando se llega a la raíz del árbol, o cuando se realiza lareestructuración en un nodo del mismo; en cuyo caso no es necesario determinar el factorde equilibrio de los restantes nodos, debido a que dicho factor queda como el que teníaantes de la inserción, ya que el efecto de la reestructuración hace que no aumente laaltura.

La violación del factor de equilibrio se resuelve con una reestructuración en la quese realiza un desplazamiento particular de los nodos implicados, también denominadorotación de los nodos. Se distingue entre rotación simple y rotación doble.

Rotación simpleLa rotación simple resuelve la violación del equilibrio de un nodo izquierda-

izquierda, simétrica a la derecha-derecha. El árbol de la Figura 11a tiene el nodo c con

Page 23: Arboles resumen

22

factor de equilibrio -1; el árbol de la Figura 11b es el resultado de insertar el nodo a.Resulta que ha crecido la altura de la rama izquierda, es un desequilibrio izquierda-izquierda que se resuelve con una rotación simple, que en este caso se puede denominarrotación n. La Figura 11d es el árbol resultante de la rotación, en el que el nodo b se haconvertido en la raíz, el nodo c su rama derecha y el nodo a continúa como ramaizquierda. Con estos movimientos el árbol sigue siendo de búsqueda y se equilibra.

Figura 11: Rotación simple AVL

Rotación dobleCon los movimientos de punteros que se realizan en la rotación simple no es

posible resolver todos los casos de violación del criterio de equilibrio.

En la Figura 12a se observa un árbol de búsqueda desequilibrado, con factores deequilibrio +2, -1 y 0. La Figura 12b aplica la rotación simple, rotación DD.

La única solución consiste en subir el nodo 40 como raíz del subárbol, como ramaizquierda situar al nodo 30 y como rama derecha el nodo 60, la altura del subárbolresultante es la misma que antes de insertar. Se ha realizado una rotación doble, derecha-izquierda, en la que intervienen los tres nodos.

Page 24: Arboles resumen

23

Figura 12: Rotación doble AVL

A continuación se escribe el código en C de los cuatro tipos de rotaciones:

Cuadro 12: Rotaciones

void rotacionll(Nodo** n, Nodo* ni){

(*n) -> izdo = ni -> dcho;ni -> dcho = (*n);

/* actualización de los factores de equilibrio */if (ni -> fe == -1) /* en la inserción siempre se cumple */{

(*n) -> fe = 0; ni -> fe = 0;}else{

(*n) -> fe = -1;ni -> fe = 1;

}(*n) = ni;

}

void rotacionDD(Nodo** n, Nodo * ni){

(*n) -> dcho = n1 -> izdo;n1 -> izdo = (*n);

/* actualización de los factores de equilibrio */if (n1 -> fe == +1) /* en la inserción siempre se cumple */{

(*n) -> fe = 0; n1 -> fe = 0;}else{

(*n) -> fe = +1;n1 -> fe = -1;

}(*n) = n1;}

void rotacionID(Nodo** n, Nodo * ni){

Nodo* n2;

Page 25: Arboles resumen

24

n2 = n1 -> dcho;(*n) -> izdo = n2 -> dcho;n2 -> dcho = *n;n1 -> dcho = n2 -> izdo;n2 -> izdo = n1;

/* actualización de los factores de equilibrio */if (n2 -> fe == +1)

n1 -> fe = -1;else

n1 -> fe = 0;if (n2 -> fe == -1)

(*n) -> fe = 1;else

(*n) -> fe = 0;

n2 -> fe = 0;(*n) = n2 ;

}

void rotacionDI(Nodo** n, Nodo* ni){

Nodo* n2;n2 = n1 -> izdo;(*n) -> dcho = n2 -> izdo;n2 -> izdo = *n;n1 -> izdo = n2 -> dcho;n2 -> dcho = n1;

/* actualización de los factores de equilibrio */if (n2 -> fe == +1)

(*n) -> fe = -1;else

(*n) -> fe = 0;if (n2 -> fe == -1)

ni -> fe = 1;else

ni -> fe = 0;

n2 -> fe = 0;(*n) = n2 ;

}

Page 26: Arboles resumen

25

BibliografíaAguilar, L. J. (1996). Fundamentos de Programación, Algoritmos y Estructuras de Datos.

Madrid: McGraw Hill.

Aguilar, L. J. (2004). Algoritmos y estructuras de datos, Una perspectiva en C. Madrid: McGrawHill.

Bowman, C. (1999). Algoritmos y Estructuras de Datos. D. F.: Oxford.