Sunteți pe pagina 1din 12

| Programación - IQ| Unidad 6 |

Programación - IQ
Unidad 6 - Arreglos y datos complejos.
Competencia específica a desarrollar:
 Resolver problemas específicos aplicando Arreglos, para estructurar modelos que integren un lenguaje
adecuado en el ámbito de interés.

Introducción
Los arreglos también son conocidos como Array, por su nombre en inglés, y un arreglo es un conjunto de
variables del mismo tipo que tienen el mismo nombre y se diferencian por un índice.
Para entender el concepto y el uso de los arreglos, se presenta el siguiente ejemplo:
Supongamos que un meteorólogo quiere guardar en una computadora la temperatura que se ha registrado
en cada hora durante el día. Y para darle cierta utilidad, al final se calcula la media de las temperaturas
registradas. Con los conocimientos que se tienen hasta ahora, el programa podría ser de la siguiente
forma:
#include <stdio.h>
int main()
{
/* Se declaran 24 variables, una para cada hora del dia */
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16;
int temp17, temp18, temp19, temp20, temp21, temp22, temp23, temp0;
int media;

/* Se pide el valor de cada una de las variables */


printf( "Temperatura de las 0: " );
scanf( "%i", &temp0 );
printf( "Temperatura de las 1: " );
scanf( "%i", &temp1 );
printf( "Temperatura de las 2: " );
scanf( "%i", &temp2 );
...
printf( "Temperatura de las 23: " );
scanf( "%i", &temp23 );

media = ( temp0 + temp1 + temp2 + temp3 + temp4 + . . . + temp23 ) / 24;


printf( "\nLa temperatura media es %i\n", media );
}
Nota: Los puntos suspensivos se han puesto para no tener que escribir todo y por lo tanto no se pueden
usar en un programa.
Este es un ejemplo que tiene tan sólo 24 variables, ¿qué pasaría si fueran más?, Precisamente en estos
casos en donde se pueden aplicar los arreglos.
Ahora se realizara el mismo programa utilizando un arreglo unidimensional. Se usaran también los
conocimientos sobre la sentencia de ciclo for.
#include <stdio.h>
int main()
{
int temp[24]; /* Con esto se declaran las 24 variables */
float media=0;
1
| Programación - IQ| Unidad 6 |

int hora;

/* Ahora se pide el valor de cada una */


for( hora=0; hora<24; hora++ )
{
printf( "Temperatura de las %i: ", hora );
scanf( "%i", &temp[hora] );
media += temp[hora];
}
media = media / 24;

printf( "\nLa temperatura media es %f\n", media );


}
Como se puede observar, es un programa más rápido de escribir y más cómodo para el usuario que el
ejemplo anterior.
Como se sabe, cuando se declara una variable, lo que se está haciendo es reservar una zona de la
memoria para ella. Cuando se declara un arreglo lo que se hace (en el ejemplo anterior) es reservar
espacio en memoria para 24 variables de tipo int. El tamaño del arreglo (24) se indica entre corchetes al
definirlo.
En el ejemplo, se recorre el arreglo mediante un ciclo for y se van dando valores a los distintos elementos
del arreglo. Para indicar a qué elemento se hace referencia, se usa un número entre corchetes (en el
ejemplo, la variable hora), a este número es lo que se le conoce como índice. El primer elemento de la
matriz en C tiene el índice 0, El segundo tiene el 1 y así sucesivamente. De forma que si se quiere dar un
valor al elemento 4 (índice 3), quedaría:
temp[ 3 ] = 20;
Nota: No hay que confundirse. En la declaración del arreglo, el número entre corchetes indica el número de
elementos en arreglo, en cambio cuando se usa el arreglo, el número entre corchetes indica que es el
índice.

6.1 - Arreglos unidimensionales: algoritmo, codificación y aplicación.


Un arreglo unidimensional es un tipo de datos estructurado que está formado por una colección finita y
ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. Los
datos que se guarden en los arreglos todos deben ser del mismo tipo.
Declaración de un arreglo unidimensional
La forma general de declarar un arreglo de una sola dimensión, es la siguiente:
tipo_de_dato nombre_del_arreglo [dimensión];
Donde:
 tipo_de_dato.- Es uno de los tipos de datos conocidos y usados por el lenguaje C (int, char, float, etc.)
o de los definidos por el usuario con typdef.
 nombre_del_arreglo.- Es el nombre de variable que se le da al arreglo para su referencia.
 dimensión.- Es el número de elementos que puede tener el arreglo.
Como se ha indicado antes, al declarar un arreglo se reserva en memoria tantas variables del tipo_de_dato
como la indicada en dimensión.
Algoritmo, codificación y aplicación
Se ha visto en el ejemplo anterior, que se tiene que indicar en varios sitios el tamaño del arreglo: en la
declaración, en el ciclo for y al calcular la media. Este es un ejemplo de programa pequeño, en un
2
| Programación - IQ| Unidad 6 |

programa mayor, probablemente habrá que escribirlo muchas más veces. Si en un momento dado se
quiere cambiar la dimensión del arreglo, se tendrá que cambiar en todos los lugares donde se use. Si hay
una equivocación al escribir el tamaño (ponemos 25 en lugar de 24) se cometerá un error y puede no ser
posible darse cuenta. Por eso es más recomendable el uso de constantes con un nombre declaradas con la
sentencia #define, por ejemplo:
#include <stdio.h>
#define ELEMENTOS 24
int main()
{
int temp[ELEMENTOS]; /* Para declarar las 24 variables */
float media;
int hora;

/* Ahora se piden el valor de cada una */


for( hora=0; hora<ELEMENTOS; hora++ )
{
printf( "Temperatura de las %i: ", hora );
scanf( "%i", &temp[hora] );
media += temp[hora];
}
media = media / ELEMENTOS;

printf( "\nLa temperatura media es %f\n", media );


}
Ahora con sólo cambiar el valor de la constante ELEMENTOS una vez, se estará haciendo el cambio en
todo el programa.
Inicialización de un arreglo
En el lenguaje C se pueden inicializar los arreglos al declararlos, igual que se hace con las variables.
Por ejemplo para inicializar una variable seria:
int hojas = 34;
Para inicializar un arreglo seria:
int temperaturas[24] = { 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 24, 22, 21, 20, 18, 17,
16, 17, 15, 14, 14, 14, 13, 12 };
Ahora el elemento 0 (que será el primero), es decir temperaturas[0] valdrá 15. El elemento 1 (el segundo)
valdrá 18 y así sucesivamente con todos los demás valores. Un ejemplo de aplicación sería el siguiente:
Recorrido del arreglo.
#include <stdio.h>
int main()
{
int hora;
int temperaturas[24] = { 15, 18, 20, 23, 22, 24, 22, 25, 26, 25, 24,
22, 21, 20, 18, 17, 16, 17, 15, 14, 14, 14, 13, 12 };
/* Recorrido del arreglo */
for (hora=0 ; hora<24 ; hora++ )
{
printf( "La temperatura a las %i era de %i grados.\n", hora, temperaturas[hora] );
}
}
Se le ha indicado al compilador que reserve memoria para un arreglo de 24 elementos de tipo int.
3
| Programación - IQ| Unidad 6 |

Nota: ¿Qué pasaría si se registran menos elementos de los reservados?, no pasa nada, sólo que los
elementos que no se registren valdrán cero.
Paso de un arreglo a una función
En el lenguaje C no se puede pasar un arreglo entero a una función. Lo que se tiene que hacer es pasar un
puntero (apuntador) al arreglo. Con este puntero se puede recorrer el arreglo completo:
#include <stdio.h>
int sumar( int *m )
{
int suma, i;

suma = 0;
for( i=0; i<10; i++ )
{
suma += m[i];
}
return suma;
}

int main()
{
int contador;
int matriz[10] = { 10, 11, 13, 10, 14, 9, 10, 18, 10, 10 };

for( contador=0; contador<10; contador++ )


printf( " %3i\n", matriz[contador] );
printf( "+ -----\n" );
printf( " %3i", sumar( matriz ) );
}
Este programa tiene algunas cosas adicionales como que muestra toda la matriz en una columna. Además
se usa para imprimir los números %3i. El 3 indica que se tienen que alinear los números a la derecha, así
queda más elegante.

6.2 - Arreglos multidimensionales: algoritmo, codificación y aplicación.


Un arreglo bidimensional tiene dos dimensiones (una fila y una columna) y es un caso particular de los
arreglos multidimensionales. En el lenguaje C, las dimensiones se manejan por medio de un par de
corchetes, dentro de los que se escriben, separados por comas, los valores de las dos dimensiones, una
para la fila y la otra para la columna.
Un arreglo bidimensional está compuesto, por un conjunto de elementos homogéneos y se puede acceder
a los datos utilizando dos subíndices, este tipo de arreglo es también conocido como matriz.
Declaración de un arreglo bidimensional (matriz)
Un arreglo bidimensional se define así:
La forma general de declarar un arreglo de dos dimensiones (bidimensional), es la siguiente:
tipo_de_dato nombre_del_arreglo [fila, columna];
Donde:
 tipo_de_dato.- Es uno de los tipos de datos conocidos y usados por el lenguaje C (int, char, float, etc.)
o de los definidos por el usuario con typdef.
 nombre_del_arreglo.- Es el nombre de variable que se le da al arreglo para su referencia.
 fila.- Es el número filas o renglones que puede tener el arreglo.
4
| Programación - IQ| Unidad 6 |

 columna.- Es el número de columnas que puede tener el arreglo.


Ejemplos:
int arreglo[10][10];
float matriz[10][10];
También se pueden utilizar constantes para definir la dimensión del arreglo de dos dimensiones:
#define N 10
int arreglo[N][N];
Inicialización del arreglo bidimensional (matriz)
Una matriz o arreglo bidimensional se puede inicializar de la siguiente forma:
int matriz[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
Con la anterior asignación se crea en memoria una matriz igual a la siguiente:

También se puede utilizar una estructura for dentro de otra estructura for para inicializar los valores de un
arreglo de dos dimensiones.
Para leer desde teclado una matriz de números enteros de dimensión 3x3.
#include <stdio.h>
#define TAM 3
void main()
{
int matriz[TAM][TAM];
int i, j;
for( i=0; i<TAM ; i++)
{
for( j=0; j<TAM; j++)
{
printf(”Ingrese el elemento [%d,%d]: “,i,j);
scanf(“%d”,&matriz[i][j]);
}
}
}
Supongamos que ahora se quiere almacenar las temperaturas de cada hora de todo un día y toda la
semana. Según lo que se aprendió en los temas anteriores, se puede usar un arreglo unidimensional para
día de la semana. En cada uno de esos arreglos se podría almacenar las temperaturas de cada día.
Una posible solución sería:
#include <stdio.h>
#define DIAS 7
#define HORAS 24
int main()
{
int temp[DIAS][HORAS];
float media = 0;
int hora, dia;

5
| Programación - IQ| Unidad 6 |

for( dia=0 ; dia<DIAS ; dia++ ) {


for( hora=0 ; hora<HORAS ; hora++ ) {
printf( "Temperatura de las %d del día %d: ", hora, dia );
scanf( "%i", &temp[dia][hora] );
media += temp[dia][hora];
}
}
media = media / HORAS / DIAS;
printf( "\nLa temperatura media de toda la semana es %f\n", media );
return 0;
}
Acceso a los elementos de un arreglo bidimensional
En un arreglo de dos dimensiones se necesitan también dos índices para acceder a sus elementos.
Si se utiliza: matriz[i][j], entonces i se refiere a la fila y j a la columna.
Para acceder al elemento de la segunda fila y segunda columna de la matriz del ejemplo anterior, tenemos:
int nro = matriz[1][1];
En la variable nro se guardara el número 5. Para imprimir todo el contenido de la matriz tenemos:
#include <stdio.h>
int main() {
int fila, columna;
int matriz[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
for(fila=0; fila<3; fila++)
for(columna=0; columna<3; columna++)
printf("%d", matriz[fila][columna]);
return 0;
}
Las matrices o arreglos bidimensionales se suelen utilizar en cálculos matemáticos, operaciones con
matrices, recorridos por matrices, y cualquier uso que se le pueda dar.
Ejercicio: Los alumnos de primer semestre de la carrera de Ingeniería en Química son 20. Todos los
alumnos toman inicialmente 5 materias lo que quiere decir que al final del semestre tendría 5 calificaciones
cada alumno. Escribir un programa que pida las 5 calificaciones de los 20 alumnos y luego devuelva el
promedio de todas las notas.

6.3 - Representación de TDA: algoritmo, codificación y aplicación.


Una definición de TDA (Tipo de Dato Abstracto) podría ser la siguiente:
Es un tipo de dato definido por el usuario para representar una entidad (abstracción) a través de sus
características (datos o atributos) y sus operaciones o funciones (algoritmos que manipulan los datos).
TDA = Datos + Algoritmos-Datos.
Una función es una generalización del concepto operador para ser aplicado a operaciones generales
definidas por un programador. Una función puede ser aplicada a diferentes datos. Con funciones se logra
una ocultación de información, denominado encapsulación. Un concepto similar es la abstracción de
datos. Un tipo de datos abstracto (TDA) define una nueva clase de objeto o concepto que puede
manejarse con independencia de la estructura de datos para representarlo.
Para ello es necesario especificar:
• Las operaciones que se puede realizar con los objetos.
• El efecto que se produce al actuar con las operaciones sobre los mismos.
6
| Programación - IQ| Unidad 6 |

Así un TDA es una generalización de los tipos de datos primitivos de un lenguaje de programación. Un TDA
encapsula la definición del tipo y todas las operaciones con este tipo.
Los lenguajes de programación entregan al programador ciertos tipos de datos básicos o primitivos,
especificando el conjunto de valores que una variable de uno de esos tipos puede tomar y el conjunto de
operaciones realizables sobre los mismos.
Los TDA’s son generalizaciones de los tipos de datos básicos y de las operaciones primitivas. Además, un
TDA encapsula cierto tipo de datos en el sentido que es posible poner la definición del tipo y todas las
operaciones con ese tipo en una sección de un programa.
Cada conjunto de operaciones define un TDA distinto. Por ejemplo, se puede definir un tipo de datos
abstracto CONJUNTO con el cual se pueden definir las siguientes operaciones:
• ANULA(A) Hace vacío al conjunto A
• UNION(A, B, C) Construye el conjunto C a partir de la unión de los conjuntos A y B.
• TAMAÑO(A) Entrega la cantidad de elementos del conjunto A.
Existen muchas estructuras de datos que se pueden utilizar para implantar eficientemente un conjunto. Por
ejemplo, mediante arreglos. Las operaciones sobre conjuntos se pueden implantar mediante funciones.
Especificación de un TDA
Es la descripción formal del tipo de dato que representa a una entidad a través de sus propiedades y su
comportamiento. Dos niveles:
 Especificación Sintáctica:
¿Qué hace? Especificación de las entidades y sus propiedades (interfaz)
• Definir el nombre de las entidades abstractas.
• Definir el nombre de las operaciones indicando el dominio (argumentos) y el codominio o rango (los
valores de retorno)
 Especificación Semántica:
¿Cómo lo hace? Descripción de la representación del objeto (estructura de los datos) y desarrollo de las
operaciones.
1) Definir el significado de cada operación usando los símbolos definidos en la especificación
sintáctica.
Ejemplo: implementación del TDA conjunto
El objetivo del ejemplo es definir una clase que gestione conjuntos de enteros. Las operaciones para el
conjunto de enteros son las siguientes:
 Unión.- La unión de dos conjuntos A y B, denotado por A  B; es el conjunto de todos los elementos
que están en A, en B o en ambos.
 Intersección.- La intersección de dos conjuntos A y B, denotado por A  B; es el conjunto de todos los
elementos que pertenecen a ambos A y B simultáneamente.
 Diferencia.- La diferencia de conjuntos A y B, denotado por A - B; es el conjunto de elementos que
pertenecen a A pero no pertenecen a B
 Pertenencia.- El número entero x es un miembro o pertenece al conjunto A si x es un elemento de A.
Esta operación se denota por x  A .
 Comparaciones.- Los conjuntos pueden compararse entre sí mediante el uso de operadores
relacionales.
a. Subconjunto.- El conjunto A es un subconjunto del conjunto B si y solo si todo elemento de A
es también un elemento de B.
b. Igualdad.- El conjunto A es igual al conjunto B si y solo si cada elemento de A está en B y
cada elemento de B está en A.
7
| Programación - IQ| Unidad 6 |

c. Desigualdad.- El conjunto A es diferente del conjunto B si y solo si A y B no son iguales.


 Cardinalidad.- La cardinalidad de A, denotado por #A es el número de elementos de A
La implementación del TDA conjunto se hace mediante una clase a la que se llama conjunto.
El diseño de la clase conjunto se presenta en la siguiente figura.

Figura 1. El Tipo Abstracto de Datos conjunto


El TDA conjunto se implementa en un archivo de cabecera (header) llamado conjunto.h; y el archivo de
prueba para la clase conjunto se escribe en el archivo fuente conjunto.cpp. Los listados de ambos
archivos se presentan en las Figuras 2 y 3 respectivamente.
Nótese que para las operaciones del TDA conjunto se han sobrecargado los operadores del modo
siguiente:
+ para la unión
- para la diferencia
* para la intersección
< para el subconjunto
== para la igualdad
¡= para la diferencia y
<= para el subconjunto propio
La sobrecarga de operadores es una facilidad muy poderosa soportada por C++, que permite al usuario
añadir un nuevo comportamiento a los operadores primitivos proporcionados por el lenguaje. A
continuación se explica este concepto: se sabe que el operador + permite sumar dos objetos del mismo tipo
como por ejemplo; dos enteros o dos reales, sin embargo se puede hacer que este mismo operador +
adquiera dos nuevos significados útiles para el TDA conjunto según lo siguiente:
1. Añadir o incluir un nuevo elemento al conjunto y
2. Realizar la unión de conjuntos.

8
| Programación - IQ| Unidad 6 |

Las secciones de código en C++, para estas operaciones se presentan enseguida.


Figura 2 – Archivo conjunto.h
//implementacion de la libreria conjunto.h
#ifndef CONJUNTO_H
#define CONJUNTO_H
const int N = 100;
using namespace std;
//declarando la clase conjunto
class conjunto {
public:
conjunto(); //constructor
~conjunto(); //destuctor
void imprimir();
void ordenar();
bool pertenece(int x);
int cardinalidad();
void operator+(int x);
//funciones amigas
friend conjunto operator+(conjunto c1 , conjunto c2);
friend conjunto operator*(conjunto c1 , conjunto c2);
friend conjunto operator-(conjunto c1 , conjunto c2);
//comparaciones
friend bool operator<=(conjunto c1, conjunto c2);
friend bool operator==(conjunto c1, conjunto c2);
friend bool operator!=(conjunto c1, conjunto c2);
friend bool operator<(conjunto c1, conjunto c2);
private:
int elem[N];
int ne;
};
//constructor
conjunto::conjunto() {
int i;
for(i=0; i<N; i++)
elem[i] = 0;
ne = 0;
}
//destructor
conjunto::~conjunto() {
}
//sobrecarga para el operador + para insertar un nuevo elemento
void conjunto::operator+(int x ) {
if ( pertenece(x) == false ) {
elem[ne] = x;
ne++;
} else
cout<<"Elemento ya existe"<<endl;
}
//imprimir los elementos del conjunto
void conjunto::imprimir() {
int i;
if ( ne > 0 ) {
ordenar();
for(i=0; i<ne; i++)

9
| Programación - IQ| Unidad 6 |

cout<<elem[i]<<"\t";
cout<<endl;
} else
cout<<"El conjunto esta vacio"<<endl;
}
//ordenar los elementos del conjunto
void conjunto::ordenar() {
int i,j,x;
if ( ne > 1 ) {
for(i=0; i<ne-1; i++)
for(j=i+1; j<ne; j++)
if ( elem[i] > elem[j] ) {
x = elem[i];
elem[i] = elem[j];
elem[j] = x;
}
}
}
// el elemento pertenece al conjunto?
bool conjunto::pertenece(int x) {
int i;
bool b;
b = false;
i = 0;
while( b == false && i < ne)
if (elem[i] == x)
b = true;
else
i++;
return b;
}
//cardinalidad: numero de elementos del conjunto
int conjunto::cardinalidad() {
return ne;
}
//definiendo la union de conjuntos
conjunto operator+(conjunto c1, conjunto c2) {
conjunto c3;
int x, i;
for(i=0; i<c1.ne; i++)
c3.elem[i] = c1.elem[i];
c3.ne = c1.ne;
for(i=0; i<c2.ne; i++) {
x = c2.elem[i];
if (c3.pertenece(x) == false) {
c3.elem[c3.ne] = x;
c3.ne++;
}
}
return c3;
}
//definiendo la interseccion de conjuntos
conjunto operator*(conjunto c1, conjunto c2) {
conjunto c3;
int x,i;

10
| Programación - IQ| Unidad 6 |

for(i=0; i<c1.ne; i++) {


x = c1.elem[i];
if ( c2.pertenece(x) == true ) {
c3.elem[c3.ne] = x;
c3.ne++;
}
}
return c3;
}
//definiendo la diferencia de conjuntos
conjunto operator-(conjunto c1, conjunto c2) {
conjunto c3;
int x,i;
for(i=0; i<c1.ne; i++) {
x = c1.elem[i];
if ( c2.pertenece(x) == false ) {
c3.elem[c3.ne] = x;
c3.ne++;
}
}
return c3;
}
//definiendo el subconjunto propio
bool operator<=(conjunto c1, conjunto c2) {
int x,i;
for(i=0; i<c1.ne; i++) {
x = c1.elem[i];
if ( c2.pertenece(x) == false )
return false;
}
return true;
}
//definiendo la igualdad de conjuntos
bool operator==( conjunto c1, conjunto c2 ) {
if ( ( c1 <= c2 ) && ( c2 <= c1 ) )
return true;
else
return false;
}
//definiendo la desigualdad de conjuntos
bool operator!=( conjunto c1, conjunto c2 ) {
return !(c1 == c2);
}
//definiendo el subconjunto
bool operator<(conjunto c1, conjunto c2) {
if ((c1 <= c2) && (c1 != c2))
return true;
else
return false;
}
#endif //fin de la libreria conjunto.h

11
| Programación - IQ| Unidad 6 |

Figura 3 - Archivo conjunto.cpp


// Programa: conjunto.cpp
#include <iostream>
#include <stdlib.h>
#include "conjunto.h"
int main() {
using namespace std;
conjunto A,B,C,D,E;
int i,x,n;
cout<<"Cuantos elementos desea ingresar para el Conjunto A ? ";
cin>>n;
for(i=1; i<=n; i++) {
cout<<"Ingrese elemento "<<i<<": ";
cin>>x;
A + x;
}
A.imprimir();
cout<<"\nCuantos elementos desea ingresar para el Conjunto B ? ";
cin>>n;
for(i=1; i<=n; i++) {
cout<<"Ingrese elemento "<<i<<": ";
cin>>x;
B + x;
}
cout<<"\nConjunto A: ";
A.imprimir();
cout<<"\nConjunto B: ";
B.imprimir();
C = A + B;
cout<<endl<<"\nC = A UNION B"<<endl;
C.imprimir();
cout<<"La cardinalidad de C es "<<C.cardinalidad()<<endl;
D = A * B;
cout<<endl<<"\nD = A INTERSECCION B"<<endl;
D.imprimir();
cout<<"La cardinalidad de D es "<<D.cardinalidad()<<endl;
E = A - B;
cout<<endl<<"\nE = DIFERENCIA de A y B"<<endl;
E.imprimir();
cout<<"La cardinalidad de E es "<<E.cardinalidad()<<endl;
if (A <= B) {
cout<<"\nA es subconjunto de B"<<endl;
if (A < B)
cout<<"\nA es subconjunto propio de B"<<endl;
} else
cout<<"\nA no es subconjunto de B"<<endl;
if (A == B)
cout<<"\nA y B son iguales"<<endl;
else
cout<<"\nA y B son diferentes"<<endl;
cout<<endl;
system("PAUSE");
}

12

S-ar putea să vă placă și