Bienvenido(a), Visitante. Favor de ingresar o registrarse.

Ingresar con nombre de usuario, contraseña y duración de la sesión

Foros del Club

Páginas: [1]   Ir Abajo
  Enviar tema  |  Imprimir  
Autor Tema: Copiar elemento de un nodo de un Arbol Binario en C.  (Leído 2019 veces)
0 Usuarios y 1 Visitante están viendo este tema.
fercamm
Guru
***

Prestigio: 0
Desconectado Desconectado

Sexo: Masculino
Mensajes: 3


SuiGenerisNet.com.ar


WWW
« en: 28/07/2006, 16:27:00 »

Buenas.
Este es un ejercicio que me tomaron en un exámen reciente de la facultad y quería saber si lo que hice está bien o no.
Les paso el ejercicio completo que hice para darles una idea de qué es y al final hago mi pregunta concreta.
El ejercicio consiste en hacer una fc. que espeje un árbol. Es decir. Si el árbol A tiene en la raíz un 1, en el hijo izquierdo un 2 y en el derecho un 3, el nuevo árbol B tendrá que tener raíz 1, hijo izquierdo 3 e hijo derecho 2. Así con todos los elementos.

typedef struct TNodo
             {
                 void *elem;
                 struct TNodo *Izq,*Der;
             } TNodo;

typedef struct
             {
                 TNodo *Raiz, Corriente;
                 int tamaniodato;
             }TDA_AB;

int ABO_Espejar (TDA_AB A, TDA_AB *B)
{
    int memoria;
    if !(A.Raiz) return 0;//Arbol A vacío.
    if (B.Raiz) return 1; //Arbol B ya cargado.
    if !(memcpy(A.Raiz->elem,B.Raiz->elem,A.tamaniodato)) return 2;//mem. insuf.
    Recursiva(A.Raiz,B.Raiz,A.tamaniodato,&memoria);
    return(memoria);//Si memoria=2 falta memoria. Si memoria=3 está todo OK.
}
/*memcpy copia elementos void. Del 1º campo copia al 2º y ocupa lo que dice el
3º campo. ABO_Espejar consiste en: Dan un árbol binario A y los elementos de A
se copian en B pero en forma de espejo. Es decir: el hijo izq de la raiz de A
queda como hijo der de la raiz de B... y así. Copia la raiz de A en la raiz de B
luego llama a recursiva. ABO_Espejar retorna el valor de "memoria"*/
int Recursiva (TNodo *PNodo, TNodo *Otro, int dato, int *memoria)
{
    if (PNodo->Izq)
    {
        if !(memcpy(PNodo->Izq->elem,Otro->Der->elem,dato)) memoria=2;
        Recursiva (PNodo->Izq,Otro->Der,dato,memoria);
    }
    if (PNodo->Der)
    {
        if !(memcpy(PNodo->Der->elem,Otro->Izq->elem,dato)) memoria=2;
        Recursiva(PNodo->Der,Otro->Izq,dato,memoria);
    }
}
/*Verifica que haya nodo en la izquierda en el árbol A. Si lo hay, copia el
elemento en la derecha del árbol B (si no puede copiar memoria toma el valor 2).
Luego llama a la misma función recursiva yendo al nodo izquierdo del árbol A y
al nodo derecho (recientemente copiado) del árbol B. Lo mismo realiza en el
nodo derecho.*/

Bueno... acá va mi duda:
Yo tengo que copiar (con el ejemplo que dí anteriormente) un elemento de A y pegarlo en B. Si yo uso esa fc. memcpy estoy copiando el elemento en, por ejemplo, Otro->Izq->elem... Eso de copiar el elemento en ese nodo está ok (yo estoy accediendo al elemento a que apunta ese nodo), pero ese nodo existe? Se puede ingresar a ese nodo de esa forma? Porque (no sé bien esta parte) Otro->Izq apunta (o es) NULL. Entonces mi otra forma (que esto NO hice en el exámen) era copiar el nodo de la forma: Otro->Izq=PNodo->Der y así, a la vez, se copiarán los elementos (creo). El único problema de esto es que el árbol seguramente puede ser muy grande, y yo le estaría pasando mucha información incorrecta y de más al árbol B (y sólo quiero pasarle el nodo en cuestión y que no apunte a ningún otro). Es decir... si estoy copiando el nº 3 (como el ejemplo que dí), si el nº 3 del árbol A tuviese otros hijos (u hojas) estaría copiándoselas a B también.
Mmmmmmmmm... no sé si se entiendió o no, pero ya me mareo =D

Otra cosa que tiene mucho que ver con esto, pero que sería como "a parte" es:
yo uso cosas como "if !(PNodo->Izq)" y realmente no sé bien por qué se usa así... pero sé que quiere decir que "si no existe PNodo-Izq...". si pasa que no existe PNodo->Izq es que está apuntando a NULL? O sea PNodo->Izq == NULL? Y si PNodo-Izq existe, a qué apunta? O sea... PNodo->Izq == ¿a qué? :S

Espero que puedan ayudarme ya que es una de las cosas que me faltan entender por si me fue mal :D

Desde ya, muchas gracias!

PD: Perdón por tantas preguntas, pero esta parte es algo que no me quedó claro y me gustaría entenderla.
En línea
CID
Administrador
Legend
*****

Prestigio: 22
Desconectado Desconectado

Sexo: Masculino
Estudiante de: Arte de la informática
Título universitario: Programador
Profesión: Desarrollador
Mensajes: 1136



WWW
Lenguajes:
Varios
Bases de datos:
Varios
« Respuesta #1 en: 28/07/2006, 17:22:14 »

Hola.
Por lo que leo tenés problemas enormes con punteros, los manejas... pero mecánicamente.
Con respector a tu primer pregunta:
Yo tengo que copiar (con el ejemplo que dí anteriormente) un elemento de A y pegarlo en B. Si yo uso esa fc. memcpy estoy copiando el elemento en, por ejemplo, Otro->Izq->elem... Eso de copiar el elemento en ese nodo está ok (yo estoy accediendo al elemento a que apunta ese nodo), pero ese nodo existe? Se puede ingresar a ese nodo de esa forma? Porque (no sé bien esta parte) Otro->Izq apunta (o es) NULL. Entonces mi otra forma (que esto NO hice en el exámen) era copiar el nodo de la forma: Otro->Izq=PNodo->Der y así, a la vez, se copiarán los elementos (creo). El único problema de esto es que el árbol seguramente puede ser muy grande, y yo le estaría pasando mucha información incorrecta y de más al árbol B (y sólo quiero pasarle el nodo en cuestión y que no apunte a ningún otro). Es decir... si estoy copiando el nº 3 (como el ejemplo que dí), si el nº 3 del árbol A tuviese otros hijos (u hojas) estaría copiándoselas a B también.
Mmmmmmmmm... no sé si se entiendió o no, pero ya me mareo =D

Código
memcpy
<string.h>
 
void *  memcpy ( void * dest, const void * src, size_t num );
 
Copy bytes to buffer from buffer.
 Copies num bytes from src buffer to memory location pointed by dest.
 
Parameters.
 
dest
   Destination buffer where data is copied.
src
   Source buffer to copy from.
num
   Number of bytes to copy.
 
Return Value.
 dest is returned.

memcpy hace una copia exacta (de num bytes) de una posición de memoria (src) a otra (dest).
Es lo mismo que tener:

Código
int i = 5, j;
j = i;

Copia por valor.
Cuando se trabaja con punteros, se intenta no realizar muchas copias por valor. Precisamente la idea de usar punteros es que es mucho más eficiente apuntar a distintas direcciones de memoria que andar copiando todo el buffer de un lugar a otro.

Con respecto a la siguiente duda (el nodo existe?):
Volvamos a la definición de puntero: Un puntero es una variable que contiene una dirección de memoria o NULL.
La práctica usual con punteros es, al crearlos, inicializarlos a NULL. De esa manera nos aseguramos que no estemos trabajando con basura.

Código
TIPO *Puntero = NULL;

Una vez hecho eso, a Puntero le podemos asignar lo que queramos y hacer de él lo que se nos ocurra.
Ahora bien, el nodo existe?... la pregunta seria: el puntero, apunta a un nodo creado?

Nada más facil que colocar

Código
if(Puntero != NULL) ...
//Equivalentemente
if(Puntero) ...

Más adelante en tu pregunta colocas: Otro->Izq=PNodo->Der
Ahi estás copiando direcciones de memorias entre punteros. Es lo que querias hacer? solo vos lo sabrás. Solo te digo que hace esa linea.

Otra cosa que tiene mucho que ver con esto, pero que sería como "a parte" es:
yo uso cosas como "if !(PNodo->Izq)" y realmente no sé bien por qué se usa así... pero sé que quiere decir que "si no existe PNodo-Izq...". si pasa que no existe PNodo->Izq es que está apuntando a NULL? O sea PNodo->Izq == NULL? Y si PNodo-Izq existe, a qué apunta? O sea... PNodo->Izq == ¿a qué? :S

Código
if !(PNodo->Izq) // es equivalente a
if( PNodo->Izq != NULL)

Es decir, si tiene una dirección de memoria válida. Con válida no quiero decir que apunte a donde vos queres que lo haga, sino que apunta a una dirección de memoria que es no invalida (no NULL).

Seguramente alguna vez he tenido que hacer un algoritmo asi, pero no recuerdo como lo programé.
Creo que para espejar un arbol binario solo necesitas intercambiar los punteros de IZQ a DER y viceversa.
Te armo una función al vuelo que intercambie los valores de dos punteros:

Código
void intercambiarP(TNodo *Izq,TNodo *Der)
{
TNodo *aux;
aux = Izq;
Izq = Der;
Der = aux;
}
 

Ahora podes usar esa función dentro de una recursiva que recorra todo el arbol.

Espero te sirva, y hayas comprendido que programar no es algo mecánico, se debe entender lo que se está haciendo. (Como todo en la vida Sonrisa)
Saludos.
En línea

Foros del Club
   

 En línea
Páginas: [1]   Ir Arriba
  Enviar tema  |  Imprimir  
 
Ir a: