Sei sulla pagina 1di 93

Arboles

Matilde Fernndez Azuela


Madrid, noviembre de 2010
Concepto de rbol
La definicin de rbol implica una naturaleza
recursiva puesto que un rbol o es vaco o se
considera formado por un nodo raz y un conjunto
disjunto de rboles que se llaman subrboles del
raz.
Las estructuras de tipo rbol se usan para
representar datos con una relacin jerrquica entre
ellos.
Relaciones entre los nodos
Los elementos de un rbol se llaman nodos y la estructura
jerrquica entre los nodos viene dada por la relacin de
paternidad que se establezca sobre los mismos.
Si existe una relacin de paternidad (rama) dirigida del
nodo a al nodo b, entonces a es el padre de b y b es un
hijo de a
Todos los nodos de un rbol tienen un nico padre (un
nico predecesor), excepto uno, denominado raz, que no
tiene padre.
Los nodos de un rbol pueden tener varios sucesores o
hijos. Los hijos del mismo padre se denominan hermanos
Grado
Se llama grado de un nodo al nmero de hijos que
salen de l. El grado de un rbol es el mayor de los
grados de sus nodos..
Si no existe limitacin para el nmero de hijos que
pueda tener un nodo, el rbol se denomina general.
Un rbol binario es aquel en el que todos sus nodos
tienen como mximo el grado 2.
TAD rbol general
TAD arbol_general (VALORES: arbol general de
elementos; OPERACIONES: vacio, crear, raiz, hijos,
esvacio)
// se basa en el TAD elemento y
// en el TAD lista_de_ag,
// lista de elementos (genrica)
// parametrizada con <arbol_general>
Sintaxis:
*vaco() arbol_general
*crear(elemento, lista_de_ag) arbol_general
raz(arbol_general) Elemento
hijos(arbol_general) lista_de_ag
esVaco(arbol_general) boolean
TAD rbol general
Semntica:
Para todo: e e elemento; l e lista_de _ag;
a e arbol_general
raiz(vacio) => error
raz(crear(e, l)) => e
hijos(crear(e, l)) => l
hijos(vacio) => error
esVaco(vaco) => true
esVaco(crear(e, l)) => false
TAD rbol binario
TAD arbol_binario (VALORES: rbol binario de elementos;
OPERACIONES: inicializar, vacio, construir, izquierda, derecha, raiz)
// se basa en el TAD elemento
Sintaxis
* inicializar() arbol_binario
vacio(arbol_binario) boolean
* construir(arbol_binario,elemento,arbol_binario) arbol_binario
raiz(arbol_binario) elemento
izquierda(arbol_binario) arbol_binario
derecha(arbol_binario) arbol_binario
TAD rbol binario
Semntica Para todo a,b: arbol_binario; e: elemento
Vacio(inicializar()) true
Vacio(construir(a,e,b)) false
Raiz(inicializar()) error
Raiz(construir(a,e,b)) e
izquierda(inicializar()) error
izquierda(construir(a,e,b)) a
derecha(inicializar()) error
derecha(construir(a,e,b)) b
rbol de expresin
Los rboles binarios pueden utilizarse para
almacenar expresiones en memoria.
Se puede decir que los rboles de expresin son
rboles binarios, cuyas hojas contienen operandos y
los otros nodos operadores.
Construccin rbol de expresin
Para construir un rbol de
expresin a partir de una
expresin matemtica en
notacin infija se utilizarn, como
estructuras de datos auxiliares,
una pila capaz de almacenar
punteros a los nodos de un rbol
y otra donde poner los
operadores temporalmente hasta
que corresponda incorporarlos al
rbol.
4+3^2
Construccin rbol de expresin
Cuando se lee un operando se crea un rbol de un nodo y
se coloca en la pila de rboles
Cuando se lee un operador se coloca en la pila de
operadores, pero si el operador a colocar tiene menor o igual
prioridad que el de la cima, antes de colocarse, saca de la
pila los operadores con mayor o igual prioridad que l para
enviarlos a la pila de rboles
Cuando se acaba la entrada tambin se saca lo que hubiera
en la pila de operadores y se enva a la pila de rboles
Cuando un operador llega a la pila de rboles se quitan dos
elementos de la mencionada pila y se construye un nuevo
rbol, con el operador como raiz y los elementos extraidos
como hijos, que vuelve a colocarse en la pila de rboles
//Arb.h
#ifndef ArbolBinarioB
#define ArbolBinarioB
class Nodo;
class Arbol{
private:
Nodo *a;
public:
Arbol();
Arbol( Arbol ai, char e, Arbol ad);
Arbol(const Arbol & arb);
~Arbol();
const Arbol& operator=(const Arbol& arb);
void Mostrar(int n=1);
void Arbol::SetA(Nodo* p){a=p;}
};
class Nodo {
private:
char e;
Arbol hi,hd;
public:
Nodo (Arbol ai,char x, Arbol ad);
~ Nodo();
Arbol& Gethi(){return hi;}
Arbol& Gethd(){return hd;}
char GetInfo(){return e;}
void Sethi(const Arbol& ai){hi=ai;}
void Sethd(const Arbol& ad){hd=ad;}
void SetInfo(char d){e=d;}
};
#endif
//fin del archivo .h
void ArbolDesdeInfija(string C, Arbol& arb)
{ Pila<Nodo*> PA;
Pila<char> PC;
Nodo* na, *nb, *nc;
char caux;
Arbol aa, ab;
for(int j=0;j<C.length(); j++)
if (C[j] == ')' )
{ while (PC.ECima() != '(')
{ caux=(PC.ECima());
PC.Quitar();
//tratar operador:
nb=(PA.ECima());
ab.SetA(nb);
PA.Quitar();
na= PA.ECima();
aa.SetA(na);
PA.Quitar();
nc= new Nodo (aa,caux,ab);
PA.Poner(nc);
}
PC.Quitar();
}
else
if (EsOperador(C[j]))
{ while (! PC.Vacia() &&
(prioridadd(PC.ECima())) >=
prioridadf(C[j]))
{ //desapilar operador:
caux=(PC.ECima());
PC.Quitar();
//tratar operador:
nb=(PA.ECima());
ab.SetA(nb);
PA.Quitar();
na= PA.ECima();
aa.SetA(na);
PA.Quitar();
nc= new Nodo (aa,caux,ab);
PA.Poner(nc);
}
//poner operador:
PC.Poner(C[j]);
}
else
if (C[j]!=' ')
{ na=new Nodo(Arbol(), C[j], Arbol());
PA.Poner(na);
}
//fin del for que recorre la expresin
while (!PC.Vacia())
{ caux=(PC.ECima());
PC.Quitar();
//tratar operador:
nb=(PA.ECima());
ab.SetA(nb);
PA.Quitar();
na= PA.ECima();
aa.SetA(na);
PA.Quitar();
nc= new Nodo (aa,caux,ab);
PA.Poner(nc);
}
arb.SetA(PA.ECima());
PA.Quitar();
}
bool EsOperador(char c)
{
string cad2="(+-*/%^";
if (cad2.find(c,0)< cad2.length())
return true;
else
return false;
}
int prioridadf(char opdor)
{ switch(opdor)
{ case '(': return 5;
case '^': return 4;
case '/':
case '*': return 2;
case '+':
case '-': return 1;
}
}
int prioridadd(char opdor)
{ switch(opdor)
{ case '(': return 0;
case '^': return 3;
case '/':
case '*': return 2;
case '+':
case '-': return 1;
}
}
rbol binario de bsqueda
Cuando existe una relacin de orden total en el
conjunto de los subrboles de un rbol, el rbol se
llama ordenado
Un rbol binario de bsqueda es un tipo especial de
rbol binario (rbol binario ordenado) en el que para
cualquier nodo su valor es superior a los valores de los
nodos de su subrbol izquierdo e inferior a los de su
subrbol derecho.
//archivo .h
#ifndef ArbolBinarioB
#define ArbolBinarioB
class Nodo;
class Arbol{
private:
Nodo *a;
void EliminaRecursivo (int &x);
void EliminaIterativo(int &x);
Arbol& Ohi();
Arbol& Ohd();
void PPuntero(Nodo * p);
int Oe();
public:
Arbol(); //constructor sin argumentos
Arbol( Arbol ai, int e, Arbol ad);
// constructor con argumentos
Arbol(const Arbol & arb);//constructor de copia
~Arbol(); // destructor
const Arbol& operator=(const Arbol& arb);
// sobrecarga del operador de asignacin
void AnadirRecursivo (int e);
void AnadirIterativo (int x);
void BorrarRecursivo (int x);
void BorrarIterativo(int x);
void RecorrerIRD();
};
class Nodo {
private:
int e;
Arbol hi,hd;
public:
Nodo (Arbol ai,int x, Arbol ad);
~ Nodo();
Arbol& Gethi(){return hi;}
Arbol& Gethd(){return hd;}
int GetInfo(){return e;}
void Sethi(const Arbol& ai){hi=ai;}
void Sethd(const Arbol& ad){hd=ad;}
void SetInfo(int d){e=d;}
};
#endif
//fin del archivo .h
// Archivo .cpp
#include <iostream>
#include <stdlib.h>
#include <iomanip.h>
#include "Arbolbb.h"
using namespace std;
Nodo::Nodo (Arbol ai, int x, Arbol ad)
{ e=x;
hi =ai;
hd = ad;
} ;
Nodo::~Nodo()
{ }
Arbol::Arbol()
{
a=NULL;
}
Arbol:: Arbol( Arbol ai, int e, Arbol ad)
{ a= new Nodo(ai,e,ad); }
Arbol::Arbol(const Arbol & arb)
{// constructor de copia
if (arb.a==NULL)
a=NULL;
else
a=new Nodo(arb.a->Gethi(),arb.a->GetInfo(),arb.a->Gethd());
//llama recursivamente al constructor por copia
}
Arbol::~Arbol()
{ if (a)
{ cout<<a->GetInfo()<<endl;
delete a;
a=NULL;
}
}
const Arbol& Arbol::operator=(const Arbol& arb)
{ if (this!=&arb)
{
if (a!=NULL)
delete a;
if (arb.a==NULL)
a=NULL;
else
a=new Nodo(arb.a->Gethi(),arb.a->GetInfo(),
arb.a->Gethd());
//llama al constructor de copia
}
return *this;
}
int Arbol::Oe(){return a->GetInfo();}
Arbol& Arbol::Ohi(){if (a) return a->Gethi();}
Arbol& Arbol::Ohd(){if (a) return a->Gethd();}
void Arbol::PPuntero(Nodo * p) { a = p;}
void Arbol::AnadirRecursivo (int x)
{ if (a == NULL)
a= new Nodo (Arbol(), x, Arbol());
else
if (a->GetInfo()>x)
a->Gethi().AnadirRecursivo(x);
else if (a->GetInfo()<x)
a->Gethd().AnadirRecursivo(x);
}
void Arbol::AnadirIterativo (int x)
{ Nodo *Ant=NULL, *nuevo, *pos=a;
bool enc=false;
while (!enc && pos != NULL)
{ if (pos->GetInfo()==x)
enc=true;
else
{ Ant=pos;
if( pos->GetInfo()<x )
pos=pos->Gethd().a;
else
pos=pos->Gethi().a;
}
} //contina
//continuacin de aadir iterativo
if (!enc)
{ nuevo= new Nodo(Arbol(),x,Arbol());
if (Ant == NULL)
a=nuevo;
else
if (Ant->GetInfo()<x)
Ant->Gethd().a = nuevo;
else
Ant->Gethi().a=nuevo;
}
}
void Arbol::RecorrerIRD()
{ if (a !=NULL)
{ a->Gethi().RecorrerIRD();
cout <<setw(4)<< a->GetInfo();
a->Gethd().RecorrerIRD();
}
}
void Arbol:: BorrarRecursivo (int x)
{ if (a == NULL)
cout << " no existe " << endl;
else
if (a->GetInfo()< x)
a->Gethd().BorrarRecursivo(x);
else if (a->GetInfo() > x)
a-> Gethi().BorrarRecursivo(x);
else
if (a-> Gethi().a==NULL)
{ Nodo * aborrar = a;
a = a->Gethd().a;
aborrar->Gethd().PPuntero(NULL);
delete aborrar;
}
else
if( a->Gethd().a==NULL)
{ Nodo * aborrar = a;
a= a->Gethi().a;
aborrar->Gethi().PPuntero( NULL);
delete aborrar;
}
else
{ int s;
a->Gethi().EliminaRecursivo(s);
a->SetInfo(s);
}
}
void Arbol::BorrarIterativo(int x)
{ Nodo * Ant= NULL, *aborrar, *pos=a;
bool enc=false;
while (!enc && pos != NULL)
{ if (pos->GetInfo()==x)
enc=true;
else
{ Ant=pos;
if( pos->GetInfo()<x )
pos=pos->Gethd().a;
else
pos=pos->Gethi().a;
}
}
//contina
if (enc)
{ if ( pos->Gethd().a ==NULL)
{ if (Ant)
if (Ant->Gethd().a == pos)
Ant->Gethd().PPuntero( pos->Gethi().a);
else
Ant->Gethi().PPuntero( pos->Gethi().a);
else
a = pos->Gethi().a;
pos->Gethi().PPuntero(NULL);
delete pos;
}
else if ( pos->Gethi().a ==NULL)
{ if (Ant)
if (Ant->Gethd().a == pos)
Ant->Gethd().PPuntero( pos->Gethd().a);
else
Ant->Gethi().PPuntero( pos->Gethd().a);
else
a = pos->Gethd().a;
pos->Gethd().PPuntero(NULL);
delete pos;
}
else
{ int s;
pos->Gethi().EliminaIterativo(s);
pos->SetInfo(s);
}
}
else
cout << " no existe";
}
void Arbol::EliminaRecursivo( int &x)
{ if ( a->Gethd().a==NULL)
{ Nodo * aborrar = a;
x= a->GetInfo() ;
a = a->Gethi().a;
aborrar->Gethi().PPuntero(NULL);
delete aborrar;
}
else
a->Gethd().EliminaRecursivo (x);
}
void Arbol::EliminaIterativo(int &x)
{ Nodo *Ant = NULL, *Aux = a;
while( Aux->Gethd().a)
{ Ant = Aux;
Aux= Aux->Gethd().a;
}
if (Ant == NULL)
a = Aux->Gethi().a;
else
Ant->Gethd().a= Aux->Gethi().a;
x= Aux->GetInfo();
Aux->Gethi().PPuntero(NULL);
delete Aux;
}
Eficiencia rboles binarios de
bsqueda
La eficiencia de los rboles binarios de bsqueda para
la localizacin de una clave vara entre O(n) y O(log(n))
En el peor de los casos, si todos los elementos se
insertan en el rbol en orden creciente o decreciente,
el rbol va a tener todas las ramas izquierda o
derecha, respectivamente, vacas, y la bsqueda en
dicho rbol ser totalmente secuencial O(n).
rboles AVL
Llamados as en honor a sus inventores: Adelson-
Velskii y Landis.
Un rbol AVL es un rbol binario de bsqueda auto-
balanceado, que cumple la condicin de que la
diferencia entre las alturas de los subrboles de cada
uno de sus nodos es como mximo una unidad
En un rbol AVL se debe almacenar la informacin
sobre la diferencia de alturas entre sus subrboles
izquierdo y derecho en cada nodo
Eficiencia en las bsquedas de un
rbol AVL
El tiempo ser proporcional a la altura del rbol, por
tanto lo que se desea encontrar es la altura mxima h
para un AVL de n nodos.
Es fcil ver que el menor nmero de nodos n en un AVL
de altura h es:
para h=0 n
0
=1
para h=1 n
1
=2
para toda h>1 n
h
= 1 + n
h-1
+ n
h-2
Eficiencia en las bsquedas de un
rbol AVL
Relacin con la serie de Fibonacci: n
h
= F
h + 3
- 1
Nodos AVL 1, 2, 4, 7, 12, ...
Altura 0, 1, 2, 3, 4, ...
(Fibonacci : 0, 1, 1, 2, 3, 5, 8, 13 ....)
(termino: 0, 1, 2, 3, 4, 5, 6, 7.....)
h
h fib
|
|
.
|

\
|
+
~
2
5 1
5
1
) (
=
|
|
.
|

\
|
|
|
.
|

\
|
=
|
|
.
|

\
|
+
~ + =
+ h h
h f h n
2
5 - 1
5
2
5 - 1
2
5 1
5
1
1 ) 3 ( ) (
3
3
8 1,61803398 * 1,894413
2
5 1
1,894413
h
=
|
|
.
|

\
|
+
=
h
h= O(log
1,618033988
n)= O(log n)
//archivo .h
#ifndef AVL
#define AVL
class Nodo;
class Arbol
{ private:
Nodo *a;
bool hc;
void EliminaRecursivo (int& x, bool& hd);
void AnadirR(int x, bool& hc);
void BorrarR(int x, bool& hd);
void ActualizarII(bool& hc);
void ActualizarID(bool& hc);
void ActualizarBI(bool& hd);
void ActualizarBD(bool& hd);
void RII();
void RID();
void RDD();
void RDI();
void RIIE();
void RDDE();
public:
Arbol();
Arbol( Arbol ai, int e, Arbol ad);
Arbol(const Arbol & arb);
~Arbol();
const Arbol& operator=(const Arbol& arb);
void AnadirRecursivo (int e);
void BorrarRecursivo (int x);
void Mostrar(int n=1);
};
class Nodo
{ private:
int e;
int fe;
Arbol hi,hd;
public:
Nodo (Arbol ai,int x,int fe, Arbol ad);
~ Nodo();
Arbol& Gethi(){return hi;}
Arbol& Gethd(){return hd;}
int GetInfo(){return e;}
int GetFe(){return fe;}
void Sethi(const Arbol& ai){hi=ai;}
void Sethd(const Arbol& ad){hd=ad;}
void SetInfo(int d){e=d;}
void SetFe(int fe){this->fe=fe;}
};
#endif
//fin del archivo .h
// Archivo .cpp
#include <iostream>
#include <stdlib.h>
#include <iomanip.h>
#include "ArbolAVL.h"
using namespace std;
Nodo::Nodo (Arbol ai, int x, int fe, Arbol ad)
{ e=x;
this->fe = fe;
hi =ai;
hd = ad;
}
Nodo::~Nodo()
{ }
Arbol::Arbol()
{ a=NULL;
}
Arbol:: Arbol( Arbol ai, int e, Arbol ad)
{ a= new Nodo(ai,e,0,ad);
}
Arbol::Arbol(const Arbol & arb)
{ if (arb.a==NULL)
a=NULL;
else
a=new Nodo(arb.a->Gethi(),arb.a->GetInfo(),
arb.a->GetFe(),arb.a->Gethd());
}
Arbol::~Arbol()
{ if (a)
{ cout<<a->GetInfo()<<endl;
delete a;
a=NULL;
}
}
const Arbol& Arbol::operator=(const Arbol& arb)
{ if (this!=&arb)
{ if (a!=NULL)
delete a;
if (arb.a==NULL)
a=NULL;
else
a=new Nodo(arb.a->Gethi(),arb.a->GetInfo(),
arb.a->GetFe() ,arb.a->Gethd());
}
return *this;
}
void Arbol::AnadirRecursivo (int x)
{ bool hc=false;
//hc representa si crece en altura
AnadirR(x, hc);
}
void Arbol::AnadirR(int x, bool& hc)
{ if (a == NULL)
{ a= new Nodo (Arbol(), x, 0, Arbol());
hc = true;
}
else
if (a->GetInfo()>x)
{ a->Gethi().AnadirR(x, hc);
if (hc)
ActualizarII(hc);
}
else
if (a->GetInfo()<x)
{ a->Gethd().AnadirR(x, hc);
if (hc)
ActualizarID(hc);
}
}
// Actualizar tras insertar por la izquierda
void Arbol::ActualizarII(bool &hc)
{ switch (a->GetFe())
{ case +1: a->SetFe(0);
hc=false;
break;
case 0: a->SetFe(-1);
break;
//hc = true
case -1: if (a->Gethi().a->GetFe()==-1)
RII();
else
RID();
hc = false;
break;
}
}
void Arbol::RII()
{ Nodo* p;
p= a->Gethi().a;
a->Gethi().a =p ->Gethd().a;
p->Gethd().a = a;
a->SetFe(0);
p->SetFe(0);
a= p;
}
void Arbol::RID()
{ Nodo * p1, *p2;
p1= a->Gethi().a; p2=p1->Gethd().a;
a->Gethi().a=p2->Gethd().a;
p2->Gethd().a=a;
p1->Gethd().a=p2->Gethi().a;
p2->Gethi().a= p1;
if (p2->GetFe()==-1)
{ a->SetFe(1);
p1->SetFe(0);
}
else if (p2->GetFe()==1)
{ a->SetFe(0);
p1->SetFe(-1);
}
else
{ a->SetFe(0);
p1->SetFe(0);
}
p2->SetFe(0);
a=p2;
}
// Actualizar tras insertar por la derecha
void Arbol::ActualizarID(bool &hc)
{ switch (a->GetFe())
{ case -1: a->SetFe(0);
hc = false;
break;
case 0: a->SetFe(+1);
break;
case +1: if (a->Gethd().a->GetFe()==1)
RDD();
else
RDI();
hc = false;
break;
}
}
void Arbol::RDD()
{ Nodo *p;
p= a->Gethd().a;
a->Gethd().a=p->Gethi().a;
p->Gethi().a=a;
a->SetFe(0);
p->SetFe(0);
a = p;
}
void Arbol:: RDI()
{ Nodo * p1, *p2;
p1= a->Gethd().a; p2=p1->Gethi().a;
a->Gethd().a= p2->Gethi().a;
p2->Gethi().a=a;
p1->Gethi().a=p2->Gethd().a;
p2->Gethd().a= p1;
if (p2->GetFe()==+1)
{ a->SetFe(-1);
p1->SetFe(0);
}
else if (p2->GetFe()==-1)
{ a->SetFe(0);
p1->SetFe(1);
}
else
{ a->SetFe(0);
p1->SetFe(0);
}
a=p2;
a->SetFe(0);
}
void Arbol:: BorrarRecursivo (int x)
{ bool hd; //hd representa si decrece en altura
BorrarR(x, hd);
}
void Arbol:: BorrarR (int x, bool& hd)
{ if (a == NULL)
{ cout << " no existe " << endl;
hd= false;
}
else
if (a->GetInfo()< x)
{ a->Gethd().BorrarR(x, hd);
if (hd)
ActualizarBD(hd);
}
else if (a->GetInfo() > x)
{ a-> Gethi().BorrarR(x, hd);
if (hd)
ActualizarBI(hd);
}
else //continua
if (a-> Gethi().a==NULL)
{ Nodo * aborrar;
aborrar = a;
a = a->Gethd().a;
aborrar->Gethd().a=NULL;
delete aborrar;
hd=true;
}
else
if (a->Gethd().a==NULL)
{ Nodo * aborrar;
aborrar = a;
a= a->Gethi().a;
aborrar->Gethi().a=NULL;
delete aborrar;
hd=true;
}
else
{ int s;
a->Gethi().EliminaRecursivo(s, hd);
a->SetInfo(s);
if (hd)
ActualizarBI(hd);
}
}
void Arbol::ActualizarBD(bool &hd)
{ Nodo *p1,*p2;
switch (a->GetFe())
{ case +1: a->SetFe(0);
break;
case 0: a->SetFe(-1);
hd=false;
break;
case -1: p1=a->Gethi().a;
if (p1->GetFe()==-1)
RII();
else
if (p1->GetFe()==0)
{ RIIE();
hd=false;
}
else
RID();
break;
}
}
void Arbol::RIIE()
{
Nodo* p;
p= a->Gethi().a;
a->Gethi().a=p->Gethd().a;
p->Gethd().a=a;
a->SetFe(-1);
p->SetFe(+1);
a= p;
}
void Arbol::ActualizarBI(bool &hd)
{ Nodo *p1,*p2;
switch (a->GetFe())
{ case -1: a->SetFe(0); break;
case 0: a->SetFe(+1); hd=false; break;
case +1: p1=a->Gethd().a;
if (p1->GetFe()==+1)
RDD();
else
if (p1->GetFe()==0)
{ RDDE();
hd=false;
}
else
RDI();
break;
}
}
void Arbol::RDDE()
{
Nodo *p;
p= a->Gethd().a;
a->Gethd().a=p->Gethi().a;
p->Gethi().a=a;
a->SetFe(1);
p->SetFe(-1);
a = p;
}
void Arbol::EliminaRecursivo( int &x, bool& hd)
{ if ( a->Gethd().a==NULL)
{ Nodo * aborrar = a;
x= a->GetInfo() ;
a = a->Gethi().a;
aborrar->Gethi().a=NULL;
delete aborrar;
hd=true;
}
else
{ a->Gethd().EliminaRecursivo (x, hd);
if (hd)
ActualizarBD(hd);
}
}
void Arbol::Mostrar(int n)
{ if (a !=NULL)
{ a->Gethd().Mostrar(n+1);
cout <<setw(4*n)<< a->GetInfo()<<endl;
a->Gethi().Mostrar(n+1);
}
}
// Programa principal
#include <cstdlib>
#include <iostream>
#include "ArbolAVL.h"
using namespace std;
int main()
{ Arbol a, a1;
cout<<"Arbol:"<<endl;
a.AnadirRecursivo(30);
a.AnadirRecursivo(40);
a.AnadirRecursivo(50);
a.AnadirRecursivo(45);
a.AnadirRecursivo(60);
a.AnadirRecursivo(20);
a.AnadirRecursivo(70);
a.AnadirRecursivo(57);
a.AnadirRecursivo(65);
//contina
a.AnadirRecursivo(42);
a.AnadirRecursivo(47);
a.AnadirRecursivo(10);
a.AnadirRecursivo(35);
a.AnadirRecursivo(36);
a.Mostrar();
cout <<endl;
system("PAUSE");
cout<<"Se borra el 70:"<<endl;
a.BorrarRecursivo(70);
a.Mostrar();
cout<<endl;
system("PAUSE ");
cout << "Se destruye el arbol original:" << endl;
a.~Arbol();
system("PAUSE ");
return EXIT_SUCCESS;
}
rboles B
Son rboles de bsqueda equilibrados y multicamino,
propuestos por Bayer y McCreight con las siguientes
propiedades estructurales:
La raz es una hoja o tiene entre 2 y Mr (un determinado
nmero mximo) ramas descendientes.
Todos los nodos que no son hojas (excepto la raz) tienen
entre (Mr + 1) div 2 y Mr ramas descendientes.
El nmero de claves en cada pgina interna es uno menos
que el nmero de sus ramas. Las claves de cada nodo se
encuentran ordenadas y clasifican las contenidas en las
pginas (nodos) descendientes.
Las hojas estn todas al mismo nivel y tienen entre (Mr - 1)
div 2 y Mr - 1 claves
Estructura de una pgina con m
claves
i=1..m, k
i
< k
i+1
i =1..m-1, p
i
apunta a una pgina cuyas claves son
mayores que k
i
y menores que k
i+1
p
0
k
1
p
1
k
2
p
2
... k
m
p
m
Implementacin en memoria
interna
La bsqueda en un rbol B es O(log n), siendo n el nmero de
elementos.
Aplicacin: Los arboles B son utilizados en bases de datos, donde se
procura que un nodo ocupe exactamente un bloque de disco.
La ventaja de los arboles B se encuentra en la disminucin de
posicionamientos de lectura/escritura en disco necesarios para
localizar una clave
Indexacin de archivos
Un ndice es una estructura de datos que permite el
acceso a la informacin almacenada en un archivo.
Cada elemento de un ndice contiene un campo clave
que identifica la informacin y otro campo con la
direccin del registro en el archivo que guarda la
informacin.
Las estructuras generalmente escogidas para
representar un ndice en memoria son un vector
ordenado o un rbol binario de bsqueda, en
cualquier caso clasificados por el campo clave.
Indexacin de archivos
Cuando un ndice es demasiado grande para albergarse
en memoria hay que mantenerlo en el disco. Para la
implementacin y trabajo con estos ndices que no es
posible cargar en memoria hay dos alternativas:
Seguir un planteamiento similar a cuando el ndice
est en memoria,
Utilizar rboles B
Implementacin en memoria
externa
(nmero de claves que tiene la pgina)
v indica rama vaca, no apunta a ningn registro
rbol B: insercin
Algoritmo de insercin
Insertar una clave (o elemento con campo clave)
en el lugar que le corresponde.
Si se excede el nmero de claves que se pueden
almacenar en una pgina o nodo, dividir la pgina
en dos, desplazando hacia arriba la clave central.
La clave que sube puede dar lugar a una nueva
divisin.
Consecuencias
Los rboles B crecen hacia arriba
Se asegura una ocupacin en cada pgina > 50%
Las hojas siempre estn al mismo nivel
rbol B: borrado
Localizar la clave (o elemento con campo clave) a
borrar y eliminarla, para lo cual hay que considerar:
La clave est en una hoja, en cuyo caso, para
eliminarla se desplazan a la izquierda el resto de
las claves (elementos) de la pgina
La clave no est en una hoja. Opciones:
sustituir la clave por el elemento mayor (clave
mayor) de la rama apuntada por el puntero
anterior
sustituir la clave por el elemento menor (clave
menor) de la rama apuntada por el puntero
siguiente
rbol B: borrado
Puede ocurrir que al borrar una clave (elemento), la
pgina correspondiente quede infra-ocupada
(ocupacin menor al 50%). Si esa pgina no es la
raz, habr que reorganizar el rbol y para ello hay
dos posibilidades:
Mover elementos: se aaden elementos de una
pgina vecina,
Fusin: Cuando no se pueden mover elementos
desde una pgina vecina porque la pgina vecina
elegida no tiene elementos de sobra se efecta
una fusin. La pgina infra-ocupada se une con la
vecina utilizando como elemento intermedio la
clave que las enlaza en la pgina del nivel superior
rbol B: recorrido
Bajar por la rama 0 hasta que se alcance una pgina
hoja
Recorrer secuencialmente la pgina hoja
Procesar la clave del padre y bajar por su rama
derecha aplicando el primer paso.
//archivo .h
#ifndef AB
#define AB
const int mr=5;
const int m=4;
class NodoArbolB;
class ArbolB
{ private:
NodoArbolB *a;
void BuscarEnPagina (int ClaveBuscada,
bool &Encontrada,int &Posicion);
void InsertarEnPagina(int ClaveAInsertar,
ArbolB RamaDer, int Posicion);
void DividirPagina(int Clave, ArbolB RamaD,
int Posicion, int &ClaveASubir,
ArbolB & NuevaRamaDer);
void BuscarClavePropagarDivision( int Cl,
bool & SubirClave, int &ClaveASubir,
ArbolB & NuevaRamaDer);
void BuscarClavePropagarFusion(int Cl,
bool& Encontrada);
void Menor(int& x);
void QuitarDePagina(int P);
void Arreglar( int P);
void MoverDer(int P);
void MoverIzq(int P);
void Combinar(int P);
public:
ArbolB(){a=NULL;}
~ ArbolB();
void Mostrar(int n);
void Insertar(int ClaveAInsertar);
void BuscarEnArbol (int ClaveBuscada,
bool& Encontrada, ArbolB &ArbolBConClave,
int &Posicion);
void Borrar (int ClaveABorrar);
};
class NodoArbolB
{ private :
int Cont;
int Clave[mr]; //la posicin 0 NO se considera
ArbolB Rama[mr]; //la posicin 0 se considera
public:
NodoArbolB::NodoArbolB (){Cont =0;}
NodoArbolB:: ~ NodoArbolB(){}
void SetCont(int n){Cont=n;}
void SetR(int i, const ArbolB& a){Rama[i]= a;}
void SetCl(int i, int c){Clave[i]=c;}
int GetCl(int i){return Clave[i];}
ArbolB& GetR(int i){return Rama[i];}
int GetCont(){return Cont;}
};
#endif
//fin del archivo .h
//archivo .cpp
#include <iostream>
#include <stdlib.h>
#include "A_B.h"
using namespace std;
void ArbolB::Insertar( int ClaveAInsertar)
{ bool SubirClave;
int ClaveASubir;
NodoArbolB * Nueva;
ArbolB NuevaRamaDer;
BuscarClavePropagarDivision(ClaveAInsertar,
SubirClave,ClaveASubir,NuevaRamaDer);
if (SubirClave)
{ Nueva = new NodoArbolB();
Nueva->SetCont(1);
Nueva->SetCl(1, ClaveASubir);
Nueva->GetR(1).a = NuevaRamaDer.a;
Nueva->GetR(0).a = a;
a = Nueva;
}
NuevaRamaDer.a=NULL;
}
void ArbolB::BuscarClavePropagarDivision(int Cl,
bool & SubirClave, int & ClaveASubir,
ArbolB & NuevaRamaDer)
{ int P; bool Encontrada;
if (a==NULL)
{ SubirClave = true; ClaveASubir = Cl;
NuevaRamaDer.a = NULL;
}
else
{ BuscarEnPagina(Cl, Encontrada, P);
if (Encontrada)
{ cout << Cl <<" est repetida " << endl;
SubirClave = false;
}
else
{ a->GetR(P).BuscarClavePropagarDivision(Cl,
SubirClave, ClaveASubir, NuevaRamaDer);
if (SubirClave)
if (a->GetCont() < m)
{ InsertarEnPagina(ClaveASubir, NuevaRamaDer, P);
SubirClave = false;
}
else
DividirPagina(ClaveASubir, NuevaRamaDer, P,
ClaveASubir, NuevaRamaDer);
}
}
}
void ArbolB::InsertarEnPagina(int ClaveAInsertar, ArbolB
RamaDer, int Posicion)
{ int I;
for (I = a->GetCont(); I >= Posicion + 1; I--)
{ a->SetCl(I+1, a->GetCl(I));
a->GetR(I+1).a=a->GetR(I).a;
a->GetR(I).a= NULL;
}
a->SetCl(Posicion + 1, ClaveAInsertar);
a->GetR(Posicion + 1).a = RamaDer.a;
a->SetCont(a->GetCont()+1);
RamaDer.a=NULL;
}
void ArbolB::DividirPagina(int Clave, ArbolB RamaD,
int Posicion, int &ClaveASubir, ArbolB & NuevaRamaDer)
{ int I, Medio;
if (Posicion <= m / 2)
Medio = m / 2;
else
Medio = m / 2 + 1;
NuevaRamaDer.a = new NodoArbolB();
for (I = Medio + 1; I <= m; I++)
{ NuevaRamaDer.a->SetCl(I-Medio, a->GetCl(I));
NuevaRamaDer.a->GetR(I-Medio).a = a->GetR(I).a;
a->GetR(I).a = NULL;
}
NuevaRamaDer.a->SetCont( m - Medio);
a->SetCont( Medio);
if (Posicion <= m / 2)
InsertarEnPagina(Clave, RamaD, Posicion);
else
NuevaRamaDer.InsertarEnPagina( Clave, RamaD,
Posicion-Medio);
ClaveASubir = a->GetCl(a->GetCont());
NuevaRamaDer.a->GetR(0).a = a->GetR(a->GetCont()).a;
a->GetR(a->GetCont()).a=NULL;
a->SetCont( a->GetCont()-1);
RamaD.a=NULL;
}
void ArbolB::BuscarEnPagina (int ClaveBuscada,
bool &Encontrada,int &Posicion)
{ if (ClaveBuscada < a->GetCl(1))
{ Encontrada = false;
Posicion = 0;
}
else
{ Posicion = a->GetCont();
while (ClaveBuscada < a->GetCl(Posicion))
Posicion --;
Encontrada = (ClaveBuscada == a->GetCl(Posicion));
}
}
void ArbolB::BuscarEnArbol (int ClaveBuscada,
bool& Encontrada, ArbolB &Pagina, int &Posicion)
{ if (a==NULL)
Encontrada = false;
else
{ BuscarEnPagina (ClaveBuscada, Encontrada, Posicion);
if (Encontrada)
Pagina.a = a;
else
a->GetR(Posicion).BuscarEnArbol(ClaveBuscada,
Encontrada,Pagina, Posicion);
}
}
void ArbolB::Mostrar(int n)
{ int I;
if (a!=NULL)
{ a->GetR(0).Mostrar(n+1);
cout.width(10*n);
for (I = 1; I <= a->GetCont(); I++)
cout <<a->GetCl(I)<<" ";
cout << endl;
for (I = 1; I <= a->GetCont(); I++)
a->GetR(I).Mostrar(n+1);
}
}
ArbolB::~ ArbolB()
{if (a) delete a;}
void ArbolB::Borrar (int ClaveABorrar)
{ bool Encontrada;
ArbolB Auxi;
BuscarClavePropagarFusion(ClaveABorrar, Encontrada);
if (! Encontrada)
cout <<ClaveABorrar<<" no esta en el arbol"<<endl;
else
if (a->GetCont() == 0)
{ Auxi.a = a;
a = a->GetR(0).a;
Auxi.a->GetR(0).a=NULL;
Auxi.a->GetR(1).a=NULL;
delete Auxi.a;
}
Auxi.a=NULL;
}
void ArbolB::BuscarClavePropagarFusion(int Cl,
bool &Encontrada)
{ int P;
int Sucesora;
if (a==NULL)
Encontrada = false;
else
{ BuscarEnPagina(Cl, Encontrada,P);
if (Encontrada)
if (a->GetR(P-1).a == NULL)
QuitarDePagina(P);
else
{ a->GetR(P).Menor(Sucesora);
a->SetCl(P,Sucesora);
a->GetR(P).BuscarClavePropagarFusion(Sucesora,
Encontrada);
}
else
a->GetR(P).BuscarClavePropagarFusion(Cl,
Encontrada);
if ((a->GetR(P).a != NULL)
&& (a->GetR(P).a->GetCont() < m / 2))
Arreglar(P);
}
}
void ArbolB::Menor(int & x)
{ if (a->GetR(0).a == NULL)
x = a->GetCl(1);
else
a->GetR(0).Menor(x);
}
void ArbolB::QuitarDePagina( int P)
{ int J;
for (J = P+1; J <= a->GetCont(); J++)
{ a->SetCl(J-1, a->GetCl(J));
a->GetR(J-1).a = a->GetR(J).a;
}
a->GetR(a->GetCont()).a = NULL;
a->SetCont(a->GetCont()-1);
}
void ArbolB::Arreglar(int P)
{ if (P > 0)
if (a->GetR(P-1).a->GetCont() > m / 2)
MoverDer(P);
else
Combinar(P);
else
if (a->GetR(1).a->GetCont() > m / 2)
MoverIzq(1);
else
Combinar(1);
}
void ArbolB::MoverDer(int P)
{ int J;
for (J = a->GetR(P).a->GetCont(); J >= 1; J--)
{ a->GetR(P).a->SetCl(J+1, a->GetR(P).a->GetCl(J));
a->GetR(P).a->GetR(J+1).a = a->GetR(P).
a->GetR(J).a;
a->GetR(P).a->GetR(J).a = NULL;
}
a->GetR(P).a->SetCont(a->GetR(P).a->GetCont() +1);
a->GetR(P).a->GetR(1).a = a->GetR(P).a->GetR(0).a;
a->GetR(P).a->SetCl(1, a->GetCl(P));
a->SetCl(P, a->GetR(P-1).a->GetCl(a->GetR(P-1).
a->GetCont()));
a->GetR(P).a->GetR(0).a = a->GetR(P-1).
a->GetR(a->GetR(P-1).a->GetCont()).a;
a->GetR(P-1).a->GetR(a->GetR(P-1).
a->GetCont()).a=NULL;
a->GetR(P-1).a->SetCont(a->GetR(P-1).a->GetCont()-1);
}
void ArbolB::MoverIzq(int P)
{ int J;
a->GetR(P-1).a->SetCont(a->GetR(P-1).
a->GetCont()+1);
a->GetR(P-1).a->SetCl(a->GetR(P-1).a->GetCont(),
a->GetCl(P));
a->GetR(P-1).a->GetR(a->GetR(P-1).a->GetCont()).a =
a->GetR(P).a->GetR(0).a;
a->SetCl(P, a->GetR(P).a->GetCl(1));
a->GetR(P).a->GetR(0).a = a->GetR(P).a->GetR(1).a;
a->GetR(P).a->SetCont(a->GetR(P).a->GetCont()-1);
for (J = 1; J <= a->GetR(P).a->GetCont(); J++)
{ a->GetR(P).a->SetCl(J, a->GetR(P).a->GetCl(J+1));
a->GetR(P).a->GetR(J).a = a->GetR(P).a->GetR(J+1).a;
a->GetR(P).a->GetR(J+1).a=NULL;
}
}
void ArbolB::Combinar(int P)
{ int J;
ArbolB Auxider, Auxiizq;
Auxider.a = a->GetR(P).a;
Auxiizq.a = a->GetR(P-1).a;
Auxiizq.a->SetCont(Auxiizq.a->GetCont()+1);
Auxiizq.a->SetCl(Auxiizq.a->GetCont(), a->GetCl(P));
Auxiizq.a->GetR(Auxiizq.a->GetCont()).a =
Auxider.a->GetR(0).a;
Auxider.a->GetR(0).a=NULL;
for (J = 1; J <= Auxider.a->GetCont(); J++)
{ Auxiizq.a->SetCont(Auxiizq.a->GetCont()+1);
Auxiizq.a->SetCl(Auxiizq.a->GetCont(),
Auxider.a->GetCl(J));
Auxiizq.a->GetR(Auxiizq.a->GetCont()).a =
Auxider.a->GetR(J).a;
Auxider.a->GetR(J).a=NULL;
}
delete Auxider.a;
Auxider.a=NULL;
QuitarDePagina(P);
Auxiizq.a=NULL;
}
//fin del archivo .cpp
//Programa principal
#include <iostream>
#include <stdlib.h>
#include "A_B.h"
using namespace std;
int main(int argc, char *argv[])
{
ArbolB a1=ArbolB(), a2=ArbolB();
int Cl;
int Opcion, P;
bool Encontrada;
char ch;
do
{ cout <<"1 Insertar"<< endl;
cout <<"2 Borrar"<< endl;
cout <<"3 Mostrar"<< endl;
cout <<"4 Fin"<< endl;
do
{ cout <<"elija opcion "<< endl;
cin >> Opcion;
}while (Opcion < 1 || Opcion > 4);
switch (Opcion)
{ case 1: cout <<"Clave a insertar: " <<endl;
cin >>Cl ;
Encontrada = false;
a1.BuscarEnArbol(Cl, Encontrada, a2, P );
if (!Encontrada)
a1.Insertar( Cl);
else
cout <<"La clave ya existe" << endl;
break;
case 2: cout <<"Clave a eliminar: "<<endl;
cin >>Cl;
a1.Borrar( Cl);
break;
case 3: a1.Mostrar(1);
break;
}
cout <<"Pulse una tecla para continuar" << endl;
ch = getchar();
putchar(ch);
}while (Opcion != 4);
cout <<endl;
system("PAUSE ");
return EXIT_SUCCESS;
}
Preguntas?

Potrebbero piacerti anche