Sei sulla pagina 1di 9

Los arboles binarios nacen de un nodo padre y puede tener 2 hijos, a su vez un nodo hijo se puede convertir en padre

y puede tener dos hijos, la idea es que no pueden ser mas de 2 por eso lo de binario, un hijo no puede tener mas de un padre. Esto entonces son una lista con doble enlaze la diferencia con las listas doblemente enlazadas es que un puntero va a a la derecha y el otro a la izquierda (graficamente hablando ya que el computador no reconoce eso) no hay uno de vuelta. Ahora si el arbol binario es ordenado el hijo la izquiera y toda la descendencia que va a la izquierda tiene que ser menor que el padre y la descendencia de la derecha mayor. ej: 10 <- padre /\ 7 15 /\/\ 5 8 NULL 17 /\\ NULL NULL NULL ese es un ejemplo grafico simple de un arbol binario ordenado. Ahora ya empiezo con codigo c++. /*definicion del nodo (estructura del arbol binario)*/ struct nodo{ int info;/*numero de cada elemento del arbol*/ struct nodo *izq ; /*apunta al hijo inquierdo*/ struct nodo *der; /*apunta al nodo derecho*/ } typedef struct nodo *ptrnodo; ptrnodo l,a,b,p; /*crea variables del tipo nodo, l sera el que tenga el primer numero*/ /*ahora comienza el manejo del programa, copia esto en un texto si esta desordenado*/ int main() { int temporal; char op; l=NULL; do{ cout<<"ing numero: "; cin>>temporal; p=new nodo; p->info=temporal; p->der=NULL; p->izq=NULL; if (l==NULL) { l=p; } else { a=NULL;

a=l; while(a!=NULL) { if(a->info>p->info) { if(a->izq!=NULL) a=a->izq; else a->izq=p; } if(a->info<p->info) { if(a->der!=NULL) a=a->der; else a->der=p; } } } cout<<"desea ing otro n s/n: "; cin>>op; }while(op=='s'); /*Ya esta listo un ingreso de un arbol binario ordenado,ahora una busqueda*/ a=l; cout<<"ING N A BUSCAR: "; cin>>temporal; while(a!=NULL) { if(temporal<a->info) a=a->izq; else if(temporal>a->der) a=a->der; else break; } if(a!=NULL) cout<<"El numero fue encontrado";/*ESTA APUNTADO POR a*/ else cout<<"Numero no esta en el arbol"; /*ahora el eliminar te lo dejo a ti, aunque te dejo lo que es como una regla de eliminado. cuando necesita eliminar un nodo que no tiene hijos solo eliminas y enlazas el ultimo a NULL (para cerrar ese lado del arbol), si solo tiene un hijo solo enlazas el padre del a eliminar si es que tiene con el hijo del a eliminar y luego simplemente borras, para eliminar un arbol con mas de 1 hijo es mas complicado, en ese caso tienes que buscar el sucesor mas cercano del a eliminar. Bueno espero que te sirva de ayuda, y si tienes una duda me preguntas. saludos Enrique Quargnolo*/ return 0;

//Tu rbol en C++ #include <iostream> using namespace std; class Nodo { private: int v; Nodo* izq,* der; friend class Arbol; public: Nodo(int v = 0) { this->v = v; izq = der = NULL; } }; class Arbol { private: Nodo* raiz; public: void Insertar(Nodo*&, int); void Preorden(Nodo*); }; void Arbol::Insertar(Nodo* &r, int v) { if(!r) { r = new Nodo(v); return; } Insertar(v < r-> v ? r->izq : r->der, v); } void Arbol::Preorden(Nodo* r) { if(r) { cout << r->v << " "; Preorden(r->izq); Preorden(r->der);

} } int main() { Nodo* raiz = NULL; Arbol a; //. . . (5) //. . ./ . .\ //. (2) . .(7) //. . . . . . \ //. . . . . . (9) //Preorden: 5, 2, 7, 9 a.Insertar(raiz, 5); a.Insertar(raiz, 7); a.Insertar(raiz, 2); a.Insertar(raiz, 9); a.Preorden(raiz); cout << endl; system("pause"); return 0; }

1.8 Estructura de la informacin (III) 4.4 rboles Los rboles son estructuras parecidas a las listas enlazadas ( 1.8), en el sentido que tienen punteros que sealan a otros elementos, pero no tienen una estructura lgica de tipo "lineal" o secuencial como aquellas, sino ramificada. Tienen aspecto de rbol, de ah su nombre (ver figura ). Su estudio desde el punto de vista matemtico pertenece a la teora de grafos; desde el punto de vista informtico son estructuras de datos, lo que significa que cada elemento, denominado nodo u hoja, contiene uno o ms valores. Su estudio corresponde a la teora de bases de datos, y en esta terminologa, los nodos que "cuelgan" de otros, se denominan hijos ("child nodes"). Cada hoja puede tener un mximo de hijos; es lo que se denomina grado mximo del rbol ("maximun degree"). Si no tiene ninguno, se dice que es un nodo terminal. Son especialmente interesantes y tiles los rboles ordenados (denominados B-trees). Esto significa que para su construccin, los nodos que se van agregando no se colocan al azar, colgando de cualquier nodo existente, sino segn un criterio que tiene en consideracin el "valor" de la hoja. Este tipo de estructura se usa extensivamente en las bases de datos [3] y en los sistemas de ficheros [1]. En los btrees se distinguen varios parmetros que son determinantes en cuanto a su idoneidad como estructuras de datos. El primero es el mximo nmero de hijos (y datos) que puede tener cada hoja; es lo que se denomina grado mximo del rbol ("maximun degree"). El nmero de hijos de una hoja o nodo, puede variar desde ninguno (nodos terminales) al mximun degree. Otro parmetro importante es el nmero

mnimo de datos que puede contener un nodo, grado mnimo ("minimun degree"). Este valor es utilizado en los procesos de insercin de nuevos datos, y determina la forma en que se desdoblan los nodos existentes para acomodar los nuevos valores (el conjunto debe permanecer ordenado). Generalmente cada hoja de un rbol es en s misma una estructura de datos. Uno o varios los campos de esta estructura se utilizan para la ordenacin (campos-ndice), y desde luego se exige que exista un criterio de ordenacin para los valores de estos campos. Es decir: que se establezca una regla por la que se pueda determinar de forma inequvoca si dos valores son iguales, o desiguales, y en este ltimo caso cual precede en el orden (este orden suele ser numrico o alfabtico [2]).

Como ejemplo, construiremos un programa que acepte caracteres por el teclado y construya un rbol binario ( 1.8b) cuyos elementos contengan el carcter introducido y estn ordenados segn su valor ASCII. En la Fig. 1 se muestra grficamente el resultado de introducir los caracteres: b, D, g, A, E y k.

El programa acepta caracteres indefinidamente (mientras exista memoria suficiente, o se pulse ESC). Despus de la introduccin de cada nuevo elemento, se muestra ordenadamente la totalidad del rbol. #include <iostream.h> struct base { char let; struct base* izq; struct base* der; } *rz, *aptr; // Ejemplo de creacin de rbol binario

// declara tipo de estructura a utilizar // para almacenar carcter // puntero izquierdo // puntero derecho // rz puntero al nodo raz; aptr puntero auxiliar

int incluir(char letra, struct base* puntero); void inorden (struct base* puntero); char acepta (void); // aceptar datos por teclado void main(void) { // ========================= char c; while ( (c = acepta()) != 27) { // Bucle principal if (incluir(c, rz)) break; inorden(rz); } } char acepta (void) { // Introducir datos por teclado char c; cout << "\n Pulse un carcter + [CR] ";

while (1) { c = getchar(); if (c == 10) continue; return c; } }

// 10 == New Line

int incluir(char letr, struct base* ptr) { // aadir elemento if (rz == NULL) { // 1o. solo la primera vez!!! rz = (struct base*) malloc(sizeof(base)); if (rz == NULL) { cout << "NO hay memoria suficiente!!" << endl; return 1; } rz->let = letr; rz->izq = rz->der = NULL; return 0; } if (letr == ptr->let) return 0; // 2o. El carcter ya existe if (letr < ptr->let) { // 3o. if (ptr->izq == NULL) { // enlace libre: incluir aptr = (struct base*) malloc(sizeof(base)); if (aptr == NULL) { cout << "NO queda suficiente memoria" << endl; return 1; } aptr->let = letr; aptr->izq = aptr->der = NULL; ptr->izq = aptr; return 0; } if (incluir(letr, ptr->izq)) // ocupado: seguir buscando return 1; // falla la insercin } if (letr > ptr->let) { // 4o. if (ptr->der == NULL) { // enlace libre: incluir aptr = (struct base*) malloc(sizeof(base)); if (aptr == NULL) { cout << "NO queda suficiente memoria" << endl; return 1; } aptr->let = letr; aptr->izq = aptr->der = NULL; ptr->der = aptr; return 0; } if (incluir(letr, ptr->der)) // ocupado: seguir buscando return 1; // falla la insercin } return 0; }

void inorden (struct base* ptr) { if (ptr == NULL) return; inorden(ptr->izq); cout << " - " << ptr->let; inorden(ptr->der); } Comentario

// Recorrer rbol

La primera parte declara la estructura, base, que ser utilizada en cada nodo; contiene un carcter para alojar el introducido por teclado, y los dos punteros que necesitan los elementos de los rboles binarios. Adems se definen dos punteros-a-base; uno de ellos, rz, apuntar desde el primer momento al nodo raz; el otro, aptr, es un puntero auxiliar que se necesita en la funcin incluir. Adems de main, el programa solo tiene tres sencillas funciones: incluir, que incluye cada nuevo elemento en el rbol con el carcter pulsado; inorden, que recorre el rbol ordenadamente mostrando en pantalla los caracteres, y acepta, que simplemente captura los datos del teclado. La funcin main consiste en un bucle que acepta indefinidamente caracteres del teclado (mientras no se pulse la tecla Escape); inserta en el rbol el carcter introducido, y finalmente muestra la totalidad del rbol hasta el momento. El proceso se termina si por alguna razn (por ejemplo, falta de memoria) falla el proceso de insertar el carcter, en cuyo caso la funcin incluir devuelve 1. La funcin acepta no merece ningn comentario; aunque quizs se podra haber afinado un poco ms para no aceptar secuencias de escape (caracteres no imprimibles 3.2.3e); simplemente letras maysculas, o minsculas, dgitos, etc. Puesto que se ha utilizado la funcin getchar, es necesario pulsar tambin Intro con cada insercin. Puede sorprender la extremada simplicidad de la funcin inorden; esta funcin recursiva recorre la totalidad del rbol mostrando de forma ordenada el carcter contenido en cada elemento. Es de destacar que en realidad la funcin: void recorrido (struct base* ptr) { if (ptr == NULL) return; recorrido(ptr->izq); recorrido(ptr->der); } recorrera la totalidad del rbol pasando por todos los nodos. Para recorrerlo en las formas preorden y postorden ( 1.8b), habra que sustituir inorden por las funciones que se indican a continuacin. Observe que la diferencia es pequesima entre las tres; simplemente la posicin del la sentencia que muestra el carcter en pantalla. void preorden (struct base* ptr) { if (ptr == NULL) return; cout << " - " << ptr->let; preorden(ptr->izq); preorden(ptr->der); } // recorrido preorden

void postorden (struct base* ptr) { if (ptr == NULL) return; postorden(ptr->izq); postorden(ptr->der); cout << " - " << ptr->let; }

// recorrido postorden

La funcin incluir, que crea cada nuevo nodo del rbol con el carcter introducido, es recursiva (como muchas de las que tratan con rboles) y muy sencilla, pero merece algn comentario: El cuerpo del primer if, solo se ejecuta la primera vez, cuando incluir es invocada desde main despus de introducido el primer carcter, y el puntero rz tiene todava su valor de inicializacin (NULL 4.2.1). Este valor previo para rz y aptr es proporcionado directamente por el compilador en el momento de la declaracin de estas variables globales. Este bloque se encarga de la creacin del nodo raz (en adelante, durante todo el programa rz seala a dicho nodo). A este respecto, obsrvese que incluir siempre es invocada desde main con el valor rz como argumento, es decir, el proceso de inclusin se inicia siempre empezando por la raz del rbol. En este bloque hay que resaltar las sentencias encargadas de asignar memoria para el nuevo elemento. Estas sentencias se repiten cada vez que se crea un elemento nuevo (en los if 3 y 4), y contienen un mecanismo de control que avisa si la memoria disponible se ha agotado: ptr = (struct base*) malloc(sizeof(base)); if (ptr == NULL) { cout << "NO hay memoria suficiente!!" << endl; return 1; } El manual de la Librera Estndar nos seala que a la funcin malloc hay que pasarle un entero con el tamao del bloque de memoria que queremos reservar -en nuestro caso sizeof(base)-, y que devuelve un puntero a la zona de memoria asignada o un NULL si falla en el intento (cosa que aprovechamos). Observe que al valor malloc(sizeof(base)) le aplicamos un "casting" ( 4.9.9) antes de asignarlo a ptr; de lo contrario se obtendra un error. Nota: tambin se podra utilizar el operador new ( 4.9.20), ms moderno que malloc; las sentencias anteriores seran entonces: if ((ptr = new(base)) == NULL) { cout << "NO hay memoria suficiente!!" << endl; return 1; } Cualquiera que fuese la funcin utilizada para crear los nuevos elementos, hay que considerar que tanto new como malloc reservan espacio del montn. En un programa real en el que se construyeran rboles como el presente, a fin de evitar prdidas de memoria cuando ya no fuesen necesarios, deberan tenerse en cuenta las observaciones respecto a la persistencia de este tipo de objetos ( 1.3.2). El segundo if simplemente no hace nada, pero acepta la entrada como vlida. Ocurre cuando el carcter ya existe previamente en el rbol (se ha repetido). El cuerpo de este bloque podra modificarse

fcilmente. Por ejemplo, para incluir un contador que sealara cuantas repeticiones se han pulsado de cada tecla. Para esto, en el diseo de la estructura base incluiramos un campo numrico que inicializaramos a cero e incrementaramos con cada repeticin. Sugerencia: en este caso tambin podramos definir sendas variables globales: total y repet, que mostraran el total de elementos en el rbol y el total de repeticiones. Sus valores se actualizaran fcilmente en la funcin inorden, o despus de cada entrada en la propia funcin incluir. El tercero y el cuarto if son los encargados de la creacin de los nuevos nodos despus de creado el nodo raz. Cuando llega a este punto, el nodo raz ya existe, el rbol es ya ms o menos grande y la invocacin se ha realizado desde main, o se trata de una de las mltiples recursiones posibles. Mediante estas recursiones, incluir trepa (aqu deberamos decir desciende) por el rbol siguiendo los enlaces izquierdos si el carcter a incluir es menor que el de los nodos que se va encontrando y a la inversa si es mayor. Cuando encuentra un nodo terminal adecuado, con el enlace izquierdo o derecho libre (respectivamente), solicita memoria; rellena los datos del nuevo nodo y lo cuelga del nodo terminal encontrado, cuyo enlace izquierdo o derecho se actualiza. El nodo recin incluido es ahora terminal; sus dos enlaces estn a cero y contiene el nuevo carcter. En este momento la funcin termina devolviendo el valor 0 (finalizacin con xito), y el control vuelve a main, donde seguir el bucle mediante la invocacin de inorden...

Potrebbero piacerti anche