Professional Documents
Culture Documents
INGENIERA SISTEMAS LABORATORIO DE ALGORITMIA Y ESTRUCTURA DE DATOS II AVL: RBOL BINARIO ORDENADO Y BALANCEADO I OBJETIVOS Explicar el TAD rbol Binario AVL. Implementar el TAD rbol Binario. Implementar el TAD rbol Binario AVL. Utilizar los TADs rbol Binario y rbol Binario AVL para la resolucin de problemas. II TEMAS TAD rbol Binario. TAD rbol Binario AVL. III MARCO TERICO DEFINICIN DE RBOL AVL Un rbol se dice balanceado en altura si las alturas de los subrboles izquierdo y derecho de cada nodo difieren en a lo sumo una unidad. Los rboles balanceados en altura se llaman rboles AVL (Por sus creadores Adelson-Velskii & Landis) Para Optimizar las Bsquedas, se intentar mantener los rboles Binarios Ordenados IZQ<RAIZ<DER y Balanceados. Llamados rboles AVL (AdelsonVelskiiLandis) Lo s rboles AVL caracterizan porque la Altura = ASD ASI: 1<=Altura<=1 Restringe la altura de cada uno de los Subrboles Se necesita un campo FDB (Factor de Balanceo) en cada nodo. RBOL AVL: FACTOR DE BALANCEO -
FDB = ASD ASI. FDB: Factor de Equilibrio. ASD: Altura del Subrbol Derecho. ASI: Altura del Subrbol Izquierdo.
EJEMPLO
Equilibrado
Equilibrado
-1
Equilibrado
-2
RBOLAVL: INSERCIN La Insercin se hace siguiendo el camino de bsqueda Puede aumentar la altura de una rama, de manera que cambie el factor de balanceo de dicho nodo. Implica que se retornar por el camino de bsqueda para actualizar el FDB de c/nodo Se puede llegar a Desbalancear (Altura=2) => ReBalanceo. O Puede mejorar: Si al rbol X se le Inserta el 1, resultar en Perfectamente Balanceado. El Proceso termina cuando se llega a la Raz o cuando termina el Rebalanceo del mismo. EJEMPLO DE RBOL AVL El rbol AVL esta Balanceado?
ASI
2
ASD
2
10
0
2
1
18
0
6
0
15
RBOL X 0
20
0
ASI
3
ASD 10
-1
3
2
2
18
0
6
-1
15
0
20
0
3
0 RBOL X + NODO 3
PROPUESTOS Seale de los siguientes rboles cul/es es/son AVL e indique el FDB de cada nodo.
RBOLAVL: REESTRUCTURACIN Hay 4 casos posibles a tener en cuenta, segn donde se hizo la Insercin. 1. Insercin en el Subrbol IZQ De la Rama IZQ de 8
8 4 2
2. Insercin en el Subrbol DER De la Rama DER de 8
14 22
14
22
SOLUCIN: La ROTACION le devuelve el equilibrio al rbol. Rotacin Simple: Caso 1 y 2: Implica a 8 y su descendiente Rotacin Doble: Caso 3 y 4: Implica a los 3 nodos Soluciones simtricas: En c/caso, las ramas estn opuestas.
RBOLAVL: ROTACIN SIMPLE Luego de Insertar el Nodo A el rbol qued desbalanceado. Segn que rama ha crecido, la Rotacin Simple puede ser de izquierdaizquierda (II) o derechaderecha(DD). A LA IZQUIERDA (RSI)
n 8 2
2
n1 n1 14
1
n 14
8
0
20
0
12
20
0
12
A LA DERECHA (RSD)
n n1 4
-1
n1 4 12 1
0 0
8
-2
8
0
1
0
12
10
RBOLAVL: EJEMPLO DE ROTACIN SIMPLE A LA IZQUIERDA Inserte en un rbol AVL la siguiente secuencia:
1, 2, 3, 4, 5, 6, 7, 8, 9
1 Insertando 1, 2, 3, 4, 5
2 Insertando 6
3 Insertando 7
11
4 Insertando 8, 9
12
RBOLAVL: EJEMPLO DE ROTACIN SIMPLE A LA DERECHA Inserte en un rbol AVL la siguiente secuencia:
9, 8, 7, 6, 5, 4, 3, 2, 1
1 Insertando 9, 8, 7, 6, 5
2 Insertando 4
3 Insertando 3
13
4 Insertando 2, 1
14
15
n apunta al nodo problema; n1 al hijo de n con problemas, n2 al hijo de n1 DI. Derechaizquierda n1->izq=n2>der n2>der=n1 n->der=n2>izq n2>izq=n n=n2 n 8 5
2
n n1 14
-1
n2 n1 14
0
10 8
0 0
n2 10
0
20
12
20
12
16
17
A LA DERECHA (RDD)
18
n apunta al nodo problema; n1 al hijo de n con problemas, n2 al hijo de n1 ID: izquierdaderecha n1->der=n2>izq n2>izq=n1 n->izq=n2>der n2>der=n n=n2 n 8
-2
n 6 10 4
0 0
n2 n1 8
0
n1 4
1
n2 6
0
10
19
20
RBOLAVL: EJEMPLO DE ROTACIN DOBLES A LA IZQUIERDA Inserte en un rbol AVL la siguiente secuencia:
1, 3, 2, 8, 5, 4, 10, 9, 7, 6
1 Insertando 1, 3, 2, 8, 5
2 Insertando 4, 10, 9
21
3 Insertando 7, 6
22
RBOLAVL: EJEMPLO DE ROTACIN DOBLES A LA DERECHA Inserte en un rbol AVL la siguiente secuencia:
10, 8, 9, 3, 6, 7, 1, 2, 4, 5
1 Insertando 10, 8, 9, 3, 6
2 Insertando 7, 1, 2
23
3 Insertando 4, 5
24
RBOLAVL: QU ROTACIN APLICAR ? Si un rbol est desbalanceado hacia la izquierda (-2), aplicar rotacin hacia derecha En un rbol que est desbalanceado hacia la izquierda revisar el factor de equilibrio del subrbol izquierdo Si un rbol est desbalanceado hacia la derecha (2), aplicar rotacin hacia izquierda En un rbol que est desbalanceado hacia la derecha revisar el factor de equilibrio del subrbol derecho Si el signo de los factores coincide, se aplica una rotacin
simple
25
RBOLAVL: EQUILIBRAR
26
RBOLAVL: INSERTAR template<class DATO> void ArbolAVL<DATO>::insertar( DATO dat) { if(!Buscar(dat)) { nodo<DATO>* padre=NULL; actual = raiz; while(!Vacio(actual) && dat != actual->dato) { padre=actual; if(dat>actual->dato) actual=actual->derecho; else if(dat<actual->dato) actual=actual->izquierdo; } if(!Vacio(actual)) return;
if(Vacio(padre))
if(dat<padre->dato)
{ padre->izquierdo=new nodo<DATO>(dat,padre);
} else
Equilibrar(padre,'I',1); if(dat>padre->dato)
{
Equilibrar(padre,'D',1);
} else { cout<<"EL ELEMENTO YA SE ENCUENTRA..."<<endl; getch(); } } PROPUESTOS 1 Dada la secuencia de claves enteras:210,31,69,85,51,36,97,25,50, Representar grficamente el rbol AVL correspondiente 2 Dada la secuencia de claves enteras:1,2,3,4,5,6,7,8, 9,10,11,12,13. Representar grficamente el rbol AVL correspondiente
13,1,23,28,10.
27
RBOLAVL: ELIMINACIN 1. Borrar el nodo como en un ABB clsico Presenta 2 casos bien diferenciados Si se trata de una hoja se elimina directamente Si tiene un nico hijo se elimina el nodo haciendo que su nodo padre pase a referenciar a su nodo hijo Si tiene dos hijos : Se sustituye el nodo por el menor elemento de su Subrbol Derecho Se elimina el nodo correspondiente a dicho menor elemento. Se sustituye el nodo con el mayor de las Claves Menores del Subrbol Izquierdo. Bajaremos al 1er nodo de la Rama Izquierda Como la clave mayor est a la derecha, se contina bajando a derecha hasta encontrar un nodo hoja (El Mayor de los Menores que reemplazar el dato a eliminar). El planteamiento ms simple en este caso es reemplazar el nodo que queremos borrar con su predecesor en el recorrido inorden. Esta estrategia garantiza que se mantiene la propiedad de los rboles binarios de bsqueda. El problema se convierte entonces en el de eliminar el nodo que ha quedado libre el predecesor en inorden. 2. Recalcular los factores de balanceo que cambiaron por el borrado, se recorre el camino desde el padre del nodo eliminado de regreso hacia la raz, actualizando los equilibrios por el camino. 3. Para cada nodo con factor de balanceo RBOLAVL: EJEMPLO DE ELIINACIN Borrar el nodo con valor 5
n 84 10 5
2
86 86
1 RSI 0
85
90
1
84
0
90
0
99
10
85
99
28
n 13
2
36 40
-1
3 1 6 12 36
-1
13
RDI 0
40
0
45 38 75 1
3 12 15
34
38
45 75
34 15
n 13 3 1 6 12 36 38 40 45 75
34 15
29
n 13 3 1 6 12 36 38 40 45 75
34 15 n 13 3
40 12 45 38 75
1 6
36
34 15
30
NODOS.H
#ifndef NODOS_H #define NODOS_H template <class DATO> class ArbolAVL; template<class DATO>class nodo { public: nodo(const DATO dat,nodo<DATO>*pad=0,nodo<DATO> *izq=0,nodo<DATO>*der=0) { dato=dat; izquierdo=izq; derecho=der; padre=pad; FE=0; }
DATO dato;
int FE;
ARBOL.H
#ifndef ARBOL_h #define ARBOL_h #include "nodos.h" #include <iostream.h> #include <stdio.h> #include <stdlib.h> #include <iomanip.h> #include <conio.h> #include <iomanip.h> int n=0,h1,h2; template <class DATO> class ArbolAVL { public: ArbolAVL() { raiz=NULL;actual=NULL; } ~ArbolAVL() { Podar(raiz); }
Mgter. Juan Pablo Apaza Condori
31
void ramaizq(nodo <DATO>*); void ramader(nodo <DATO>*); void altura(); void numnodos(); void mostr(); void most(nodo<DATO>*,int); void insertar( DATO ); void Borrar(); void Borrar2(DATO); void eng(); void rainor(); void rapost(); void rapreo(); bool Buscar( DATO ); void parentesco(); bool Vacio(nodo<DATO>*r) { return r==NULL; } bool EsHoja (nodo<DATO>*r) { return !r->derecho && !r->izquierdo; } // void InOrden(void (*func)(DATO&,int), nodo<DATO>*nodo=NULL,bool r=true); void InOrden(nodo<DATO>*); // void PreOrden(void (*func)(DATO&,int), nodo<DATO>*nodo=NULL,bool r=true); void PreOrden(nodo<DATO>*); // void PostOrden(void (*func)(DATO&,int),nodo<DATO>*nodo=NULL,bool r=true); void PostOrden(nodo<DATO>*); void Equilibrar(nodo<DATO> *, char, int); nodo<DATO>*nodenc; private:
void RSI(nodo<DATO>* nod ); void RSD(nodo<DATO>* nod); void RDI(nodo<DATO>* nod ); void RDD(nodo<DATO>* nod); void Podar(nodo<DATO>* &);
}; template<class DATO> void ArbolAVL<DATO>::insertar( DATO dat) { if(!Buscar(dat)) { nodo<DATO>* padre=NULL; actual = raiz; while(!Vacio(actual) && dat != actual->dato) { padre=actual; if(dat>actual->dato)
Mgter. Juan Pablo Apaza Condori
32
if(Vacio(padre))
if(dat<padre->dato)
{
Equilibrar(padre,'I',1);
if(dat>padre->dato)
{ padre->derecho=new nodo<DATO>(dat,padre); }
Equilibrar(padre,'D',1);
33
34
35
P->padre = Q->padre = R; if(B) B->padre = Q; if(C) C->padre = P; // Ajustar valores de FE: switch(R->FE) { case -1: Q->FE = 0; P->FE = 1; break; case 0: Q->FE = 0; P->FE = 0; break; case 1: Q->FE = -1; P->FE = 0; break; } R->FE = 0; }
36
37
{ /*if(r) nodo=raiz; if(nodo->izquierdo) PostOrden(func,nodo->izquierdo,false); if(nodo->derecho) PostOrden(func,nodo->derecho,false); func(nodo->dato);*/ if(r!=NULL) { PostOrden(r->izquierdo); PostOrden(r->derecho); printf(" \t%d <%i>",r->dato,r->FE); } // getch(); }
38
bool detector; nodo<DATO>* r,*aux,*ant,*ant2; system("cls"); if(raiz==NULL) cout<<"NO HAY NINGUN ELEMENTO EN EL ARBOL PARA ELIMINAR"<<endl; else { cout<<"SE VA A ELIMINAR EL NODO QUE CONTENGA EL ITEM QUE INGRESE"<<endl; cout<<"INGRESE ITEM: ";cin>>dat; detector=Buscar(dat); if(!detector) cout<<"NO SE PUEDE ELIMINAR UN ELEMENTO QUE NO ESTA"<<endl; else { if(raiz->dato==dat) { if(raiz->izquierdo==NULL && raiz->derecho==NULL) { aux=raiz; delete aux; raiz=NULL; } else { //ama2=0; if(raiz->izquierdo!=NULL) { r=raiz->izquierdo; exito=0; if(r->derecho==NULL) goto choque; else { while(exito==0) { ant=r; r=r->derecho; if(r->derecho==NULL) { exito=1; ant->derecho=r->derecho; raiz->dato=r->dato; } } } } else { choque: if(raiz->derecho!=NULL) { r=raiz->derecho; exito=0; if(r->izquierdo==NULL) { raiz->dato=r->dato;
39
raiz->derecho=r->derecho; aux=r; delete aux; } else { while(exito==0) { ant=r; r=r->izquierdo; if(r->izquierdo==NULL) { exito=1; ant->izquierdo=r->izquierdo; raiz->dato=r->dato; } } } } else { r=raiz->izquierdo; raiz->dato=r->dato; aux = r; raiz->izquierdo=r->izquierdo; delete aux; } } } } else { ///////////////////////////////////////////////// r=raiz; if(r->dato==dat && r->izquierdo ==NULL && r->derecho==NULL) { aux=raiz; delete aux; raiz=NULL; } else { while(r!=NULL) { flag=0; ant=r; if(dat>r->dato) { r=r->derecho; flag=2; } else { r=r->izquierdo; flag=1; }
40
///////////dos hijos////////// if(r->dato==dat && r->izquierdo!=NULL && r->derecho!=NULL) { ant2=r; r=r->izquierdo; if(r->derecho==NULL) { ant2->dato=r->dato; if(r->izquierdo==NULL) { ant2->izquierdo=r->derecho; r=NULL; break; } else { ant2->izquierdo=r->izquierdo; aux=r; r=NULL; delete aux; break; } } else { yes=0; while(yes==0) { aux=r; r=r->derecho; if(r->derecho==NULL) { ant2->dato=r->dato; ant2->izquierdo=r->izquierdo; aux->derecho=NULL; delete r->derecho; yes=1; r=NULL; } } } } else { if(r->dato==dat && r->izquierdo==NULL && r->derecho!=NULL) { if(flag==2) { ant->derecho=r->derecho; aux=r; delete aux; r=NULL; break; } }
41
if(r->dato==dat && r->izquierdo!=NULL && r->derecho==NULL) { if(flag==2) { ant->derecho=r->izquierdo; aux=r; delete aux; r=NULL; break; } } if(r->dato==dat && r->izquierdo!=NULL && r->derecho==NULL) { if(flag==1) { ant->izquierdo=r->izquierdo; aux=r; delete aux; r=NULL; break; } } if(r->dato==dat && r->izquierdo==NULL && r->derecho!=NULL) { if(flag==1) { ant->izquierdo=r->derecho; aux=r; delete aux; r=NULL; break; } } if(r->dato==dat && r->izquierdo==NULL && r->derecho==NULL) { if(flag==1) { aux=r; ant->izquierdo=NULL; r=NULL; } if(flag==2) { aux=r; ant->derecho=NULL; r=NULL; } delete aux; } } n--; } } }
42
cout<<"ELIMINANDO..."<<endl; } } getch(); }
43
44
else Equilibrar(nodenc->padre,'I',-1); } else if(auxiz->derecho!=NULL) { recorre=auxiz->derecho; while(recorre) { ese=recorre; recorre=recorre->derecho; } nodenc->dato=ese->dato; auxde=ese->padre; auxde->derecho=recorre; delete ese; if(raiz->dato==nodenc->dato) Equilibrar(raiz,'I',-1); else Equilibrar(nodenc->padre,'I',-1); } } else {///// if(nodenc->izquierdo==NULL && nodenc->derecho==NULL) { aux=nodenc->padre; auxiz=aux->izquierdo; auxde=aux->derecho; if(auxiz) { if(auxiz->dato==nodenc->dato) { aux->izquierdo=nodenc->izquierdo;//puede ser nodenc derecho los dos son nulos Equilibrar(nodenc->padre,'I',-1); } } if(auxde) { if(auxde->dato==nodenc->dato) { aux->derecho=nodenc->derecho; Equilibrar(nodenc->padre,'D',-1); } } delete nodenc; } else { aux=nodenc->padre; if(nodenc->izquierdo==NULL && nodenc->derecho!=NULL) { if(aux->derecho->dato==nodenc->dato) { aux->derecho=nodenc->derecho; Equilibrar(nodenc->padre,'D',-1); }
45
else if(aux->izquierdo->dato==nodenc->dato) { aux->izquierdo=nodenc->izquierdo; Equilibrar(nodenc->padre,'I',-1); } } else if(nodenc->derecho==NULL && nodenc->izquierdo!=NULL) { if(aux->izquierdo->dato==nodenc->dato) { aux->izquierdo=nodenc->izquierdo; Equilibrar(nodenc->padre,'I',-1); } else if(aux->derecho->dato==nodenc->dato) { aux->derecho=nodenc->derecho; Equilibrar(nodenc->padre,'D',-1); } } delete nodenc; } } printf("ELIMINANDO...\n");getch(); n--; } }
#endif
46
ARBOLAVL.CPP
#include "ARBOL.h" //#include "nodos.h" #include <iostream.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <iomanip.h>
void mostr();
{
/*template<class DATO>
void main()
{
int op, ele; char c=1; ArbolAVL<int> ArbolInt; system("cls"); do { ///getch(); system("cls"); cout<<"\n\n\n"<<endl; // cout<<"\t\t\t"<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<< c<<c<<c<<c<<c<<endl; cout<<"\t\t\t1.-\tINSERTAR NODO"<<endl; cout<<"\t\t\t2.-\tBUSCAR"<<endl; cout<<"\t\t\t3.-\tGRAFICAR"<<endl; cout<<"\t\t\t4.-\tELIMINAR"<<endl; cout<<"\t\t\t5.-\tMOSTRAR"<<endl; // cout<<"\t\t\t6.-\tPROFUNDIDAD"<<endl; // cout<<"\t\t\t7.-\t# DE NODOS"<<endl; // cout<<"\t\t\t8.-\tPARENTESCO"<<endl; cout<<"\t\t\t9.-\tSALIR"<<endl; // cout<<"\t\t\t"<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<<c<< c<<c<<c<<c<<c<<endl; //cout<<"\t\t\t***************************\n"; cout<<"\t\t\tOPCION: ";cin>>op; switch(op) { case 1: { printf("ELEMENTO\t: ");cin>>ele; ArbolInt.insertar(ele); break; } case 2: { printf("ELEMENTO\t: ");cin>>ele; if(ArbolInt.Buscar(ele))
47
cout<<"EL ELEMENTO SI ESTA..."<<endl; else cout<<"EL ELEMENTO NO ESTA..."<<endl; getch(); break; } case 3: { ArbolInt.eng(); break; } case 4: { //if(ArbolInt.Vacio(aux)) printf("EL ARBOL ESTA VACIO...\n"); //else //{ printf("INGRESE ELEMENTO: "); cin>>ele; ArbolInt.Borrar2(ele); // } //ArbolInt.Borrar(); break; } case 5: ArbolInt.mostr(); break; case 6: ArbolInt.altura(); break; case 7: ArbolInt.numnodos(); break; case 8: ArbolInt.parentesco(); break; case 9: exit(1); break; } }while(op); }
48
49
V EJERCICIOS 1 Determine cual de los siguientes rboles es un rbol AVL e indique el FDB de cada nodo.
D
2 Dado el rbol AVL:
50
5 Insertar la secuencia
en el AVL:
5 Insertar 40,
6 Se quiere leer un archivo de texto y almacenar en memoria todas las palabras de dicho texto y su frecuencia. La estructura de datos va ser tal que permita realizar una bsqueda en un tiempo O(log n)), sin que dependa de la entrada de datos, por o que se requiere utilizar un rbol AVL. El archivo de texto se llama carta.dat, se pide almacenar dicho texto en memoria, utilizando la estructura rbol indicada anteriormente. Posteriormente se ha de realizar un procedimiento, que dada una palabra nos indique el nmero de veces que aparece en el texto. 7 En un archivo de texto se encuentra los datos(nombre, apellidos, direccin, telefono) completos de los alumnos del taller de teatro de la universidad. Escribir un programa que lea el archivo y forme un rbol binario equilibrado (AVL) con respecto a la clave apellido .
8 Una empresa de servicios tiene tres departamentos, comercial(1), explotacin(2) y comunicaciones(3). Cada empleado est adscrito a uno de ellos. Se ha realizado una redistribucin de personal entre los departamentos. El archivo EMPRESA contiene en cada registro los campos Numero_Idt, Origen, Destino.
El Origen toma los valores 1, 2, 3 dependiendo del departamento inicial al que pertenece el empleado. El campo Destino toma los mismos valores, dependiendo del nuevo departamento asignado al empleado. El archivo no est ordenado. Escribir un programa que almacene los registros del archivo EMPRESA en tres rboles AVL, uno por cada departamento de origen, y realice el intercambio de registros en los rboles segn el campo destino.
51