Académique Documents
Professionnel Documents
Culture Documents
Código
#include <iostream>
#include <cstdlib>
using namespace std;
struct nodo{
int nro;
struct nodo *izq, *der;
};
ABB crearNodo(int x)
{
ABB nuevoNodo = new(struct nodo);
nuevoNodo->nro = x;
nuevoNodo->izq = NULL;
nuevoNodo->der = NULL;
return nuevoNodo;
}
void insertar(ABB &arbol, int x)
{
if(arbol==NULL)
{
arbol = crearNodo(x);
}
else if(x < arbol->nro)
insertar(arbol->izq, x);
else if(x > arbol->nro)
insertar(arbol->der, x);
}
verArbol(arbol->izq, n+1);
}
int main()
{
ABB arbol = NULL; // creado Arbol
system("pause");
return 0;
}
1. INTRODUCCIÓN.
La búsqueda en árboles binarios es un método de búsqueda simple, dinámico y
eficiente considerado como uno de los fundamentales en Ciencia de la
Computación. De toda la terminología sobre árboles,tan sólo recordar que la
propiedad que define un árbol binario es que cada nodo tiene a lo más un hijo a la
izquierda y uno a la derecha.Para construir los algoritmos consideraremos que
cada nodo contiene un registro con un valor clave a través del cual efectuaremos
las búsquedas.En las implementaciones que presentaremos sólo se considerará en
cada nodo del árbol un valor del tipo tElemento aunque en un caso general ese
tipo estará compuesto por dos:una clave indicando el campo por el cual se realiza
la ordenación y una información asociada a dicha clave o visto de otra forma,una
información que puede ser compuesta en la cual existe definido un orden.
if(!t)
return FALSE
else if(t->etiqueta==x)
return TRUE;
else if(t->etiqueta>x)
return pertenece(x,t->hizqda);
else return pertenece(x,t->hdrcha);
}
if(!(*t)){
*t=(nodoABB)malloc(sizeof(struct tipoceldaABB));
if(!(*t)){
error("Memoria Insuficiente.");
}
(*t)->etiqueta=x;
(*t)->hizqda=NULL;
(*t)->hdrcha=NULL;
} else if(x<(*t)->etiqueta)
inserta(x,&((*t)->hizqda));
else
inserta(x,&((*t)->hdrcha));
}
Por ejemplo supongamos que queremos construir un ABB a partir del conjunto
de enteros {10,5,14,7,12} aplicando reiteradamente el proceso de inserción.El
resultado es el que muestra la figura 2.
Es fácil ver que si un árbol binario con n nodos está completo (todos los nodos no
hojas tienen dos hijos) y así ningún camino tendrá más de 1+log2n nodos.Por
otro lado,las operaciones pertenece e inserta toman una cantidad de tiempo
constante en un nodo.Por tanto,en estos árboles, el camino que forman desde la
raíz,la secuencia de nodos que determinan la búsqueda o la inserción, es de
longitud O(log2n),y el tiempo total consumido para seguir el camino es
también O(log2n).
Terminaremos este apartado con algunos comentarios sobre los borrados en los
ABB.Es evidente que si el elemento a borrar está en una hoja bastaría
eliminarla,pero si el elemento está en un nodo interior,eliminándolo,podríamos
desconectar el árbol.Para evitar que esto suceda se sigue el siguiente
procedimiento:si el nodo a borrar u tiene sólo un hijo se sustituye u por ese hijo y
el ABB quedar&aacue; construido.Si u tiene dos hijos,se encuentra el menor
elemento de los descendientes del hijo derecho(o el mayor de los descendientes
del hijo izquierdo) y se coloca en lugar de u,de forma que se continúe
manteniendo la propiedad de ABB.
Los Árboles son las estructuras de datos mas utilizadas, pero también una de las mas
complejas, Los Árboles se caracterizan por almacenar sus nodos en forma jerárquica y no en
forma lineal como las Listas Ligadas, Colas,Pilas,etc., de las cuales ya hemos hablado en días
pasados.
Fig. 1: La imagen muestra la diferencia entra las estructuras de datos lineas y las no lineales
como lo son los Árboles.
Fig.
2: La imagen muestra de forma gráfica cuales son los nodos Raíz, Rama, Hoja.
Fig.3: La siguiente imagen muestra de forma gráfica los nodos Padre, Hijo y Hermanos
Los arboles a demas de los nodos tiene otras propiedades importantes que son utilizadas en
diferente ámbitos los cuales son:
Nivel: Nos referimos como nivel a cada generación dentro del árbol. Por ejemplo, cuando a un
nodo hoja le agregamos un hijo, el nodo hoja pasa a ser un nodo rama pero a demas el árbol
crece una generación por lo que el Árbol tiene un nivel mas.Cada generación tiene un número
de Nivel distinto que las demas generaciones.
Un árbol vacío tiene 0 niveles
El nivel de la Raíz es 1
El nivel de cada nodo se calculado contando cuantos nodos existen sobre el, hasta
llegar a la raíz + 1, y de forma inversa también se podría, contar cuantos nodos existes
desde la raíz hasta el nodo buscado + 1.
Fig. 6:
Imagen que nuestra dos Árboles con Orden = 2(Izquierda) y un segundo con Orden =
3(Derecha).
Notemos que un Árbol con Orden = 1 no tendría sentido ya que seria una estructura lineal. ya
que cada nodo solo podría tener un Hijo y tendríamos un Árbol como la Imagen de la Fig.1.
Este valor no lo calculamos, si no que ya lo debemos conocer cuando diseñamos nuestra
estructura, ya que si queremos calcular esto lo que obtendremos es el grado(hablamos de el
continuación).
Grado: El grado se refiere al número mayor de hijos que tiene alguno de los nodos del Árbol y
esta limitado por el Orden, ya que este indica el número máximo de hijos que puede tener un
nodo.
Fig. 7:
En la imagen podemos apreciar un Árbol con grado 2(Izquierda) y un otro con grado
3(Derecha).
El grado se calcula contando de forma recursiva el número de hijos de cada sub-árbol hijo y el
numero de hijos del nodo actual para tomar el mayor, esta operación se hace de forma recursiva
para recorrer todo el árbol.
grado = max(contarHijos(hijo1),contarHijos(hijo2), contarHijos(hijoN), contarHijos(this))
Sub-Árbol: Conocemos como Sub-Árbol a todo Árbol generado a partir de una sección
determinada del Árbol, Por lo que podemos decir que un Árbol es un nodo Raíz con N Sub-
Árboles.
Fig. 8: En la imagen de puede apreciar que un Árbol esta compuesto por una seria de Sub-
Arboles los cual conforman toda la estructura.
Existen escenarios donde podemos sacar un Sub-Árboles del Árbol para procesarlo de forma
separada, de esta forma el Sub-Árboles pasa a ser un Árbol independiente, También podemos
eliminar Sub-Árboles completos, Agregarlos,entre otras operaciones.
Árbol n-ario
los arboles n-arios son aquellos arboles donde el número máximo de hijos por nodo es de N,
en la figura 7 podemos apreciar dos árboles con grado 2 y grado 3, estos dos arboles también
los podemos definir como Árbol n-ario con n = 2 y n=3 respectivamente.
Árboles binarios
Esta estructura se caracteriza por que cada nodo solo puede tener máximo 2 hijo, dicho de otra
manera es un Árbol n-ario de Grado 2.
Fig. 9: En la imagen podemos apreciar un Árbol Binario.
Árbol binario lleno: Es aquel que el que todos los nodos tiene cero o 2 hijos con excepción de
la Raíz.
Búsquedas no informadas
Las búsquedas no informadas son aquellas en que se realiza el viaje por todo el árbol sin tener
una pista de donde pueda estar el dato deseado. Este tipo de búsquedas también se conocen
como búsquedas a ciegas.
Para comprender mejor que es una búsqueda no informada expondremos el siguiente ejemplo:
Imagine que vamos por la carretera y de repente encontramos dos caminos, el problema a qui
es que uno después de 50 kilómetros esta en construcción y el otro nos lleva a nuestro destino,
sin embargo ninguno de los caminos tiene señalamiento. Lo que tendríamos que hacer es
recorrer el primero camino y después de 50 kilómetros encontrarnos con que el camino esta en
construcción, entonces tendríamos que regresar para irnos por el segundo camino,el cual nos
lleva a nuestro destino(Para esto ya recorrimos los 50 kilómetros de ida y los 50 kilómetros de
regreso lo que nos da 100 kilómetros mas a nuestra ruta).
A este tipo de escenarios en los cuales las búsquedas de hacen a ciegas los conocemos como
búsquedas no informadas.
Las siguientes métodos de búsqueda que veremos a continuación(Búsqueda en profundad y
Búsqueda en amplitud) pertenecen a las búsquedas no informadas.
Búsqueda en profundidad
Recorrido Pre-orden: El recorrido inicia en la Raíz y luego se recorre en pre-orden cada
unos de los sub-árboles de izquierda a derecha.
Esta definición puede ser un poco compleja de entender por lo que mejor les dejo la siguiente
imagen.
Fig. 12:En la imagen podemos ver el orden en que es recorrido el árbol iniciando desde la
Raíz.
Búsqueda en amplitud.
Se recorre primero la raíz, luego se recorren los demas nodos ordenados por el nivel al que
pertenecen en orden de Izquierda a derecha.
Este tipo de búsqueda se caracteriza por que la búsqueda se hace nivel por nivel y de izquierda
a derecha.
Fig. 18: En la
imagen se observa como es que un nodo es buscado mediante la búsqueda en profundidad.
En la imagen podemos observa que el árbol es recorrido en su totalidad pero esto no siempre
es a sí, ya que el algoritmo se detiene cuando el elemento buscado es encontrado.
Si observamos el código de forma minuciosa podemos observar dos puntos muy interesantes,
el primero es que esta función no es recursiva, y la segunda es que se utiliza una Cola para
controlar el flujo del recorrido.
Los pasos para hacer el recorrido es el siguiente:
Conclusiones
Como hemos observado los arboles son estructuras bastante complejas, tiene una gran
aplicaciones en la ciencia y en la programación convencional. En los últimos años este tipo de
estructuras ha sido utilizadas con mucha frecuencia en la Inteligencia artificial.
En esta publicación hemos visto los puntos vas relevantes a en cuenta a lo que son los arboles
y los principales métodos de búsqueda, sin embargo estamos lejos de cubrir este tema en
profundidad ya que existen muchísimos tipos de operaciones y algoritmos que se pueden
realizar sobre estas estructuras de datos.
Espero que este información te sirve de utilidad y no olvides darle like y recomendar esta
publicación ya que esto me servirá para crear mas y mejor material.
Arbol Binario de Busqueda !!!
CODIGO COMPLETO AQUI !!!
#1 Mensaje por Diabliyo » 06/02/2005 10:25 pm
Hola:
-Insercion
-Recorridos
-Busquedas
-Alturas
-Nodos
-Podar
---------------> DESCARGALO <----------------
CÓDIGO: SELECCIONAR TODO
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
struct arbol
{
int dato;
struct arbol *izq;
struct arbol *der;
}*raiz;
/*PROTOTIPOS*/
void inicializar( void );
int vacio( struct arbol *hoja );
int eshoja( struct arbol *hoja );
struct arbol *insertar( struct arbol *raiz, struct
arbol *hoja, int num );
int busqueda( struct arbol *hoja, int num );
int alturax( struct arbol *hoja, int num );
int alturafull( struct arbol *hoja, int *altura );
void auxaltura( struct arbol *hoja, int *altura, int
cont );
int nodos( struct arbol *hoja );
void auxnodos( struct arbol *hoja, int *cont );
struct arbol *borrarx( struct arbol *hoja, int num
);
struct arbol *podar( struct arbol *hoja );
void preorden( struct arbol *hoja );
void inorden( struct arbol *hoja );
void posorden( struct arbol *hoja );
void menu_recorridos( void );
void menu_busquedas( void );
void menu_alturas( void );
void menu_nodos( void );
void menu_podar( void );
while( hoja )
{
if( num==hoja->dato ) return altura;
else
{
altura++;
if( num<hoja->dato ) hoja= hoja-
>izq;
else hoja= hoja->der;
}
}
return FALSO;
}
(*cont)++;
auxnodos( hoja->izq, cont );
auxnodos( hoja->der, cont );
}
podar( hoja->izq );
podar( hoja->der );
free( hoja );
hoja= NULL;
return hoja;
}
/*Recorridos*/
inorden( hoja->izq );
printf( "%i ", hoja->dato );
inorden( hoja->der );
}
posorden( hoja->izq );
posorden( hoja->der );
printf( "%i ", hoja->dato );
}
while( _op!='4' )
{
clrscr();
printf( "1. PreOrden." );
printf( "\n2. InOrden." );
printf( "\n3. PosOrden." );
printf( "\n4. Salir." );
printf( "\n\n:: " );
_op= getch();
switch( _op )
{
case '1':
preorden( raiz );
getch();
break;
case '2':
inorden( raiz );
getch();
break;
case '3':
posorden( raiz );
getch();
break;
}
}
return;
}
while( _op!='3' )
{
clrscr();
printf( "1. Altura de Un Nodo \(
Profundidad \). " );
printf( "\n2. Altura de Todo el Arbol."
);
printf( "\n3. Salir." );
printf( "\n\n:: " );
_op= getch();
switch( _op )
{
case '1':
printf( "\n\nNumero: " );
scanf( "%i", &val );
altura= alturax( raiz, val );
if( !altura ) printf(
"\n\nImposible, numero inexistente." );
else printf( "\n\nLa Altura
es: %i", altura );
getch();
break;
case '2':
altura= 0;
printf( "\n\nLa Altura del
Arbol es: %i", alturafull( raiz, &altura ) );
getch();
break;
}
}
return;
}
while( _op!='3' )
{
clrscr();
printf( "1. Podar Un Nodos del Arbol." );
printf( "\n2. Podar Todo el Arbol." );
printf( "\n3. Salir." );
_op= getch();
switch( _op )
{
case '1':
printf( "\n\nNumero: " );
scanf( "%i", &val );
raiz= borrarx( raiz, val );
printf( "\n\n.... Borrado
...." );
break;
case '2':
raiz= podar( raiz );
printf( "\n\nArbol Borrado por
Completo." );
getch();
break;
}
}
return;
}
int main()
{
char _op='A';
int val;
inicializar();
while( _op!='S' )
{
clrscr();
printf( "Insertar." );
printf( "\nRecorridos." );
printf( "\nBusquedas." );
printf( "\nAlturas." );
printf( "\nNodos." );
printf( "\nPodar." );
printf( "\nSalir." );
printf( "\n\n:: " );
_op= toupper( getch() );
switch( _op )
{
case 'I':
printf( "\n\nNumero: " );
scanf( "%i", &val );
if( busqueda( raiz, val ) )
{
printf( "\n\nEste numero
ya ha sido insertado." );
getch();
break;
}
raiz= insertar( raiz, raiz,
val );
break;
case 'R':
if( vacio( raiz ) )
{
printf( "\n\nEl Arbol Aun
esta Vacio." );
getch();
break;
}
menu_recorridos();
break;
case 'B':
if( vacio( raiz ) )
{
printf( "\n\nEl Arbol Aun
esta Vacio." );
getch();
break;
}
menu_busquedas();
break;
case 'A':
if( vacio( raiz ) )
{
printf( "\n\nEl Arbol Aun
esta Vacio." );
getch();
break;
}
menu_alturas();
break;
case 'N':
if( vacio( raiz ) )
{
printf( "\n\nEl Arbol Aun
esta Vacio." );
getch();
break;
}
menu_nodos();
break;
case 'P':
if( vacio( raiz ) )
{
printf( "\n\nEl Arbol Aun
esta Vacio." );
getch();
break;
}
menu_podar();
break;
}
}
printf( "\n\nPulsa para salir..." );
getchar();
return 0;
}
byeeeeeee
Gracias!!
Código:
private:
class nodo { //nodo del arbol binario
public:
T info;
arbin<T> izq, der;
nodo (const T & e=T(), const arbin<T> &ni=arbin(), const arbin<T> & nd=arbin()):
info(e), izq(ni), der(nd) {}
};
typedef nodo* nodoptr;
nodoptr raiz;
};
Volver arriba
Volver arriba
Código:
Arbol.Izquierdo(12);
Arbol.Nodo = Arbol.hIzquierdo;
Arbol.Izquierdo(3);
Arbol.Nodo = Arbol.hIzquierdo;
Arbol.Derecho(55);
Arbol.Izquierdo(50);
Arbol.Toma(10); // Asignamos un valor al
for(int i=0;i<Nodo.Length;i++)
Console.WriteLine("Nodo["+i+"] El der
Console.ReadKey();
}
suerte
mrcone
343
Gracias, pero la salida del código no tiene nada que ver con lo que quiero. – akko el 20 dic. 16 a las 3:03
añade un comentario
voto a favor0votar en contra
Con el código que esta en el blog de Martin Cruz, hice una modificación en la función de
mostrar implementando la función gotoxy(), la cual comparta a continuación.
int auxX = 0;//Variable publica.
auxX = 0;//se debe reestablecer a 0 cada vez que se desea llamar la función
mostrarArbol(miArbol,0);
return;
}
mostrarArbol(miArbol -> izq,auxY+2);//Se para hasta el nodo mas a la izquierda del árbol construye
primero el subarbol izq porque sus valores en X son menores
cout << miArbol -> dato << endl << endl;//Muestra el dato del nodo respectivo
mostrarArbol(miArbol -> der,auxY+2);//Se para hasta el nodo mas a la derecho del árbol
//Se debe tener el cuenta el funcionamiento de la recursividad la cual implementa una pila para almacenar
las instrucciones
}//
compartirmejorar esta respuesta
editada el 19 nov. 17 a las 14:55
Johnny
932211
respondida el 19 nov. 17 a las 3:11
Jorge Pinzon
12
Gracias Johnny así es como quería que se viera el código y la explicación, es la primera vez que hago un
aporte en este sitio, gracias nuevamente. – Jorge Pinzon el 19 nov. 17 a las 17:18
añade un comentario
lemonde066
Nuevo Miembro
Mensajes: 2
o
como estan amigos. he buscado en internet y en muchos codigos fuente, pero mi duda surge
porque no logro que me ordene los datos en preorden, inorden y postorden?. imprimo los valores
cada vez que los ingreso al arbol para verificar que si estan entrando; pero a la hora de llamar a mi
funcion dependiendo que tipo de orden quiero se queda en overflow; segun he revisado y al
parecer me toma la raiz =NULL. no tengo mucha experiencia como programador y menos en
arboles
utilizo turbo c++ IDE en una pentium IV de 3 ghz.
pd. en el "case" existen opciones que he puesto pero aun no tienen su funcion respeciva.
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define NULL 0
int nodo;
int cuenta_nodos=0;
int contador[6];
void menu(void);
void inserta(struct arbol *raiz, int nodo);
void preorden(struct arbol *raiz);
void inorden(struct arbol *raiz);
void postorden(struct arbol *raiz);
struct arbol
{
int dato;
struct arbol *izq;
struct arbol *der;
};
struct arbol *raiz=NULL;
main(void)
{
clrscr();
menu();
getch();
return 0;
}
void menu(void)
{clrscr();
int opcion;
gotoxy(1,30);cout<<("1...ingresar nodo");
gotoxy(1,31);cout<<("2...ordenar en preorden");
gotoxy(1,32);cout<<("3...ordenar en inorden");
gotoxy(1,33);cout<<("4...ordenar en postorden");
gotoxy(1,34);cout<<("5...cuantos nodos tiene el arbol ");
gotoxy(1,35);cout<<("6...cual es el valor maximo ");
gotoxy(1,36);cout<<("7...promedio valor de los nodos");
gotoxy(1,37);cout<<("0...salir");
gotoxy(1,38);cin>>opcion;
switch(opcion)
{ case 1:
{ for (int j=0;j<7;j++)
{ gotoxy(1,1);cout<<("ingresa valor");
gotoxy(18,1);cin>>nodo;
inserta(raiz,nodo);
}
menu(); break;
}
case 2: { preorden(raiz);
getch();
menu(); break;
}
case 3: { inorden(raiz);
menu(); break;
}
case 4: { postorden(raiz);
getch();
menu(); break;
}
case 5: { gotoxy(1,15); cout<<("tiene",cuenta_nodos);
getch();
menu(); break;
}
case 0:
{ break ;}
default:
menu();
}
}
void inserta (arbol *raiz,int nodo)
{
if (raiz==NULL)
{
raiz=(arbol *)malloc(sizeof(arbol*));
raiz->dato=nodo;
cuenta_nodos=cuenta_nodos+1;
contador[cuenta_nodos]=nodo;
raiz->izq=raiz->der=NULL;
gotoxy(15,2); cout<<("la raiz es ",raiz->dato);
gotoxy(20,4); cout<<("el nodo derecho es:", raiz->der);
gotoxy(5,4); cout<<("el nodo izquierdo es:", raiz->izq);
gotoxy(30,1); cout<<("ef",contador);
gotoxy(45,1); cout<<contador[cuenta_nodos];
getch();
}
else
if (raiz->dato < nodo)
{ inserta(raiz->der,nodo);}
else
if (raiz->dato >nodo)
{ inserta (raiz->izq, nodo);}
}
El código es el siguiente:
int Evalua(NodoB n,ArbolB T)
{
char ident;
EtiquetaArbolB(&c,n,T);
switch(c){
case '+':
return Evalua(HijoIzqdaB(n,T),T)+Evalua(HijoDrchaB(n,T),T);
break;
case '-':
return Evalua(HijoIzqdaB(n,T),T)-Evalua(HijoDrchaB(n,T),T);
break;
case '*':
return Evalua(HijoIzqdaB(n,T),T)*Evalua(HijoDrchaB(n,T),T);
break;
case '/':
return Evalua(HijoIzqdaB(n,T),T)/Evalua(HijoDrchaB(n,T),T);
break;
default:
return valor(c);
}
}
char *preorden="GEAIBMCLDFKJH";
char *inorden="IABEGLDCFMKHJ";
char *postorden;
/*---------------------------------------*/
if(n!=0){
pos[n-1]=pre[0];
longIzqda=strchr(in,pre[0])-in;
post (pre+1,in,pos,longIzqda);
post (pre+1+longIzqda,in+1+longIzqda,pos+longIzqda,n-1-longIzqda);
}
}
/*----------------------------------------*/
aux=strlen(preorden);
postorden=(char *)malloc(aux*sizeof(char));
if (postorden){
printf("El preorden es: %s\n",preorden);
printf("El inorden es: %s\n",inorden);
post(preorden,inorden,postorden,aux);
postorden[aux]='\0';
printf("El postorden calculado es: %s\n",postorden);
free(postorden);
}
else{
fprintf(stderr,"Error: Sin memoria\n");
return 1;
}
return 0;
}
El código es el siguiente:
/*Fichero: comprobar.c */
/*---------------------------------------*/
p=CrearPila(sizeof(NodoB));
et=malloc(tamano);
if(!et){
.... /*Error:Sin memoria*/
}
aux=NODOB_NULO;
Push(&aux,p);
nodoActual=RaizB(T);
fin=0;
while(!fin){
while(nodoActual!=NODOB_NULO){
Push(&nodoActual,p);
nodoActual=HijoIzqdaB(nodoActual,T);
}
Tope(&nodoActual,p);
Pop(p);
if (nodoActual!=NODOB_NULO){
EtiquetaArbolB(et,nodoActual,T);
(*EscribirElemento)(et);
nodoActual=HijoDrchaB(nodoActual,T);
}
else fin=1;
}
free(et);
DestruirPila(p);
}
El código es el siguiente:
void Refleja(ArbolB T)
{
ArbolB Ti,Td;
if(T!=ARBOLB_VACIO){
Ti=PodarHijoIzqdaB(RaizB(T),T);
Td=PodarHijoDrchaB(RaizB(T),T);
Refleja(Ti);
InsertarHijoDrchaB(RaizB(T),Ti,T);
Refleja(Td);
InsertarHijoIzqdaB(RaizB(T),Td,T);
}
}