200 likes | 363 Views
Árboles AVL cont. Algoritmo de Inserción. En la construcción de un árbol AVL todo nodo que se inserte, se insertará como una hoja . Los pasos son: 1. Buscar donde insertar el nuevo nodo 2. Insertar el nuevo nodo 3. Recalcular factores de balance
E N D
Algoritmo de Inserción En la construcción de un árbol AVL todo nodo que se inserte, se insertará como una hoja. Los pasos son: 1. Buscar donde insertar el nuevo nodo 2. Insertar el nuevo nodo 3. Recalcular factores de balance 4. Rebalancear el árbol si es necesario
Para el primer paso, el cual consiste en buscar dónde insertar el nuevo nodo se utilizan las siguientes variables: • p: Para recorrer el árbol buscando donde insertar el nuevo nodo • q: Apuntará hacia el padre de p Inicialmente p será la raíz y q será NULL
Cuando p se haga NULL, q apuntará hacia el nodo que será el padre del nodo que contiene el nuevo dato • Ahora bien, como el tercer paso es rebalancear el árbol, se requiere conocer cuál será el nodo "raíz" del sub-árbol a balancear. Se llamará a este nodo PIVOTE. Es decir, PIVOTE será la raíz del árbol a balancear
Como al rebalancear un árbol, éste siempre cambia de raíz, la nueva raíz, (que queda en Q), habrá que pegarla del nodo que era padre de PIVOTE. Esto implica que se debe conocer el padre de PIVOTE. Se llamará a este nodo pp
Para determinar PIVOTE se debe tener en cuenta que los únicos nodos que pueden quedar desbalanceados son aquellos cuyo factor de balance es diferente de cero • En concreto, PIVOTE es el nodo más cercano al nodo donde se hará la inserción, con factor de balance diferente de cero. Es bueno aclarar que es el nodo más cercano en la trayectoria desde la raíz hasta el nodo que será el padre del nuevo nodo • Puede suceder que PIVOTE sea RAIZ, con factor de balance cero • Inicialmente PIVOTE será la raíz y pp será NULL
class Nodo { public: int clave; Nodo *hijoIzq; //Apuntador a hijo izquierdo Nodo *hijoDer; //Apuntador a hijo derecho int FB; //Factor de Balance public: Nodo(int dato); }; Nodo::Nodo(int dato) //Constructor { clave = dato; hijoIzq = NULL; hijoDer = NULL; FB=0; }
class ArbolAVL { public: Nodo *raiz; //Apunta a la raíz del arbol Nodo *actual; public: ArbolAVL(); //Constructor void insertar(int dato); //Recorrido void inorden(Nodo *r); //Rotaciones void Rotacion_a_la_Derecha(Nodo *P, Nodo *Q); void Rotacion_a_la_Izquierda(Nodo *P, Nodo *Q); Nodo *Doble_Rotacion_a_la_Derecha(Nodo *P, Nodo *Q); Nodo *Doble_Rotacion_a_la_Izquierda(Nodo *P, Nodo *Q); };
//Constructor ArbolAVL::ArbolAVL() { raiz=NULL; actual=NULL; }
//Rotaciones: void ArbolAVL::Rotacion_a_la_Derecha(Nodo *P, Nodo *Q) { P -> hijoIzq = Q -> hijoDer; Q -> hijoDer = P; P -> FB = 0; Q -> FB = 0; } void ArbolAVL::Rotacion_a_la_Izquierda(Nodo *P, Nodo *Q) { P -> hijoDer = Q -> hijoIzq; Q -> hijoIzq = P; P -> FB = 0; Q -> FB = 0; }
Nodo *ArbolAVL::Doble_Rotacion_a_la_Derecha(Nodo *P, Nodo *Q) { Nodo *R = Q -> hijoDer; //Se obtiene R a partir de Q int factor_R = R->FB; //Se guarda el factor de balance de R Rotacion_a_la_Izquierda(Q, R); Rotacion_a_la_Derecha(P, R); switch ( factor_R ) { case 0: P -> FB = 0; Q -> FB = 0; break; case 1: P -> FB = -1; Q -> FB = 0; break; case -1: P -> FB = 0; Q -> FB = 1; break; } R -> FB = 0; //Aunque sobra ya que las rotaciones ya lo han puesto en 0 return R; //Se devuelve la raíz del árbol balanceado }
Nodo *ArbolAVL::Doble_Rotacion_a_la_Izquierda(Nodo *P, Nodo *Q) { Nodo *R = Q -> hijoIzq; //Se obtiene R a partir de Q int factor_R = R->FB; //Se guarda el factor de balance de R Rotacion_a_la_Derecha(Q, R); Rotacion_a_la_Izquierda(P, R); switch ( factor_R ) { case 0: P -> FB = 0; Q -> FB = 0; break; case 1: P -> FB = 0; Q -> FB = -1; break; case -1: P -> FB = 1; Q -> FB = 0; break; } R -> FB = 0; //Aunque sobra ya que las rotaciones ya lo han puesto en 0 return R; //Se devuelve la raíz del árbol balanceado }
//Algoritmo de Inserción: void ArbolAVL::insertar(int dato) { Nodo *x= new Nodo(dato); //Crea el nodo para el nuevo Nodo *p = raiz; //Asigna valores iniciales a las variables Nodo *q = NULL; //que se utilizan para buscar el sitio donde Nodo *pivote = raiz; //se insertará el nuevo nodo y determinar Nodo *pp= NULL; //pivote y su padre. if(raiz == NULL) //Si árbol vacío { raiz = actual = x; //El nuevo a su vez es la raíz y el actual }
else { while (p != NULL) { if (p-> clave == dato) { //Controla repetidos delete(x); return; } if (p->FB != 0) { //O sea que es -1 ó +1 pivote = p; //Determina el PIVOTE pp = q; //y su padre. } q = p; //Actualiza q if ( p->clave > dato) p = p -> hijoIzq; //Avanza con p else p = p -> hijoDer; //Avanza con p }
if (q->clave > dato) q->hijoIzq = x; //Inserta x como hijo izquierdo else // o como hijo derecho de q q->hijoDer = x; //Recalcula factor de balance de PIVOTE if (pivote-> clave > dato) { pivote->FB = pivote->FB +1; q = pivote-> hijoIzq; } else { pivote->FB = pivote->FB -1; q = pivote-> hijoDer; }
//Recalcula factores de balance de todos los nodos en la //trayectoria desde PIVOTE hasta el nodo insertado x p = q; while (p != x) { if (p->clave > dato) { p->FB = 1; p = p->hijoIzq; } else { p->FB = -1; p = p->hijoDer; } }
if (pivote->FB == 0 || pivote-> FB == -1 || pivote-> FB == 1) //Si el árbol siguió balanceado retorna return; //Determina el tipo de rotación if (pivote->FB == 2 && q->FB == 1) Rotacion_a_la_Derecha(pivote,q); if (pivote->FB == -2 && q->FB == -1) Rotacion_a_la_Izquierda(pivote,q); if (pivote->FB == 2 && q->FB == -1) q=Doble_Rotacion_a_la_Derecha(pivote,q); if (pivote->FB == -2 && q->FB == 1) q=Doble_Rotacion_a_la_Izquierda(pivote,q);
// Si el nodo desbalanceado era la raíz lo actualiza y regresa. if (pp == NULL) { raiz = q; return; } // Pega la nueva raíz del árbol rebalanceado (q) al nodo pp. if (pivote == pp->hijoIzq) pp->hijoIzq = q; else pp->hijoDer = q; } }
void ArbolAVL::inorden(Nodo *r) { if(r) { inorden(r->hijoIzq); cout<<" "<<r->clave<<" "; inorden(r->hijoDer); } }
void main(void) { //Se crea un árbol AVL ArbolAVL miarbolAVL; //Se insertan claves en el árbol: miarbolAVL.insertar(9); miarbolAVL.insertar(6); miarbolAVL.insertar(1); //Desencadena rotación por la derecha miarbolAVL.inorden(miarbolAVL.raiz); }