cap.2 definición de estructuras de datos en c.lsb/elo320/clases/c2.pdf · 1 profesor leopoldo...

36
1 Profesor Leopoldo Silva Bijit 20-01-2010 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.

Upload: vuongquynh

Post on 29-May-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

1

Profesor Leopoldo Silva Bijit 20-01-2010

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.

Page 2: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

2 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

listas

árboles

grafos

Figura 2.2. Vínculos entre componentes de datos.

Page 3: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 3

Profesor Leopoldo Silva Bijit 20-01-2010

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[].

Page 4: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

4 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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 \n", A[12]); imprime 12

printf(" %d \n", B[-2]); imprime 8

printf(" %d \n", A[-1]); imprime cualquier cosa que estuviera almacenada antes de A

printf(" %d \n", 1[-1+B] ); imprime 10

printf(" %d \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]

arr[3][5]

Figura 2.2.a. Matriz de caracteres

Page 5: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 5

Profesor Leopoldo Silva Bijit 20-01-2010

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.

ar

(*pt[2])[5]

pt

Figura 2.2.b. Arreglo de punteros a arreglos de caracteres

Page 6: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

6 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

Page 7: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 7

Profesor Leopoldo Silva Bijit 20-01-2010

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:

1 2 3 4

Page 8: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

8 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

//Definiciones de tipos

typedef struct fecha Fecha; //hay diferencia entre mayúsculas y minúsculas.

typedef Fecha * pFecha; //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);

Page 9: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 9

Profesor Leopoldo Silva Bijit 20-01-2010

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;

nodo1

1 2 3

lista

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.

Page 10: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

10 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

Tabla

0

1

2

….

B-1

Índice String0

String i

String j

String k

Figura 2.5. Arreglo de listas.

Page 11: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 11

Profesor Leopoldo Silva Bijit 20-01-2010

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 3 4

5 6 7 8 10 11 12 13 9

Figura 2.6. Multiárbol.

Page 12: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

12 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

Page 13: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 13

Profesor Leopoldo Silva Bijit 20-01-2010

Í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.

Page 14: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

14 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

0

1 2 3

4 5 6 7 9 10 11 12 8

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

Page 15: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 15

Profesor Leopoldo Silva Bijit 20-01-2010

/* 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;

Page 16: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

16 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

*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.

Page 17: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 17

Profesor Leopoldo Silva Bijit 20-01-2010

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.

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:

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).

Lista1

newnodo ?

ref

dato1 = 0

dato2 = 1

Datos Stack

Lista1

newnodo

heap

ref

dato1 = 0

dato2 = 1

Datos Stack

i1 = ?

i2 = ?

next = ?

Page 18: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

18 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

Figura P2.3

Al salir de Push, desaparecen las variables automáticas, ubicadas en el stack, y la situación

queda:

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.

Lista1

newnodo

heap

ref

dato1 = 0

dato2 = 1

Datos Stack

i1 = 0

i2 = 1

next

Lista1

heap Datos Stack

i1 = 0

i2 = 1

next

Page 19: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 19

Profesor Leopoldo Silva Bijit 20-01-2010

Las listas con cabecera ( header ) permiten diseños alternativos.

b) Después de crealista, el espacio queda:

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.

Lista1

heap Datos

i1 = 0

i2 = 1

next

i1=4

i2 = 5

next

i1 = 3

i2 = 4

next

i1 = 2

i2 = 3

next

i1 = 1

i2 = 2

next

Lista2 i1 = 5

i2 = -1

next

i1 =1

i2 = 3

next

i1 = 2

i2 = 2

next

i1 = 3

i2 = 1

next

i1 = 4

i2 = 0

next

Page 20: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

20 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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+1x2

2+0x2

1+1x2

0 = 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++;

}

Page 21: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 21

Profesor Leopoldo Silva Bijit 20-01-2010

*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.

Page 22: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

22 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

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:

clave

p2 p3 p1

Page 23: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 23

Profesor Leopoldo Silva Bijit 20-01-2010

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:

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.

pn

6

p2 p3 p1

4

p2 p3 p1

Page 24: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

24 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

pn=creanodo(5);

Figura P2.7.

pn->p3=pn;

Figura P2.8.

pn->p1=creanodo(3);

Figura P2.9.

pn->p1->p3=pn;

Figura P2.10.

pn

5

pn

5

pn

5

3

pn

5

3

Page 25: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 25

Profesor Leopoldo Silva Bijit 20-01-2010

pn->p2=creanodo(8);

Figura P2.11.

pn->p2->p3=pn->p1;

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;

pn

5

3 8

pn

5

3 8

Page 26: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

26 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

pn

6

p2 p3 p1

4

p2 p3 p1

Page 27: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 27

Profesor Leopoldo Silva Bijit 20-01-2010

Antes de main, el espacio de variables puede visualizarse según:

Figura P2.13.

Figura P2.14.

x

p

y

q

w

px

x

p

y

q

z

x

p

y

q

w

px

x

p

y

q

z

px->p =&z w.q=px->p;

Page 28: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

28 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

Figura P2.15.

Figura P2.16.

x

p

y

q

w

px

x

p

y

q

z

z.p=w.p

px->q->q=px

x 2

p

y 8

q

w

px

x 2

p

y 9

q

z

w.x=z.x=2

(*px).y=8;

(*(w.q)).y=9

Page 29: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 29

Profesor Leopoldo Silva Bijit 20-01-2010

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 ;

x 2

p

y 8

q

w

px

x 2

p

y 9

q

z

px =(pt)malloc(sizeof(t));

x 12

p

y 12

q

px ->p=px->q=(pt)0;

px ->x=px->y=12;

Page 30: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

30 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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);

}

Page 31: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 31

Profesor Leopoldo Silva Bijit 20-01-2010

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()

Page 32: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

32 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

{ 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;

Page 33: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 33

Profesor Leopoldo Silva Bijit 20-01-2010

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);

}

Page 34: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

34 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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.

Page 35: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

Definición de Estructuras de Datos en C. 35

Profesor Leopoldo Silva Bijit 20-01-2010

Í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

Page 36: Cap.2 Definición de estructuras de datos en C.lsb/elo320/clases/c2.pdf · 1 Profesor Leopoldo Silva Bijit 20-01-2010 Capítulo 2. Definición de Estructuras de Datos en C. Se desea

36 Estructuras de Datos y Algoritmos

Profesor Leopoldo Silva Bijit 20-01-2010

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