C01 - Departamento de Electrónica

Anuncio
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
ELO320 Estructuras de Datos y Algoritmos
Solución Certamen 01
#include <stdlib.h>
#include <stdio.h>
#define MAX 5
typedef struct nn
{ int i1;
int i2;
struct nn * next;
} nodo, * pnodo;
pnodo lista1=NULL;
pnodo lista2=NULL;
pnodo getnodo(void)
{ pnodo p;
if( (p=(pnodo)malloc(sizeof(nodo)))==NULL) return(NULL); else return(p);
}
void Push(pnodo *ref, int dato1, int dato2)
{ pnodo newnodo;
if ( (newnodo=getnodo( )) == NULL) exit(1);
newnodo->i1 = dato1; newnodo->i2 = dato2; newnodo->next = *ref;
*ref = newnodo;
}
void crealista(void)
{ int i;
for(i=0; i<MAX; i++)
{ Push(&lista1, i, i+1);
}
Push(&lista2, MAX-i, i-1);
}
pnodo busca(pnodo pp)
{ pnodo qq=NULL;
while (pp !=NULL) {qq = pp; pp = pp->next;}
return (qq);
}
pnodo busca2(pnodo p, int j, pnodo q)
{
if(p !=NULL)
{ while( p->i1 != j ) p = p->next;
if (p != NULL)
while (q !=NULL) { if(p->i2 == q->i1) return(q);
return (NULL);
}
return(NULL);
}
Prof. Leopoldo Silva Bijit.
20-08-2004
q = q->next; }
1
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
ELO320 Estructuras de Datos y Algoritmos
Solución Certamen 01
int main(void)
{ pnodo tt;
crealista();
printf(" %d \n", ( *(busca(lista1)) ).i1);
printf(" %d \n", busca(lista2)->i2);
if( (tt=busca2(lista1, 3, lista2)) !=NULL) printf(" %d \n", tt->i2);
return(0);
}
a) Explicar, empleando un diagrama, el paso por referencia de Push. 10 puntos.
b) Diagrama de la estructura después de ejecutar crealista(); 20 puntos.
c) Explicar acción realizada por busca. 20 puntos.
d) Explicar acción realizada por busca2. 30 puntos.
e) Determinar qué imprime el programa. 20 puntos.
Solución.
a) En la función crealista, se tiene un ejemplo de uso de Push.
Consideremos el llamado: Push(&lista1, 0, 1).
En la definición de Push, el primer argumento es un puntero a puntero a nodo.
Dentro de la función, la ocurrencia de *ref, denota a la variable, cuya dirección es
pasada en la invocación a la función, en el caso del ejemplo referencia a variable
global lista1.
Si *ref, aparece a la derecha, formando parte de una expresión, su valor es el
almacenado en lista1; si aparece a la izquierda, se escribe en la variable lista.
Luego de la invocación a la función, se tiene el siguiente esquema para las
variables.
Datos
Stack
Lista1
newnodo
?
ref
dato1 = 0
dato2 = 1
Nótese que los argumentos son variables almacenadas en el stack, iniciadas con
los valores de los parámetros de la invocación. La variable local newnodo, al no
estar inicializada en su definición apunta a cualquier lado. Razón por la cual,
conviene definirlas e inicializarlas simultáneamente.
Después de un llamado exitoso a getnodo(); es decir, malloc asignó una
estructura en el heap, un diagrama de la situación es el siguiente:
Prof. Leopoldo Silva Bijit.
20-08-2004
2
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
ELO320 Estructuras de Datos y Algoritmos
Solución Certamen 01
Datos
Stack
heap
Lista1
newnodo
i1 = ?
ref
i2 = ?
dato1 = 0
next = ?
dato2 = 1
El resto de la función, escribe en los campos de la estructura creada en el heap. Y
además, en último término, sobreescribe en la variable global lista1(en el ejemplo
que se analiza).
Datos
Stack
heap
Lista1
newnodo
i1 = 0
ref
i2 = 1
dato1 = 0
next
dato2 = 1
Al salir de Push, desaparecen las variables automáticas, ubicadas en el stack, y
la situación queda:
Datos
Stack
heap
Lista1
i1 = 0
i2 = 1
next
Si se hubiera pasado solamente un puntero a nodo como referencia, se tendría el
diseño:
Prof. Leopoldo Silva Bijit.
20-08-2004
3
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
ELO320 Estructuras de Datos y Algoritmos
Solución Certamen 01
void Push2(pnodo ref, int dato1, int dato2)
{
pnodo newnodo;
if ( (newnodo=getnodo()) == NULL) exit(1);
newnodo->i1 = dato1;
newnodo->i2 = dato2;
newnodo->next = ref;
ref = newnodo;
}
Y un ejemplo de uso, sería:
Push2(lista1, 0, 1);
Lo cual no es equivalente al diseño anterior. Puede comprobarse efectuando un
diagrama.
Las listas con cabecera ( header ) permiten diseños alternativos.
b) Después de crealista, el espacio queda:
Datos
Lista1
Lista2
heap
i1=4
i1 = 3
i1 = 2
i1 = 1
i1 = 0
i2 = 5
i2 = 4
i2 = 3
i2 = 2
i2 = 1
next
next
next
next
next
i1 =1
i1 = 2
i1 = 3
i1 = 4
i1 = 5
i2 = 3
i2 = 2
i2 = 1
i2 = 0
next
next
next
next
i2 = -1
next
c) A la función busca, se le pasa la dirección del primer nodo de la lista. Si la
lista es vacía, retorna un puntero nulo. Si no es vacía, con pp recorre la lista,
dejando qq apuntado al nodo corriente y con pp al próximo. Cuando se llega con
pp, al final de la lista, qq apunta al último nodo de la lista.
d) La función busca2 intenta encontrar el valor j en el campo i1 del nodo
apuntado por el argumento p. Si la lista es vacía retorna un puntero nulo; en
caso de encontrar el valor j, busca a partir del nodo apuntado por q, el valor del
campo i1 que sea igual al valor del campo i2 del nodo donde quedó apuntando p.
Si lo encuentra, retorna un puntero al nodo que cumple la condición anterior; en
caso contrario, retorna un puntero nulo.
La invocación: busca2(lista1, 3, lista2), después del primer while, deja p
apuntando al segundo nodo de la lista1, el segundo while deja q apuntando al
cuarto nodo de la lista2; ya que busca en ésta el valor 4 en el campo i1.
Prof. Leopoldo Silva Bijit.
20-08-2004
4
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
ELO320 Estructuras de Datos y Algoritmos
Solución Certamen 01
El diseño de la función incurre en un error frecuente, en este tipo de problemas.
¿Qué ocurre si el valor j no se encuentra en ningún campo i1 de la lista apuntada
por p?.
Cuando p tome valor nulo, intentará leer p->i1 en las primeras direcciones de
memoria, las cuales suelen pertenecer a un segmento del sistema operativo. Lo
más seguro que la ejecución del proceso aborte debido a un error de
segmentación.
Se podría corregir, cambiando:
while( p->i1 != j ) p = p->next;
por:
while ((p != NULL)&&( p->i1 != j )) p = p->next;
Lo cual funciona debido a que el and opera con cortocircuito.
e) En primer término imprime el campo i1 del último nodo de la lista1.
Luego el campo i2 del último nodo de la lista2.
Finalmente el campo i2 de la lista 2, cuyo campo i1 es 4; ya que en la lista1, el
campo i2 es 4, cuando el campo i1 es 3.
Imprimiría:
0
-1
0
Prof. Leopoldo Silva Bijit.
20-08-2004
5
Descargar