-- AUTOR: Elvira Mayordomo Cámara
-- PROYECTO: módulo de implementación del
-- TAD arboles AVL (árboles binarios de búsqueda
-- casi equilibrados)
-- FICHERO: avl.adb
-- FECHA: 14-11-03

with unchecked_deallocation;
with text_io;
use text_io;

package body avl is

procedure disponer is new unchecked_deallocation(nodo,arbin);

procedure reequilibrar(a:in arbin);
-- Pre: partiendo de un árbol AVL, 
-- uno de los hijos de la raiz a ha cambiado en altura
-- (sumando ó restando 1)
-- por lo que las alturas de a hacia arriba
-- deben ser recalculadas y posiblemente el árbol
-- reequilibrado.
-- Post: a tiene los mismos nodos y es
-- un AVL
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)

procedure creaVacio(a:out arbin) is
-- Post: a=aVacío
-- coste en tiempo O(1)
begin
a:=null;
end creaVacio;

procedure insertarrec(a,nuevodato:in out arbin) is
-- Pre: a=a0
-- Post: a=insertar(a0,e) pero sin reequilibrado
-- resultado devuelve el punto de inserción del
-- nuevo nodo.
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
begin
	if a=null then 
		a:=nuevodato;
	elsif (nuevodato.dato<=a.dato) then
		nuevodato.padre:=a;
		insertarrec(a.izq,nuevodato);
	else
		nuevodato.padre:=a; 
		insertarrec(a.der,nuevodato);
	end if;
end insertarrec;

procedure insertar(a:in out arbin; e:in elemento) is
-- Pre: a=a0
-- Post: a=insertar(a0,e)
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
nuevodato: arbin;
begin
	nuevodato:=new nodo'(e,null,null,null,0);
	insertarrec(a,nuevodato);
	reequilibrar(nuevodato.padre);
end insertar;

function esta(a:arbin; e:elemento) return
boolean is
-- Post: esta(a,e)= está?(a,e)
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
resultado: boolean;
begin
	resultado:=false;
	if a/=null then 
		if (a.dato = e) then resultado:=true;
		elsif (e<=a.dato) then
		resultado:=esta(a.izq,e);
		else resultado:=esta(a.der,e);
		end if;
	end if;
	return resultado;	
end esta;

function min(a:arbin) return elemento is
-- Pre: not(esvacío(a))
-- Post: min(a)= min(a)
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
begin
	if a.izq=null then return a.dato;
	else return min(a.izq);
	end if;
end min;

function max(a:arbin) return elemento is
-- Pre: not(esvacío(a))
-- Post: max(a)= max(a)
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
begin
	if a.der=null then return a.dato;
	else return max(a.der);
	end if;
end max;

procedure borrarrec(a:in out arbin; e:in
elemento; lugar:out arbin) is
-- Pre: a=a0
-- Post: a=borrar(a0,e) sin reequilibrar
-- lugar tiene al padre del borrado
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
aux:arbin; 
nuevaraiz:elemento;
begin
	if a/=null then 
		if (a.dato = e) then 
			if a.der=null and a.izq=null then
				aux:=a;
				lugar:=a.padre; 					
				a:=null;
				disponer(aux);
			elsif a.izq/=null then
				nuevaraiz:=max(a.izq);
				a.dato:=nuevaraiz;
				borrarrec(a.izq,nuevaraiz,lugar);
			else
				nuevaraiz:=min(a.der);
				a.dato:=nuevaraiz;
				borrarrec(a.der,nuevaraiz,lugar);	
			end if;
		elsif (e<=a.dato) then
			borrarrec(a.izq,e,lugar);
		else borrarrec(a.der,e,lugar);
		end if;
	end if;
end borrarrec;

procedure borrar(a:in out arbin; e:in
elemento) is
-- Pre: a=a0
-- Post: a=borrar(a0,e)
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
lugar:arbin; 
begin
	borrarrec(a,e,lugar);
	if lugar/=null then 
		reequilibrar(lugar);
	end if;	
end borrar;

function altura(a:arbin) return integer is
-- calcula la altura de a a partir de las de
-- a.izq y a.der
-- coste en tiempo O(1)
altizq,altder: integer;
begin
	if a=null then 
		return -1; 
	else
		if a.der/=null then
			altder:=a.der.altura;
		else
			altder:=-1;
		end if;
		if a.izq/=null then
			altizq:=a.izq.altura;
		else
			altizq:=-1;
		end if;
		return(1+integer'Max(altizq,altder));
	end if;
end altura;

function factorequilibrio(a:arbin) return integer is
-- calcula el factor de equilibrio de a 
-- coste en tiempo O(1)
begin
	if a=null then 
		return 0; 
	else
		return altura(a.der)-altura(a.izq);
	end if;
end factorequilibrio;

procedure rotacionSder(a:in out arbin) is
-- Pre: a/=null y a.izq/=null
-- Post: realiza una rotación simple a dcha
-- sobre a
-- coste en tiempo O(1)
NA, NB: nodo;
begin
	NA:=a.all;
	NB:=a.izq.all;
	a.dato:=NB.dato;
	a.der:=a.izq;
	a.der.padre:=a;
	a.izq:=NB.izq;
	if a.izq/=null then a.izq.padre:=a; end if;
	a.der.dato:=NA.dato;
	a.der.izq:=NB.der;
	if a.der.izq/=null then
		a.der.izq.padre:=a.der; 
	end if;
	a.der.der:=NA.der;
	if a.der.der/=null then
		a.der.der.padre:=a.der; 
	end if;
	a.der.altura:=altura(a.der);
	a.altura:=altura(a);
end rotacionSder;

procedure rotacionSizq(a:in out arbin) is
-- Pre: a/=null y a.der/=null
-- Post: realiza una rotación simple a izda
-- sobre a
-- coste en tiempo O(1)
NA, NB: nodo;
begin
	NA:=a.all;
	NB:=a.der.all;
	a.dato:=NB.dato;
	a.izq:=a.der;
	a.izq.padre:=a;
	a.der:=NB.der;
	if a.der/=null then a.der.padre:=a; end if;
	a.izq.dato:=NA.dato;
	a.izq.der:=NB.izq;
	if a.izq.der/=null then
		a.izq.der.padre:=a.izq; 
	end if;
	a.izq.izq:=NA.izq;
	if a.izq.izq/=null then
		a.izq.izq.padre:=a.izq; 
	end if;
	a.izq.altura:=altura(a.izq);
	a.altura:=altura(a);
end rotacionSizq;

procedure rotacionDder(a:in out arbin) is
-- Pre: a/=null, a.izq/=null y a.izq.der/=null
-- Post: realiza una rotación doble a dcha
-- sobre a
-- coste en tiempo O(1)
NA, NB, NC: nodo;
begin
	NA:=a.all;
	NC:=a.der.all;
	NB:=NC.izq.all;
	a.dato:=NB.dato;
	a.izq:=NC.izq;
	a.izq.padre:=a;
	a.izq.dato:=NA.dato;
	a.izq.izq:=NA.izq;
	if a.izq.izq/=null then
		a.izq.izq.padre:=a.izq; 
	end if;
	a.izq.der:=NB.izq;
	if a.izq.der/=null then
		a.izq.der.padre:=a.izq; 
	end if;
	a.der.izq:=NB.der;
	if a.der.izq/=null then
		a.der.izq.padre:=a.der; 
	end if;
	a.izq.altura:=altura(a.izq);
	a.der.altura:=altura(a.der);
	a.altura:=altura(a);
end rotacionDder;

procedure rotacionDizq(a:in out arbin) is
-- Pre: a/=null, a.der/=null y a.der.izq/=null
-- Post: realiza una rotación doble a izda
-- sobre a
-- coste en tiempo O(1)
NA, NB, NC: nodo;
begin
	NC:=a.all;
	NA:=a.izq.all;
	NB:=NA.der.all;
	a.dato:=NB.dato;
	a.der:=NA.der;
	a.der.padre:=a;
	a.der.dato:=NC.dato;
	a.der.izq:=NB.der;
	if a.der.izq/=null then
		a.der.izq.padre:=a.der; 
	end if;
	a.der.der:=NC.der;
	if a.der.der/=null then
		a.der.der.padre:=a.der; 
	end if;
	a.izq.der:=NB.izq;
	if a.izq.der/=null then
		a.izq.der.padre:=a.izq; 
	end if;
	a.izq.altura:=altura(a.izq);
	a.der.altura:=altura(a.der);
	a.altura:=altura(a);
end rotacionDizq;

procedure rotar(a:in out arbin) is
-- Pre: a=a0 es un árbol en el que la raiz tiene factor de
-- equilibrio +2 ó -2 y el resto de los nodos entre -1 y +1.
-- Post: a es un árbol AVL con los mismos
-- valores que a0 y altura(a)=altura(a0)-1
-- coste en tiempo O(1)
begin
	if factorequilibrio (a)=-2 then
		if factorequilibrio (a.izq)= 1 then
			rotacionDizq(a);
		else 
			rotacionSder(a);
		end if;
	else
		if factorequilibrio (a.der)= -1 then
			rotacionDder(a);
		else 
			rotacionSizq(a);
		end if;
	end if;					
end rotar;

procedure reequilibrar(a:in arbin) is
-- uno de los hijos de a ha cambiado en altura
-- por lo que las alturas de a hacia arriba
-- deben ser recalculadas y posiblemente el árbol
-- reequilibrado.
-- coste en tiempo: para un árbol de n nodos tarda
-- O(log n)
aux: arbin;
fe: integer;
desequilibrado:boolean;
begin
	-- actualización de alturas
	aux:=a;
	desequilibrado:=false;	
	while aux/=null and not desequilibrado loop
		aux.altura:=altura(aux);
		fe:=factorequilibrio(aux);
		desequilibrado:=(fe=2) or(fe=-2);
		if not desequilibrado then aux:=aux.padre; end if;
	end loop;	
	if desequilibrado then rotar(aux); end if;
end reequilibrar;

procedure preOrden(a:in arbin) is
-- muestra por pantalla el preorden de a
begin 
	if a/=null then
		put(a.dato);
		preOrden(a.izq);
 		preOrden(a.der);
 	end if;
end preOrden;

procedure postOrden(a:in arbin) is
-- muestra por pantalla el preorden de a
begin 
	if a/=null then
		postOrden(a.izq);
 		postOrden(a.der);
		put(a.dato);
 	end if;
end postOrden;

procedure mostrar(a:in arbin) is
-- Muestra por pantalla preorden y postorden
begin
	put_line("El preorden es:");
	preOrden(a);
	put_line("");
	put_line("El postorden es:");
	postOrden(a);
	put_line("");
end mostrar;	

end avl; 


syntax highlighted by Code2HTML, v. 0.9.1