Diseño

Anuncio
1
Capítulo 2.
Definición de Estructuras de Datos en C.
Se desea conocer las técnicas para diseñar estructuras de datos. Se repasan los conceptos de
tipos básicos, para luego desarrollar las herramientas de creación de nuevas estructuras,
haciendo énfasis en los conceptos de agrupación y vinculación. Dando ejemplos que
posteriormente se emplearán en el texto.
2.1. Tipos primitivos.
En los lenguajes de programación suele disponerse de tipos básicos o primitivos: caracteres,
enteros con y sin signo, reales o flotantes de simple y doble precisión.
Se dispone la forma de definir e inicializar variables de esos tipos, y también la forma de
escribir constantes de esos tipos.
Para los tipos primitivos existen numerosos y variados operadores que permiten construir
expresiones con variables y constantes de dichos tipos. En determinados casos existen
mecanismos automáticos para convertir valores de un tipo en otro, sin embargo es preferible la
conversión explícita a través del molde o “cast”.
Mediante las bibliotecas de entrada-salida pueden ingresarse o desplegarse valores de esos
tipos.
2.2. Mecanismos de estructuración.
Existen dos mecanismos básicos de estructuración de datos: la agrupación y la vinculación.
2.2.1. Grupos básicos.
La estructura (struct) permite agrupar elementos de diferente tipo. El arreglo agrupa elementos
de igual tipo. El string agrupa caracteres.
Profesor Leopoldo Silva Bijit
20-01-2010
2
Estructuras de Datos y Algoritmos
Estructura
Arreglo
String
Figura 2.1. Agrupaciones de datos.
Se dispone de una forma de definir variables de esos grupos básicos, y los mecanismos de
acceso a las componentes: el discriminador del campo (un punto) para las estructuras; y los
paréntesis cuadrados o corchetes para delimitar el índice de la componente del arreglo. Las
operaciones que están definidas para estos grupos básicos son muy reducidas, el programador
debe crear sus propias funciones o métodos para efectuar operaciones más complejas sobre
estos grupos básicos. En el caso de strings existe una biblioteca estándar de funciones que los
manipulan (ver Apéndice 2).
Las agrupaciones pueden ser tan complejas como sea necesario: ya que es posible crear arreglos
de estructuras, y también estructuras que contengan arreglos y strings.
2.2.2. Vínculos.
Pueden establecerse relaciones entre elementos de datos. Los siguientes diagramas ilustran las
formas básicas de vinculación: vínculos de orden o secuencia en listas, relaciones jerárquicas en
árboles, e interconexiones complejas en grafos.
árboles
listas
grafos
Figura 2.2. Vínculos entre componentes de datos.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
3
El vínculo es el elemento de datos de una componente que permite accesar a otra componente.
Una componente puede contener información de uno o más vínculos.
El programador debe disponer de elementos del lenguaje que le permitan crear nuevos tipos de
datos, y mediante estos tipos crear funciones o métodos que realicen operaciones sobre las
componentes.
Cuando el número máximo de componentes es conocido de antemano, las componentes pueden
modelarse como una serie de arreglos agrupados en una estructura. En la cual se emplea uno o
varios arreglos para establecer el o los vínculos entre las componentes. Se suele definir como
cursor a una variable que contiene el valor del índice de una componente.
Otro mecanismo para establecer vínculos es el puntero, que es una variable que contiene la
dirección de otra componente. La vinculación a través de punteros suele emplearse
preferentemente en situaciones dinámicas, en las cuales el número de las componentes varía
durante la ejecución del programa; esto debido a que se crean, insertan y descartan
componentes.
2.3. Ejemplos basados en arreglos.
2.3.1. Acceso a componentes del arreglo.
El acceso a componentes se realiza vía indirección de un puntero constante que es el nombre del
arreglo, con un offset dado por el índice del elemento.
Se definen tipos de datos.
typedef int Tipo;
/* tipo de item del arreglo */
typedef int Indice; /* tipo del índice */
Es práctica usual, definir mediante una constante el tamaño máximo del arreglo
#define MaxEntradas 10
Se definen e inician con valores dos arreglos
Tipo A[MaxEntradas]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Tipo B[MaxEntradas]={ 10,11,12,13,14,15,16,17,18,19};
A las funciones que manipulan arreglos se les suele pasar el arreglo por referencia.
Por ejemplo la función que imprime en una línea las componentes de un arreglo a.
void mostrar(Tipo *a, Indice inferior, Indice superior)
{
Indice i;
for (i = inferior; i <= superior; i++) printf(" %d ", a[i]);
putchar('\n');
}
Note que el primer argumento de la función también puede escribirse: Tipo a[].
Profesor Leopoldo Silva Bijit
20-01-2010
4
Estructuras de Datos y Algoritmos
Ejemplos de uso:
mostrar(A, 0, 4); imprime 0 1 2 3 4
mostrar(A+2, 0, 4); imprime 2 3 4 5 6
La manipulación de arreglos no suele verificar el rango del índice. En el caso de haberse
definido adyacentes los arreglos A y B, la referencia a A[12] está accesando efectivamente a
B[2], por eso se muestra un 12; pero es un error por acceso fuera de rango.
printf(" %d
printf(" %d
printf(" %d
printf(" %d
printf(" %d
\n", A[12]); imprime 12
\n", B[-2]);
imprime 8
\n", A[-1]); imprime cualquier cosa que estuviera almacenada antes de A
\n", 1[-1+B] ); imprime 10
\n", -1[B] ); imprime -11 (es una referencia correcta)
Similares errores pueden generarse accesando componentes indireccionando vía puntero:
printf(" %d \n", *(A+12)); imprime 12
printf(" %d \n", *(-2+B)); imprime 8
Los ejemplos anteriores ilustran que el acceso a componentes de un arreglo se efectúa mediante
indirección con el puntero que es el nombre del arreglo.
La expresión: A[c] se interpreta como el contenido de la dirección:
A + c*(tamaño del tipo del arreglo).
Donde A es la dirección de la primera componente del arreglo.
Empleando el lenguaje:
A[c] equivale a: *(A+c) y A es equivalente a &A[0].
Definición de matrices.
Puede definirse una matriz de caracteres, arr, de R renglones y C columnas mediante:
#define R 8 //renglones
#define C 10 //columnas
char arr[R][C];
arr
arr[3][5]
arr[3]
Figura 2.2.a. Matriz de caracteres
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
5
Entonces: arr[3] es el cuarto renglón de la matriz arr, y es un arreglo de C caracteres. Puede
considerarse que arr[3] es la dirección de inicio de ese arreglo; es decir, es un puntero constante
que indica la primera componente de ese arreglo. Puede escribirse, usando notación de punteros
como: *(arr+3).
La expresión: a[3][5], denota el sexto carácter del cuarto renglón. La cual puede escribirse,
usando notación con punteros, mediante: * ( *(arr+3) + 5 ).
Puede concluirse que arr es un puntero a un puntero a carácter.
Definición de arreglo de arreglos.
Empleando definición de tipos puede crearse el tipo renglón, como un arreglo de C caracteres.
Y mediante este nuevo tipo puede definirse una matriz ar, como un arreglo de renglones.
Definiciones que se muestran a continuación.
#define R 8 //renglones
#define C 10 //columnas
typedef char renglon[C];
renglon ar[R];
La expresión ar[3] es el cuarto renglón. La expresión: * ( *(ar+3) + 5 ) corresponde al sexto
carácter almacenado en el cuarto renglón, y es equivalente a: ar[3][5].
Con el mismo procedimiento se pueden estructurar organizaciones más complejas. Por ejemplo
una matriz cuyo contenido sea un arreglo.
Los arreglos aseguran que las componentes quedan adyacentes en memoria. En el caso de
matrices, el último elemento del primer renglón queda adyacente con el primer elemento del
segundo renglón.
Arreglo de punteros a renglones.
Un ejemplo de creación de estructuras de datos, empleando el lenguaje C, es diseñar un arreglo
de punteros pt, que apunten a los renglones de una matriz.
pt
ar
(*pt[2])[5]
Figura 2.2.b. Arreglo de punteros a arreglos de caracteres
Profesor Leopoldo Silva Bijit
20-01-2010
6
Estructuras de Datos y Algoritmos
Las siguientes declaraciones de tipos y definiciones de variables, crean el espacio que
almacenará a la estructura de datos.
typedef char renglon[C]; //definición de tipo renglón como un arreglo de C caracteres
typedef renglon * prenglon; //definición del tipo puntero a renglón
renglon ar[R];
//Matriz de caracteres como arreglo de renglones
prenglon pt[R];
//Arreglo de punteros a los renglones.
Es preciso vincular los punteros del arreglo con los renglones, lo cual se efectúa con:
for(i=0; i<R; i++) pt[i]=&ar[i]; //llena arreglo de punteros a renglones.
Entonces: pt[2] contiene un puntero al tercer renglón. Lo cual puede escribirse: *(pt +2 ).
La expresión: *(pt[2]) es el tercer renglón, que en este caso es un arreglo de C caracteres; es
decir: *( *(pt+2)) es el valor del puntero al inicio de ese renglón. Y consecuentemente:
*( *(pt+2)) +5 es el puntero al sexto carácter del tercer renglón.
Finalmente para accesar al elemento ubicado en el tercer renglón y en la sexta columna, debe
indireccionarse el puntero anterior, lo cual puede escribirse: *( *( *(pt+2)) +5), o empleando
notación de arreglos: (*pt[2])[5] .
Una alternativa a lo anterior es convertir el puntero a renglón en un puntero a carácter, esto se
logra mediante: (char *) pt[2]; entonces el acceso a un carácter, a través de punteros a renglones
se logra con: ((char*) pt[i])[j].
Arreglo de punteros a caracteres.
Puede lograrse una representación más simple, si se almacenan en un arreglo punteros a
caracteres, en lugar de punteros a renglones. Esto puede modelarse según:
typedef char renglon[C]; //definición de tipo renglon como un arreglo de C caracteres
renglon ar[R];
// Arreglo de R renglones
char * pch[R];
// Arreglo de punteros a caracteres
Los vínculos de la estructura se producen con:
for(i=0; i<R; i++) pch[i]=(char *) (&ar[i]); //llena arreglo de punteros a char
La expresión: pch[i][j] accesa al carácter ubicado en el renglón (i+1) y en la columna (j+1).
2.3.2. Lista simplemente enlazada en base a cursores.
#define MaxEntradas 4
#define fin_de_lista -1
Con los siguientes datos:
Tipo Valor[MaxEntradas] ={1, 2, 3, 4};
Indice Cursor[MaxEntradas] ={2, 3, 4, fin_de_lista };
Puede visualizarse la siguiente lista.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
1
2
7
3
4
Figura 2.3. Lista simplemente enlazada.
Se tiene, como ejemplo, que: Cursor[2] contiene el valor 4 de índice.
2.4. Ejemplos basados en estructuras.
2.4.1. Estructura para fecha.
Agrupamos mediante la estructura fecha los campos: día, mes, año.
//molde. Declaración.
struct fecha
{ int dia;
int mes;
int agno;
};
La declaración sólo establece un molde o patrón para la estructura.
Se denominan instancias o definiciones de variables cuando se asocia un tipo a una variable. La
definición considera una asignación de memoria para la variable.
//instancias.
struct fecha fecha1; //definición.
struct fecha fecha2={1,5,2004}; //definición e inicialización
Nótese que se requiere preceder con la palabra struct al nombre del molde.
También se puede establecer una definición e inicialización de un puntero a la variable fecha1,
mediante:
struct fecha *ptfecha1=&fecha1;
No puede accederse a los campos de una estructura no iniciada, para lectura.
Se pueden copiar estructuras completas, mediante asignación:
fecha1=fecha2;
Puede escribirse en un campo determinado:
fecha1.mes=11;
// mediante el selector de campos
ptfecha1->dia=25;
//o a través del puntero
La forma equivalente, vía indirección del puntero, no suele emplearse:
*(ptfecha1.dia) = 25;
Es preferible crear tipos, previo a la definición de variables de tipo estructura:
Profesor Leopoldo Silva Bijit
20-01-2010
8
//Definiciones de tipos
typedef struct fecha Fecha;
typedef Fecha * pFecha;
Estructuras de Datos y Algoritmos
//hay diferencia entre mayúsculas y minúsculas.
//define puntero a elemento de tipo Fecha.
En este ámbito, las definiciones de las instancias para las variables, quedan:
Fecha fecha3 = {1, 5, 2004}; //definición e inicialización.
pFecha pfecha3=&fecha3;
Observar que las definiciones no son precedidas por struct.
Es preciso crear métodos para desplegar variables que son estructuras:
Se ilustra pasar el argumento como una estructura. Lo cual implica: crear el espacio y copiar la
estructura en el frame de la función:
void printfecha(Fecha f)
//paso por valor
{
printf(" Día = %d Mes = %d Año = %d \n", f.dia, f.mes, f.agno); //lectura de campos
}
Es preferible pasar una referencia a la estructura, ya que esto ocupa menos espacio en el frame.
Sólo es preciso copiar un puntero.
void printfecharef(pfecha p)
//paso por referencia.
{
printf(" Día = %d Mes = %d Año = %d \n", p->dia, (*p).mes, p->agno);
}
Ejemplos de uso:
printfecha(fecha3);
printfecharef(pfecha3);
También es útil disponer de un constructor de la estructura.
Fecha setfecha (int dia, int mes, int agno)
//retorno de estructura
{
Fecha f;
f.dia=dia; f.mes=mes; f.agno= agno; //escritura en campos
return(f);
}
Ejemplo de uso:
fecha3 = setfecha(15, 6, 2005);
También suele ser necesario desarrollar funciones para realizar operaciones de comparación
entre estructuras. El siguiente prototipo ilustra un operador de comparación “mayor o igual
que”, al cual se le pasan punteros a estructuras y devuelve un puntero a la estructura que es
mayor o igual que la otra, el diseño de la función se deja como tarea.
pFecha fechaGET(pFecha pf1, pFecha pf2);
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
9
Se pueden crear arreglos de estructuras de tipo Fecha:
Fecha ArrFecha[3]={ {1,1,2005},{30,6,2005},{31,12,2005}};
printf("mes %d \n", (ArrFecha+1)->mes); imprime 6
printf("dia %d \n", ArrFecha[2].dia); imprime 31
Es responsabilidad del programador no exceder los rangos del arreglo.
2.4.2. Lista simplemente enlazada en base a punteros.
Es posible declarar el molde y definir tipos simultáneamente.
En esta situación en lugar de moldenodo se podría haber puesto cualquier otro identificador.
Esta forma suele describirse como declaración anónima.
typedef struct moldenodo
{ int clave;
struct moldenodo *proximo;
} nodo, *pnodo;
//instancias. Definiciones.
nodo nodo1={1,NULL};
nodo nodo2={2,NULL};
nodo nodo3={3,NULL};
pnodo lista=&nodo1;
Las siguientes asignaciones crean los vínculos.
lista->proximo = &nodo2;
nodo2.proximo = &nodo3;
lista
1
nodo1
2
3
nodo2
nodo3
Figura 2.4. Lista simplemente enlazada, mediante punteros.
En caso de definir la lista en forma dinámica, sólo es preciso definir la variable lista. El espacio
para los nodos se solicita a través de llamados a malloc; debido a esto los nodos no tienen un
nombre y sólo se los puede accesar vía punteros.
En el caso del ejemplo, los nodos se han definido en forma estática, y tienen un nombre de
variable asociado.
Profesor Leopoldo Silva Bijit
20-01-2010
10
Estructuras de Datos y Algoritmos
2.5. Estructuras más complejas.
2.5.1. Arreglo de listas.
Pueden concebirse estructuras más complejas.
Por ejemplo se desea disponer de un arreglo de punteros, donde cada elemento del arreglo es el
inicio de una lista simplemente enlazada.
Consideraremos que cada celda debe estar asociada a un string, donde los strings pueden ser de
diferente largo. Se decide que no es conveniente almacenar los strings como arreglos de
caracteres, esto implicaría un tamaño fijo para cada arreglo, con lo cual se ocuparía mal el
espacio cuando deba almacenarse un string de pequeño largo, y la estructura puede colapsar si el
largo del string es mayor que el tamaño máximo del arreglo. Es preferible asociar al nodo de la
lista un puntero a un string, lo cual ocupa un tamaño fijo (normalmente los bytes ocupados por
un entero).
Definimos entonces los siguientes tipos:
typedef struct moldecelda
{
char *nombre;
struct moldecelda *next;
} celda, *pcelda;
#define BALDES 10 /* 10 celdas */
static pcelda hashtable[BALDES]; /*tabla punteros */
La palabra static, que precede a la definición, explícitamente indica que la tabla debe
almacenarse en un segmento estático de la memoria. Es decir estará disponible, durante toda la
ejecución del programa.
Se ilustra un ejemplo de la estructura.
Índice
Tabla
String0
0
1
2
….
B-1
String i
String j
String k
Figura 2.5. Arreglo de listas.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
11
Veremos que se pueden desarrollar algoritmos eficientes para buscar strings almacenados en la
tabla, cuando estudiemos tablas de hash.
2.5.2. Arreglo de estructuras.
El siguiente ejemplo de diseño de una estructura de datos, contempla un arreglo en el cual se
califica el estado de cada celda. Suponemos que se almacena un entero, y para describir
lógicamente el estado empleamos la definición de un tipo enumerativo, que permite el mapeo de
nombres lógicos con enteros. Internamente se emplean enteros, pero el programador puede
referirse a ellos mediante sus nombres equivalentes.
typedef enum {vacio, ocupado, descartado} state;
typedef struct hcelda
{ int clave;
state estado;
} celda;
#define B 10 /* 10 celdas */
static celda hashtab[B]; /*arreglo de celdas */
static int ocupados;
//ocupados de la tabla
El programador puede escribir expresiones en términos del tipo enumerativo:
(hashtab[i].estado != vacio && hashtab[i].estado != descartado)
2.5.3. Multiárboles.
La descripción de un nodo que pueda tener un número variable de punteros que apunten a sus
descendientes no es práctica. Ya que esto implica almacenar los vínculos en un arreglo, y si es
arreglo debe tener un tamaño fijo. El cual debe escogerse considerando el máximo número de
descendientes que soportará la estructura; mal empleando los recursos en el caso de un nodo sin
hijos, o de nodos con un pequeño número de descendientes. Además siempre estará el riesgo de
que aparezca un nodo con mayor número de descendientes que el tamaño máximo escogido.
1
2
5
3
6
7
8
4
9
10
11
Figura 2.6. Multiárbol.
Profesor Leopoldo Silva Bijit
20-01-2010
12
13
12
Estructuras de Datos y Algoritmos
El esquema anterior ilustra los vínculos. Este ejemplo refuerza el concepto que un vínculo puede
ser un cursor o un puntero.
El número variable de los vínculos asociados a un nodo pueden reemplazarse por sólo dos
vínculos: uno que relaciona el nodo con el primer descendiente izquierdo, y otro que vincula a
cada nodo con su hermano derecho. Nótese que en cada nivel puede observarse una lista de
nodos que parte del nodo ubicado más a la izquierda y termina en un vínculo nulo después del
último descendiente de un nodo.
Figura 2.7. Primer descendiente izquierdo, hermano derecho.
Con esta visualización se requieren sólo dos vínculos por nodo.
2.5.3.1. Descripción mediante punteros.
Una representación mediante punteros requiere definir la estructura del nodo según:
typedef struct moldenodo
{
int valornodo;
struct moldenodo *hijoizquierdo;
struct moldenodo *hermanoderecho;
struct moldenodo *padre;
potros * datos_periféricos;
} nodo, *pnodo;
Donde se han definido los tipos asociados al nodo y al puntero a nodo.
Se ha considerado que se almacenará un entero como clave o valor distintivo del nodo. Se ha
agregado un puntero a una estructura que podría almacenar otros datos asociados al nodo, con el
campo datos_periféricos. También se agrega un puntero al padre, ya que esta información
reduce el tiempo de buscar al padre de un nodo determinado.
2.5.3.2. Descripción mediante arreglos de cursores.
Se describe a continuación los valores que describen el multiárbol, de la Figura 2.6, mediante
arreglos de cursores para el Hijo izquierdo y Hermano Derecho. Se ha considerado que un valor
cero indica que no hay hijo izquierdo o hermano derecho o padre; si se desea usar el nodo cero,
podría elegirse -1 como el cursor nulo.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
13
Índice Hijo izquierdo Hermano derecho Padre Clave Otros datos
0
0
0
0
--1
2
0
0
1
-2
5
3
1
2
-3
7
4
1
3
-4
10
0
1
4
-5
0
6
2
6
-6
0
0
2
6
-7
0
8
3
7
-8
0
9
3
8
-9
0
0
3
9
-…
Figura 2.8. Multiárbol mediante arreglo de cursores.
Se ha agregado un arreglo de cursores para especificar el padre del nodo. Esta información
facilita la búsqueda del padre de un nodo dado.
Un diseño de la estructura de datos considera al multiárbol como una estructura cuyos campos
son los diferentes arreglos.
#define MAXNODOS 13
struct moldemultiarbol
{
int Hijo_izquierdo[MAXNODOS];
int Hermano_derecho[MAXNODOS];
int Padre[MAXNODOS];
int clave[MAXNODOS];
int dato1[MAXNODOS];
} arbol;
arbol.Hijo_derecho[4] tiene valor 0; lo cual indica que es el último descendiente.
La estructura puede contener más o menos información dependiendo de costo de las
operaciones que se deseen implementar. Por ejemplo si sólo se desea conocer la conectividad de
los nodos del multiárbol, basta que la estructura aporte información para conocer quien es el
padre de cada nodo, con esta descripción si luego se desea conocer los hijos de cada nodo,
resultará un algoritmo costoso.
2.5.3.3. Descripción por arreglo de padres.
Profesor Leopoldo Silva Bijit
20-01-2010
14
Estructuras de Datos y Algoritmos
0
1
4
2
5
6
3
7
8
9
10
11
12
Figura 2.9. Multiárbol mediante arreglo de padres.
En un ambiente de grafos, es de interés describir un árbol que interconecta todos los vértices sin
formar circuitos. Se ilustra un árbol de un grafo orientado, en el que se muestra el número
asociado a cada vértice; se ha considerado el vértice 0, esto debido a que los arreglos en C,
parten de índice cero.
La información que describe el árbol anterior es:
Vértice
0 1 2 3 4 5 6 7 8 9 10 11 12
Padre del vértice 0 0 0 0 1 1 2 2 2 3 3 3 3
Figura 2.10 Arreglo de padres.
Empleando lenguaje de programación, queda:
int PadreDelVertice[MAXNODOS]={0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3};
2.6. Un ejemplo real de estructuras.
La realidad suele ser más compleja que los casos idealizados que se exponen en los cursos
básicos.
El diseño de una estructura más realista, es la que describe los encabezados de los paquetes
ICMP e IP en un ambiente de red.
Primero se definen dos tipos básicos, con fines de compatibilidad. Se mapean los tipos del
lenguaje C, a tipos lógicos. Si los tamaños de los tipos básicos de un compilador para un
procesador específico son diferentes, basta cambiar el nombre de los tipos básicos. Toda la
codificación no es necesario modificarla, ya que queda en términos de u8_t y u16_t, que son los
tipos usados en el programa.
typedef unsigned char u8_t; //es el tipo byte.
typedef unsigned short u16_t; //el entero de 16 bits
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
15
/* The ICMP and IP headers. */
typedef struct {
/* IP header. */
u8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
u16_t ipchksum;
u16_t srcipaddr[2],
destipaddr[2];
/* ICMP (echo) header. */
u8_t type,
icode;
u16_t icmpchksum;
u16_t id,
seqno;
} uip_icmpip_hdr;
Problemas resueltos.
P2.1. Se tiene el siguiente programa:
#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;
Profesor Leopoldo Silva Bijit
20-01-2010
16
Estructuras de Datos y Algoritmos
*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); q = q->next; }
return (NULL);
}
return(NULL);
}
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.
b) Diagrama de la estructura después de ejecutar crealista();
c) Explicar acción realizada por busca.
d) Explicar acción realizada por busca2.
e) Determinar qué imprime el programa.
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.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
17
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
Figura P2.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:
Datos
Stack
heap
Lista1
newnodo
i1 = ?
ref
i2 = ?
dato1 = 0
next = ?
dato2 = 1
Figura P2.2.
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).
Profesor Leopoldo Silva Bijit
20-01-2010
18
Estructuras de Datos y Algoritmos
Datos
Stack
heap
Lista1
newnodo
i1 = 0
ref
i2 = 1
dato1 = 0
next
dato2 = 1
Figura P2.3
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
Figura P2.4
Si se hubiera pasado solamente un puntero a nodo como referencia, se tendría el diseño:
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.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
19
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
Figura P2.5.
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.
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.
Profesor Leopoldo Silva Bijit
20-01-2010
20
Estructuras de Datos y Algoritmos
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
P2.2. Escribir una función:
int btoi(char *str, int *pvalor) que convierta un string binario pasado en str (Ej. "110101") a un
entero a ser retornado en pvalor (Ej. 53). La función retorna 0 si no hay error y retorna -1 si el
string binario tiene un carácter que no es '0' o '1'.
Nota: 1101 (en binario) = 1x23+1x22+0x21+1x20 = 8 + 4 + 1 = 13 en decimal
/* Uso de la funcion */
#include <stdio.h>
#include <math.h>
#include <string.h>
int btoi(char *str, int *pvalor);
main()
{
int valor=0;
char str[10];
strcpy(str, "110101");
if( !btoi(str, &valor) ) printf("string binario: %s, int:%d\n", str, valor);
}
Solución.
int btoi(char *str, int *pvalor)
{ int i=0, largo=0, temp=0;
largo = strlen(str) - 1; //índice del dígito menos significativo
while(i <= largo)
{
if (*(str + i) == '1')
temp += (int) pow(2, largo - i);
//suma las potencias presentes de dos, desde la más significativa.
else if (*(str + i) == '0') ;
else return -1; //no es 1 ó 0
i++;
}
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
21
*pvalor = temp; //retorno por referencia
return 0;
}
Una alternativa es sumar las potencias presentes de dos, desde la menos significativa.
int btoi(char *str, int *pvalor)
{ int i=0, temp=0, pot=1;
i = strlen(str)-1; //índice del dígito menos significativo
while(i >=0)
{
if (*(str + i) == '1')
{ temp += pot; printf(" %d %d \n",temp, pot);}
else if (*(str + i) == '0') ;
else return -1; //no es 1 ó 0
i--;pot*=2;
}
*pvalor = temp;
return 0;
}
P2.3. Se tiene la siguiente función:
char *f1(char *s, int c)
{
while( *s )
{ if( *s == (char) c ) return (char *) s;
s++;
}
return (char *) 0;
}
a) Explicar los cast que se emplean y su necesidad.
b) Qué realiza la función.
c) Si se tiene char *string="12345678"; explicar que despliega:
printf("%s\n", f1(string, '3')) ;
Solución.
El cast (char) c se emplea, debido a que el segundo argumento de la función es de tipo entero,
para convertirlo a carácter y efectuar la comparación con un carácter del string. No es
necesario, ya que por defecto, los valores de tipo carácter son promovidos automáticamente a
enteros con signo. Por ejemplo se puede pasar equivalentemente el valor 65 ó 0x45 ó „A‟. Esto
permite pasar caracteres de control que no son imprimibles, como argumentos. La comparación
también se podía haber explicado según: ( (int) *s == c ). Es preferible usar cast, de tal modo
de comparar valores de igual tipo.
El cast en return (char *) s; no es necesario, ya que s es de tipo puntero a char.
Profesor Leopoldo Silva Bijit
20-01-2010
22
Estructuras de Datos y Algoritmos
El cast return (char *) 0; es necesario para retornar un puntero nulo a carácter.
b) Revisa y encuentra la primera ocurrencia del carácter (char) c, en el string apuntado por s;
retornado un puntero al carácter de s que es igual a (char) c. Si el string es nulo, retorna un
puntero nulo a carácter; también si no encuentra (char) c en el string.
c) Despliega el string: 345678, seguido de un terminador de línea, ya que el llamado
f1(string, '3') retorna un puntero al string “345678".
P2.4. Se tiene la siguiente función:
int f2(char *s1, char *s2)
{
while( *s1++ == *s2 )
if( *s2++ == '\0' ) return(1);
return(0);
}
a) Explicar que realiza la función. Indicando las condiciones en las que retorna un cero o un uno
b) Dar un ejemplo de uso. Definiendo las variables que sean necesarias.
Solución.
a) Compara dos strings. Retorna 1 sólo si los strings son iguales. Reconoce la igualdad de dos
strings nulos. Retorna cero, si los strings son diferentes. Si los caracteres, en la misma
posición, de s1 y s2 son iguales va recorriendo ambos strings.
Si los primeros caracteres de los strings fuesen iguales, retorna un cero si string s1 es más corto
que el string s2 (ya que no se cumple la condición del while); lo mismo sucede si string 1 es más
largo que el string s2.
b) char *s1="12345678";
char *s2="12345";
if ( f2(s1,s2)==0) printf("no son iguales\n"); else printf("son iguales\n");
P2.5. Se tiene la estructura para un nodo,
con clave de tipo entera y tres punteros a nodo.
clave
p1
p2
p3
a) Definir los tipos: nodo y pnodo (puntero a nodo).
b) Diseñar, empleando malloc, la función con prototipo: pnodo creanodo(int clave); que solicita
espacio e inicializa el nodo con punteros nulos y la clave del nodo con el valor del argumento.
c) Si se tiene la siguiente definición: pnodo pn; dibujar un diagrama con los datos, luego de
ejecutada la secuencia:
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
23
pn=creanodo(5);
pn->p3=pn;
pn->p1=creanodo(3);
pn->p1->p3=pn;
pn->p2=creanodo(8);
pn->p2->p3=pn->p1;
d) Escribir el segmento que forma el siguiente diagrama:
pn
4
p1
6
p2
p3
p1
p2
p3
Figura P2.6.
Solución.
a)
typedef struct moldenodo
{ int clave;
struct moldenodo *p1;
struct moldenodo *p2;
struct moldenodo *p3;
} nodo , *pnodo;
b)
pnodo creanodo(int clave)
{ pnodo p;
if ((p = (pnodo) malloc(sizeof(nodo))) == NULL) {
printf ("Memoria insuficiente para crear nodo\n");
exit(1);
}
p->clave=clave;p->p2=NULL;p->p1=NULL;p->p3=NULL;
return(p);
}
c) Los diagramas se ilustran después de ejecutada la instrucción.
Profesor Leopoldo Silva Bijit
20-01-2010
24
Estructuras de Datos y Algoritmos
pn=creanodo(5);
pn
5
Figura P2.7.
pn->p3=pn;
pn
5
Figura P2.8.
pn->p1=creanodo(3);
pn
5
3
Figura P2.9.
pn->p1->p3=pn;
pn
5
3
Figura P2.10.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
25
pn->p2=creanodo(8);
pn
5
3
8
Figura P2.11.
pn->p2->p3=pn->p1;
pn
5
3
8
Figura P2.12.
c)
pn= creanodo(6); pn->p2=pn; pn->p3=pn;
pn->p1=creanodo(4); pn->p1->p1=pn->p1;
pn->p1->p3=pn; pn->p1->p2=pn;
Profesor Leopoldo Silva Bijit
20-01-2010
26
Estructuras de Datos y Algoritmos
pn
4
p1
6
p2
p3
p1
p2
p3
Figura P2.13.
P2.6. Se tiene el siguiente programa.
#include <stdlib.h>
typedef struct nn
{ int x;
struct nn * p;
struct nn * q;
int y;
} t, *pt;
t w, z;
pt px=&w;
void main(void)
{ px->p=&z;
w.q = px->p;
px->q->q=px;
z.p = w.p;
w.x = z.x = 2;
(*px).y = 8;
(*(w.q)).y =9;
px=(pt) malloc(sizeof(t));
px->p=px->q = (pt ) 0;
px->x=px->y=12;
}
Efectuar un diagrama de los datos después de ejecutar las instrucciones de main.
Solución.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
27
Antes de main, el espacio de variables puede visualizarse según:
px
w
z
x
x
p
p
q
q
y
y
Figura P2.13.
px
w
x
p
px->p =&z
q
w.q=px->p;
y
z
x
p
q
y
Figura P2.14.
Profesor Leopoldo Silva Bijit
20-01-2010
28
Estructuras de Datos y Algoritmos
px
w
x
p
q
y
px->q->q=px
z
x
z.p=w.p
p
q
y
Figura P2.15.
px
w
x
2
p
w.x=z.x=2
q
y
8
(*px).y=8;
z
x 2
p
q
(*(w.q)).y=9
y
9
Figura P2.16.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
29
px
px =(pt)malloc(sizeof(t));
w
x
2
p
x
12
p
y
y
q
8
q
z
12
x 2
px ->p=px->q=(pt)0;
p
y
q
9
px ->x=px->y=12;
Figura P2.17.
Ejercicios propuestos.
E1. Determinar qué imprimen los siguientes segmentos:
a ) printf(“\n%o %x %d”, 17, 017, 0x17) ;
b) n = 3 ; printf(“-05d %5d”, n, n) ;
c) x = 1234E-2 ; printf(“%6.3f”, x) ;
d) j =2; if ( ( '1' -1 ) == --j ) printf("verdad"); else printf("falso");
E2. Colocar paréntesis y evaluar las expresiones siguientes:
Si es preciso puede indicar los resultados de expresiones intermedias.
a) a != b && c + 1 == ! c + 2
con a1) a=2 ; b=3 ; c = 1;
a2) a=3 ; b=2 ; c=2 ;
b) 1 + 2 * ( n += 8) / 4
con n=3 ;
c) a < b ? a < b ? a+1 : a+2 : a+3 con a=2 ; b= 3 ;
Profesor Leopoldo Silva Bijit
20-01-2010
30
Estructuras de Datos y Algoritmos
E3. Se tiene el siguiente programa:
Qué efectúa la función, indicar tipo de parámetros.
Escribir el prototipo y dónde debe ubicarse en el programa.
Qué escribe el programa principal.
void main()
{ int i=11, j ;
j = funcion( i++, 5) ; printf(“\n%d %d”, j, i);
j = funcion( j+i, j-3) ; printf(“\n%d %d”, j, i);
}
int funcion( int x, int y)
{
int s,t ;
for( s=0 ; x != 0 ; x--) for ( t=0 ; t != y ; s++,t++) ;
return( s ) ;
}
E4. Escribir programa.
a) Que genere los primeros 20 números de la secuencia: 1, 4, 7, 10, 14, ....
b) Que genere b elementos de la secuencia a partir del a-ésimo. Leer a y b.
E5. Indicar que escribe el programa.
#include <stdio.h>
int func(int *, float *, char);
void show();
float f1=1, f2=2.2;
int i1=2, i2;
void main()
{
i2 = func(&i1, &f2, '1'); show();
i1 = func(&i2, &f1, '2'); show();
for(;;);
}
void show()
{ printf("\ni1= %d i2= %d" ,i1,i2);
printf("\nf1= %f f2= %f",f1, f2); }
int func(int *i, float *f, char ch)
{
*f = (float)(*i+2); *i = (int)(*f)+2; printf("\n%c ", ch);
return(*i+2);
}
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
31
E6. Indicar qué imprime el programa.
#include <stdio.h>
int a[5];
int i;
void arreglo(int j){ for(i=0;i<5; a[i]=j+i, i++); }
void show(void){for(i=0;i<5;i++) printf(" %3d" , a[i]); printf("\n");}
void main(void)
{ arreglo(1), show();
arreglo(2), show();
arreglo(a[2]+*a+3), show();
while(1);
}
E7. Indicar qué imprime el programa.
Indicar qué efectúa cada función.
#include <stdio.h>
void prt(int);
void f2(int&);
void f1(int&);
void main(void)
{ int i=1024;
prt(i);
i = 0x10; f1(i); prt(i);
i = -1; f2(i); prt(i);
}
void f1(int& i)
{ i = (i | 0x8000); }
void f2(int& i)
{ i = (i>>1); i = (i&0x7fff); }
void prt(int i)
{ int j;
for (j=15; j>=0; j--)(1<< j ) &i ? printf( '1') : printf( '0'); printf( '\n');
}
E8. Indicar qué imprime el programa.
#include <stdio.h>
int f1(int& , int);
int f2(int *, int);
void main()
Profesor Leopoldo Silva Bijit
20-01-2010
32
Estructuras de Datos y Algoritmos
{ int k, m =1;
k = f1(m,5); printf(“%d \n %d “, k, m);
k = 2; m = 3;
m= f2(&m, m); printf(“%d \n”, m );
k = 4; m = 6;
k = f1( m, f1(m,3)+5 ); printf(“%d \n %d \n”, k, m);
}
int f1(int&i , int j)
{ j = j+i ; i = i+j; return(i+j); }
int f2(int *i, int j)
{ *i = j+2+*i; return(j+*i); }
E9. Indicar qué escribe el programa.
#include <stdio.h>
struct punto{
int x;
int y;
};
struct molde{
int a[2];
char c;
punto p; };
void main()
{
molde m1={{2,4},'p',{3,5}}, m2={{5,6},'q',{7,1}};
molde *pm=&m2;
int *pi=&(m1.p.y);
printf(“%d \n”, *pi ) ;
printf(“%d \n”, cout << m2.a[1] + m1.p.x );
printf(“%d \n”, pm->a[1] + pm->p.x );
printf(“%d \n “, *(pi-1)) ;
pi = &m2.a[0];
printf(%d \n “, *(pi+1));
}
E10. Determinar la salida.
#include <stdio.h>
int f2(int x, int y, int z)
{int i;
for(i=0; i<x; i++) y+=z;
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
33
return(y);
}
int main(void)
{
printf("%d ", f2(5, 3, 2));
return(0);
}
E11. Determinar la salida.
#include <stdio.h>
int arr[10];
void f1(int x, int *y)
{ int i;
for(i=0; i<x; i++) *(y+i) = i;
}
void f2(int x, int *y)
{ int i;
for(i=0; i<x; i++) printf("%d, ", *(y+i));
putchar('\n');
}
int main(void)
{
f1(5, arr); f2(5, arr);
return(0);
}
E12. Determinar la salida.
#include <stdio.h>
int arr[10];
int *pi;
#define NULL ( (char *) 0)
void f1(int x, int *y)
{int i;
for(i=0; i<x; i++) *(y+i)=i;
}
int *f2(int x, int *y, int z)
{ int i;
for(i=0; i<x; i++) if(*(y+i)== z ) return(y+i);
return((int *) NULL);
}
Profesor Leopoldo Silva Bijit
20-01-2010
34
Estructuras de Datos y Algoritmos
int main(void)
{
f1(5, arr); pi=f2(5, arr, 8);
if(pi!=((int *) NULL)) printf("%d ", *pi); else printf("no se encuentra\n");
return(0);
}
#include <stdio.h>
E13. Explicar que realizan las funciones.
void prtlong(unsigned long int i)
{ int j; unsigned long int k; k=1L;
for (j=31; j>=0; j--) if((k<<j)&i) putchar(‟1‟); else putchar(‟0‟);
}
void prtint(int i)
{ int j, k=1;
for (j=15; j>=0; j--) if( (k<<j)&i ) putchar(‟1‟); else putchar(‟0‟);
}
void sp(int i) { int j; for(j=i; j>0;j--) putchar(‟ ‟); }
void lrs(int *p, int *q)
{
int k,m;
k=(*p)&0x0001; m=(*p)&0x8000;
(*p)>>=1; if(m) *p=(*p)&0x7fff;
(*q)>>=1; if(k) *q=(*q)|0x8000;else *q=(*q)&0x7fff;
}
void ars(int *p, int *q)
{ int k,m;
extern int s;
k=(*p)&0x0001; m=(*q)&0x0001;
(*p)>>=1;(*q)>>=1;if(k) *q=(*q)|0x8000; else *q=(*q)&0x7fff; s=m;
}
E14. Describir un multiárbol
Mediante un arreglo de listas de los hijos de cada nodo. El arreglo debe tener una entrada por
cada nodo, además considerar que la raíz pueda se cualquier nodo.
Profesor Leopoldo Silva Bijit
20-01-2010
Definición de Estructuras de Datos en C.
35
Índice general.
CAPÍTULO 2. ............................................................................................................................................ 1
DEFINICIÓN DE ESTRUCTURAS DE DATOS EN C......................................................................... 1
2.1. TIPOS PRIMITIVOS. ............................................................................................................................. 1
2.2. MECANISMOS DE ESTRUCTURACIÓN. ................................................................................................. 1
2.2.1. Grupos básicos. ......................................................................................................................... 1
2.2.2. Vínculos. .................................................................................................................................... 2
2.3. EJEMPLOS BASADOS EN ARREGLOS. ................................................................................................... 3
2.3.1. Acceso a componentes del arreglo. ........................................................................................... 3
Definición de matrices. .................................................................................................................................... 4
Definición de arreglo de arreglos. .................................................................................................................... 5
Arreglo de punteros a renglones. ..................................................................................................................... 5
Arreglo de punteros a caracteres. ..................................................................................................................... 6
2.3.2. Lista simplemente enlazada en base a cursores. ....................................................................... 6
2.4. EJEMPLOS BASADOS EN ESTRUCTURAS. ............................................................................................. 7
2.4.1. Estructura para fecha. ............................................................................................................... 7
2.4.2. Lista simplemente enlazada en base a punteros. ....................................................................... 9
2.5. ESTRUCTURAS MÁS COMPLEJAS....................................................................................................... 10
2.5.1. Arreglo de listas. ..................................................................................................................... 10
2.5.2. Arreglo de estructuras. ............................................................................................................ 11
2.5.3. Multiárboles. ........................................................................................................................... 11
2.5.3.1. Descripción mediante punteros. ........................................................................................................ 12
2.5.3.2. Descripción mediante arreglos de cursores. ...................................................................................... 12
2.5.3.3. Descripción por arreglo de padres. .................................................................................................... 13
2.6. UN EJEMPLO REAL DE ESTRUCTURAS. .............................................................................................. 14
PROBLEMAS RESUELTOS. ........................................................................................................................ 15
P2.1. Se tiene el siguiente programa: ............................................................................................... 15
P2.2. Escribir una función: ............................................................................................................... 20
P2.3. Se tiene la siguiente función: ................................................................................................... 21
P2.4. Se tiene la siguiente función: ................................................................................................... 22
P2.5. Se tiene la estructura para un nodo, ........................................................................................ 22
P2.6. Se tiene el siguiente programa. ................................................................................................ 26
EJERCICIOS PROPUESTOS. ....................................................................................................................... 29
E1. Determinar qué imprimen los siguientes segmentos: ................................................................ 29
E2. Colocar paréntesis y evaluar las expresiones siguientes: ........................................................... 29
E3. Se tiene el siguiente programa: .................................................................................................. 30
E4. Escribir programa. ..................................................................................................................... 30
E5. Indicar que escribe el programa. ................................................................................................ 30
E6. Indicar qué imprime el programa. ............................................................................................. 31
E7. Indicar qué imprime el programa. .............................................................................................. 31
E8. Indicar qué imprime el programa. .............................................................................................. 31
E9. Indicar qué escribe el programa. ................................................................................................ 32
E10. Determinar la salida. ................................................................................................................ 32
E11. Determinar la salida. ................................................................................................................ 33
E12. Determinar la salida. ................................................................................................................ 33
Profesor Leopoldo Silva Bijit
20-01-2010
36
Estructuras de Datos y Algoritmos
E13. Explicar que realizan las funciones. ..........................................................................................34
E14. Describir un multiárbol .............................................................................................................34
ÍNDICE GENERAL. ....................................................................................................................................35
ÍNDICE DE FIGURAS. ................................................................................................................................36
Índice de figuras.
FIGURA 2.1. AGRUPACIONES DE DATOS. ........................................................................................................2
FIGURA 2.2. VÍNCULOS ENTRE COMPONENTES DE DATOS. ............................................................................2
FIGURA 2.2.A. MATRIZ DE CARACTERES ......................................................................................................4
FIGURA 2.2.B. ARREGLO DE PUNTEROS A ARREGLOS DE CARACTERES ........................................................5
FIGURA 2.3. LISTA SIMPLEMENTE ENLAZADA................................................................................................7
FIGURA 2.4. LISTA SIMPLEMENTE ENLAZADA, MEDIANTE PUNTEROS. ...........................................................9
FIGURA 2.5. ARREGLO DE LISTAS. ...............................................................................................................10
FIGURA 2.6. MULTIÁRBOL. ..........................................................................................................................11
FIGURA 2.7. PRIMER DESCENDIENTE IZQUIERDO, HERMANO DERECHO. .......................................................12
FIGURA 2.8. MULTIÁRBOL MEDIANTE ARREGLO DE CURSORES. ..................................................................13
FIGURA 2.9. MULTIÁRBOL MEDIANTE ARREGLO DE PADRES........................................................................14
FIGURA 2.10 ARREGLO DE PADRES. .............................................................................................................14
FIGURA P2.1. ...............................................................................................................................................17
FIGURA P2.2. ...............................................................................................................................................17
FIGURA P2.3 ................................................................................................................................................18
FIGURA P2.4 ................................................................................................................................................18
FIGURA P2.5. ...............................................................................................................................................19
FIGURA P2.6. ...............................................................................................................................................23
FIGURA P2.7. ...............................................................................................................................................24
FIGURA P2.8. ...............................................................................................................................................24
FIGURA P2.9. ...............................................................................................................................................24
FIGURA P2.10. .............................................................................................................................................24
FIGURA P2.11. .............................................................................................................................................25
FIGURA P2.12. .............................................................................................................................................25
FIGURA P2.13. .............................................................................................................................................26
FIGURA P2.13. .............................................................................................................................................27
FIGURA P2.14. .............................................................................................................................................27
FIGURA P2.15. .............................................................................................................................................28
FIGURA P2.16. .............................................................................................................................................28
FIGURA P2.17. .............................................................................................................................................29
Profesor Leopoldo Silva Bijit
20-01-2010
Descargar