arrays unidimensionales (vectores)

Anuncio
P RÁCTICAS DE F UNDAMENTOS DE I NFORMÁTICA
DIPLOMATURA EN ESTADÍSTICA
CURSO 2009 – 2010
MARTES 15 Y JUEVES 10 DE DICIEMBRE DE 2009
SESIÓN
06 ARRAYS UNIDIMENSIONALES (VECTORES)
SESIÓN
07 ARRAYS BIDIMENSIONALES (MATRICES)
Hasta ahora hemos estado trabajando principalmente con cuatro tipos de datos básicos: enteros
(integer), reales (real), caracteres (char) y valores lógicos (boolean). Sin embargo, existen otros
tipos de datos más complejos como los tipos estructurados que permiten almacenar una colección
de valores bajo un único identificador de variable, es decir, la colección tiene un único nombre que
engloba todos esos valores. Por supuesto, se sigue podiendo acceder individualmente a cada valor
o componente de la colección. Por ejemplo, si en uno de nuestros programas necesitásemos
almacenar diez valores de tipo entero, en lugar de crearnos diez variables con diez identificadores
diferentes num1, num2, ..., num10, podríamos almacenar esos diez valores utilizando una única
variable de un tipo estructurado, y luego acceder a cada valor concreto a través del identificador de
la variable general y el índice concreto del valor, que podría ser por ejemplo de la posición 1 a la
posición 10.
Los arrays son un caso concreto de tipo estructurado (como los registros, los conjuntos y los
ficheros). Básicamente son variables capaces de almacenar una colección de valores que sean del
mismo tipo (por ejemplo, como decíamos antes, diez enteros). Como veremos a lo largo de esta
sesión, los arrays pueden tener una o más dimensiones. Cuando tienen una sola dimensión se les
suele llamar vectores, y cuando tienen dos dimensiones se les conoce como matrices (lo mismo que
en matemáticas o física). Aunque como también veremos, el número de dimensiones no tiene por
qué estar limitado a dos como máximo, sino que en general hablaremos de arrays
multidimensionales.
ARRAYS UNIDIMENSIONALES (VECTORES)
El caso más sencillo de arrays son los unidimensionales, que no son otra cosa que vectores, es
decir, una fila de valores. En la figura de abajo puedes ver un ejemplo de una variable de ese tipo
que por ahora llamaremos vector (luego veremos cómo se llama en Pascal). A esa variable la hemos
llamado numeros, y almacena en este caso diez valores de tipo entero. Para acceder a cada valor
concreto utilizamos su índice o posición, que va en este caso desde 1 hasta 10. Así, el primer
elemento del vector será numeros[1], el segundo numeros[2], y así sucesivamente.
numeros
4
27
215
49
-15
11
-23
0
8
16
1
2
3
4
5
6
7
8
9
10
Cada uno de estos elementos se trata como si fuera una variable individual, es decir, cuando
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
1
escribimos numeros[1] es como si tuviéramos nuestra variable num1 de tipo entero, por lo que
podemos asignarle cualquier valor entero a la variable utilizando el operador de asignación := o
hacer cualquier operación que se nos ocurra con ella.
Hasta ahora, para declarar una variable escribíamos su nombre, seguido de dos puntos, y después el
tipo de esa variable acabado en punto y coma (por ejemplo, num : integer;). Para declarar una
variable de tipo vector en Pascal tenemos que hacer uso de la palabra reservada array, tal y como se
muestra a continuación
nombreDeLaVariable : array [índiceInicial..índiceFinal] of tipoBásico;
donde índiceInicial e índiceFinal son los índices (posiciones) inicial y final de la colección de
valores, y tipoBásico es cualquiera de los tipos básicos que hemos visto hasta ahora (integer, real,
char, boolean, incluso string). ¿Cómo declararíamos el vector numeros del que hablamos
anteriormente?
numeros : array [1..10] of integer;
De esta forma tendremos una variable cuyo identificador es numeros y que es de tipo array de
enteros, cuyos índices van desde el 1 hasta el 10, por lo que tendremos diez enteros.
Veamos un ejemplo concreto en Pascal de cómo podríamos leer por teclado un vector de diez
enteros, calcular la media de todos ellos y mostrarla por pantalla
Lo primero que tenemos que hacer es declarar el vector junto con las otras variables que vayamos a
utilizar. Después, ya en el cuerpo de nuestro programa principal, podemos leer todas las
2
Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010
Diplomatu ra en Estadíst ica – Universidad de Granada
componentes del vector. Pero no hace falta poner diez instrucciones read, sino que podemos utilizar
un bucle for para que resulte mucho más fácil, claro y conciso. Una vez leídos todos los valores,
pasamos a procesarlos. En este caso inicializamos la suma al valor cero, y utilizando otro bucle for
vamos añadiéndole el valor de cada componente del vector, a las cuales accedemos mediante su
índice. Finalmente mostramos por pantalla la suma dividida entre el número de valores.
En realidad, los índices del vector no tienen por qué empezar por el valor 1. En el ejemplo anterior
podrían haber ido perfectamente desde el 11 hasta el 20. Podrían ser incluso negativos. La única
restricción es que el índice inicial debe ser menor o igual que el final. Prueba a cambiar la
declaración del vector del ejercicio anterior para que los índices sean negativos y vayan desde el -10
hasta el -1. Una vez hechas las modificaciones, comprueba si sigue funcionando el programa (se
compila y se ejecuta correctamente).
Es posible que hayas recibido un mensaje de error por pantalla al empezar a introducir los números
(program exited with exitcode = 201). Si es así, la razón es que en la declaración del array has
cambiado los índices para que vayan del -10 al -1, pero sin embargo los bucles for siguen
accediendo a las componentes utilizando los índices del 1 al 10. Estás intentando acceder por tanto
a un elemento con un índice que está fuera del rango declarado, lo cual causa ese error en tiempo de
ejecución. Podemos evitar tener que estar cambiando los valores inicial y final de los bucles cada
vez que se modifican el tamaño o los índices del vector de la siguiente manera. En lugar de iterar
desde
1
hasta
10
podemos
iterar
desde
low(nombreDeLaVariable)
hasta
high(nombreDeLaVariable) tal y como se muestra en la siguiente imagen
Estas funciones low y high lo que hacen es devolver el índice menor y mayor, respectivamente, del
array que se les pasa como argumento. Además, observa cómo también hemos utilizado en el
ejemplo anterior la función length (que ya vimos en la segunda práctica) para calcular cuántos
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
3
elementos tiene el vector, en lugar de poner directamente el valor 10. Así, si cambiamos la longitud
del vector en la declaración, el programa seguiría funcionando sin tener que realizar ninguna otra
modificación.
Otra de las cosas que podemos hacer con los arrays es inicializar el valor de cada componente en
la propia declaración. Para ello, sólo tenemos que poner, después del tipo de array, un igual
seguido de la lista de valores iniciales separados por comas y en entre paréntesis
numeros : array [-10..1] of integer = (4, 27, 215, 49, -15, 11, -23, 0, 8, 16);
Además de números, los índices de los vectores pueden ser caracteres. El siguiente vector por
ejemplo podría almacenar un valor entero para cada uno de los caracteres comprendidos entre la ‘a’
y la ‘z’
frecuencias : array ['a'..'z'] of integer;
Dicho vector podría utilizarse para almacenar con qué frecuencia (cuántas veces) aparece cada letra
en un texto determinado
frecuencias
54
9
17
...
2
‘a’
‘b’
‘c’
...
‘z’
Así, podríamos almacenar en frecuencias[‘a’] cuántas letras ‘a’ contiene el texto. De esta forma
podríamos intentar adivinar en qué idioma está escrito el texto sin necesidad de conocer ni una sola
palabra de ese lenguaje, ya que cada letra tiene una frecuencia de aparición diferente en cada idioma
Porcentaje de aparición de cada letra en un texto
16,000
14,000
12,000
10,000
8,000
6,000
4,000
2,000
0,000
a b c d e f g h i j k l m n o p q r s t u v w x y z
Español
4
Inglés
Francés
Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010
Diplomatu ra en Estadíst ica – Universidad de Granada
Como vemos, letras como la h, la k, y la w son muchísimo más comunes en inglés que en español y
en francés, por lo que si la frecuencia de aparición relativa de estas letras en un texto es alta, cabría
la posibilidad de pensar que el texto está escrito en inglés. Lo mismo pasa en español con la vocal a
o en francés con las letras u y v. Pero hay que tener en cuenta que para que este método de
detección del idioma funcione más o menos bien, el texto debe tener un tamaño aceptable.
STRING
Un caso concreto de vectores son las cadenas de caracteres, es decir, los string, que no son otra
cosa que arrays unidimensionales de caracteres (cada posición del vector es un carácter, un char).
Nosotros, siempre que hemos declarado un string lo hemos hecho de la siguiente manera
cadena : string;
Esta declaración reserva espacio para una cadena de tamaño máximo, es decir, de 255 caracteres.
Si quisiéramos tener una cadena de menor tamaño para almacenar por ejemplo un DNI, podríamos
hacer perfectamente
dni : string[9];
Así reservaríamos espacio solamente para 9 caracteres. Para acceder a la primera cifra del DNI
escribiríamos dni[1], para la segunda dni[2], y así hasta la última, que sería dni[8].
Pascal cuenta con un conjunto de operadores, funciones y procedimientos para manipular cadenas
de caracteres. Ya hemos visto en alguna ocasión la función length, que calcula la longitud de una
cadena. También podemos concatenar cadenas utilizando la función concat, o simplemente
juntándolas con el operador + como se muestra a continuación
cadenaResultado := concat(‘Hola’, ‘ mundo’, ‘!!!’);
cadenaResultado := ‘Hola’ + ‘ mundo’ + ‘!!!’;
Ambas instrucciones almacenarían en la variable cadenaResultado la cadena ‘Hola mundo !!!’. Por
otro lado, si queremos copiar una subcadena podemos hacer la siguiente llamada
cadenaResultado := copy(‘Hola mundo!!!‘, 1, 4);
En este caso estaríamos copiando 4 caracteres de la cadena ‘Hola Mundo!!!’ empezando por la
posición 1, con lo que almacenaríamos en cadenaResultado la cadena ‘Hola’. Si lo que queremos es
insertar una cadena dentro de otra, podemos usar la función insert
cadenaResultado := insert(‘Hola !!!‘, ‘mundo’, 6);
Esto insertaría la cadena ‘mundo‘ en la posición 6 de la cadena ‘Hola !!!’, es decir, justo donde
comienzan los signos de exclamación. Para eliminar una subcadena, podemos hacer uso de delete
cadenaResultado := delete(‘Hola mundo!!!‘, 1, 4);
Como vemos, la sintaxis es muy parecida a la de la función copy, sólo que en este caso, además de
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
5
devolver la subcadena, esta se elimina de la cadena original. También podemos buscar una cadena
dentro de otra utilizando la función pos
posicionInicio := pos(‘Hola mundo!!!’, ‘mundo’);
Esta función devolvería la posición a partir de la que comienza la subcadena ‘mundo’ dentro de la
cadena ‘Hola mundo!!!’. Finalmente, para convertir cadenas en números y viceversa podemos usar
los procedimientos str y val
str(134.56, cadena)
val(‘134.56’, numero, variableDeError)
str asigna a la variable cadena la representación, en forma de cadena de caracteres, del número que
se le pasa como primer argumento, mientras que val hace exactamente lo contrario, asigna a la
variable numero el valor numérico que representa la cadena que se le pasa como primer parámetro.
En este último caso, si no se puede realizar la conversión (si por ejemplo estamos intentando
convertir en número la cadena ‘hola’), la variable variableDeError tomará un valor distinto de 0.
Por lo tanto, siempre que hagamos uso de val, deberemos comprobar a continuación el estado de
dicha variable de error.
ARRAYS DINÁMICOS
Hasta ahora hemos visto un determinado tipo de arrays, conocidos como arrays estáticos, los
cuales tienen siempre una longitud fija que se incluye en la declaración del array. Así, si queríamos
calcular la media de diez enteros nos creábamos un vector de longitud diez donde íbamos
almacenando los números que íbamos leyendo. Una vez que habíamos leído todos los valores,
recorríamos el vector para sumarlos y al final dividíamos entre la longitud del vector. Pero, ¿qué
pasa si lo que queremos es calcular la media de 20 valores? O peor aún, ¿qué pasa si es el usuario el
que tiene que decidir de cuántos números quiere calcular la media? En ese caso los arrays estáticos
ya no nos valen. Necesitamos poder definir dinámicamente, es decir, en tiempo de ejecución, cuál
va a ser la longitud del vector. Este tipo de arrays se conocen como arrays dinámicos. Para declarar
un array de forma dinámica simplemente tenemos que omitir el rango, es decir, los índices inicial y
final en la declaración del array
nombreDeLaVariable : array of tipoBásico;
o para nuestro ejemplo concreto
numeros : array of integer;
A continuación, y ya en el cuerpo del programa principal, podemos definer la longitud concreta que
va a tener el array (ya que la longitud inicial siempre es 0) realizando una llamada al procedimiento
setLength
setLength(numeros,10);
donde numeros es nuestra variable array dinámico, y 10 es la longitud que va a tener el array.
Veamos cómo quedaría el ejemplo del cálculo de la media utilizando un array dinámico
6
Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010
Diplomatu ra en Estadíst ica – Universidad de Granada
Observa cómo primero le pedimos al usuario que introduzca de cuántos números quiere realizar la
media y luego ya hacemos que el vector tenga esa longitud. Copia el programa y ejecútalo para
calcular la media de por ejemplo tres enteros. ¿Por qué número crees que empezarán a numerarse
los índices en los arrays dinámicos? Compruébalo.
Es muy importante que recuerdes que, a diferencia de lo que ocurre con las cadenas de caracteres
(los string) cuyos índices empiezan por 1, en el caso de los arrays dinámicos los índices comienzan
siempre por 0.
Aunque no entraremos en detalle en el siguiente aspecto, merece la pena mencionar que cuando se
realiza una asignación directa entre variables arrays dinámicas (por ejemplo A := B, siendo A y B
dos arrays dinámicos), no se realiza una copia elemento a elemento, sino que los dos arrays pasan a
compartir la misma zona de memoria, por lo que los cambios que realicemos en una variable se
verán reflejados automáticamente en la otra variable.
ARRAYS BIDIMENSIONALES (MATRICES)
Como ya hemos comentado, en la declaración de un array hay que especificar de qué tipo van a ser
sus componentes. Este tipo puede ser otro array, de forma que cada elemento del primer vector es a
su vez otro vector. Así podemos definir arrays bidimensionales, o lo que es lo mismo, matrices. La
siguiente declaración crea una variable llamada numeros de tipo array de cuatro elementos, en el
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
7
que cada elemento es a su vez un array formado por tres números enteros
numeros : array [1..4] of array of [1..3] of integer;
Este tipo de declaraciones de arrays de arrays se suele escribir de forma más abreviada de la
siguiente manera (ambas son equivalentes)
numeros : array [1..4,1..3] of integer;
numeros será por tanto una matriz de 4 filas por 3 columnas en la que cada elemento será un
número entero. Su representación gráfica sería la que se muestra a continuación
índiceFila
2
3
4
4
27
215
49
1
numeros -10
8
16
61
2
51
15
57
-3
3
índiceColumna
1
numeros es un array de cuatro elementos que contiene en cada posición un array de tres elementos.
Podemos acceder a cada una de estas celdas de la matriz de la siguiente manera
numeros[índiceFila][índiceColumna]
Por ejemplo, mediante numeros[1][1] accederíamos a la primera variable entera, que en este caso
contiene el valor 4, numeros[1][2] devolvería un -10, y así sucesivamente.
Al igual que ocurría con los vectores, podemos trabajar por separado con cada celda de la matriz y
tratarlas como si fueran variables independientes, o también podemos trabajar con la matriz de
forma global. Podríamos asignar por ejemplo el contenido de una matriz (o array en general,
porque no tiene que ser necesariamente bidimensional) a otra matriz, de forma que se copia cada
una de las celdas.
En el caso de las matrices bidimensionales, para la lectura de los datos por teclado deberemos
utilizar un doble bucle for anidado, de manera que el bucle más exterior se puede utilizar para
recorrer cada una de las filas de la matriz, y el bucle más interior recorre cada una de las columnas
de la fila que marca el bucle exterior. Sería algo similar a lo que aparece en el siguiente ejemplo.
Piensa qué es lo que haría exactamente este programa.
8
Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010
Diplomatu ra en Estadíst ica – Universidad de Granada
ARRAYS MULTIDIMENSIONALES
Los arrays multidimensionales no son más que una generalización de los vectores y matrices.
Podríamos tener por ejemplo un array de tres dimensiones (como si fuera un cubo). Para declararlo
simplemente tendríamos que especificar el rango de cada dimensión, separando cada rango por una
coma
array3D : array [1..5,1..10,1..15] of integer;
En este caso tendríamos 5 filas, 10 columnas y una profundidad igual a 15. Es como si tuviéramos
15 tablas de tamaño 5 x 10, una detrás de otra. Para acceder a cada elemento haríamos referencia al
índice que este tiene para cada dimensión. Por ejemplo, para acceder al elemento de la primera fila
y segunda columna, de la tercera tabla podríamos utilizar cualquiera de estas dos instrucciones
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
9
array3D[1][2][3]
array3D[1,2,3]
EJERCICIOS PARA PRACTICAR CON VECTORES
Ejercicio 01. Crea un programa que lea un vector por teclado y muestre su contenido por pantalla.
Ejercicio 02. Escribe un programa que lea n temperaturas por teclado y las almacene en un vector.
A continuación, el programa deberá calcular y mostrar por pantalla cuál es la temperatura media y
cuántas temperaturas son mayores o iguales que la media.
Ejercicio 03. Implementa un programa que calcule el número de elementos negativos, positivos y
nulos de un vector de n elementos introducido por teclado.
Ejercicio 04. Realiza una función que calcule el mayor elemento de una lista de tamaño n leída por
teclado.
Ejercicio 05. Crea una función que calcule el producto escalar de dos vectores.
Ejercicio 06. Implementa una función que diga si una cadena es un palíndromo, es decir, si se lee
igual de izquierda a derecha que de derecha a izquierda. Por ejemplo, la cadena ‘sos’, o
‘dabalearrozalazorraelabad’ son palíndromos.
Ejercicio 07. Escribe un procedimiento que invierta el contenido de un vector, de manera que el
primer elemento pase a ser el último y el último el primero, el segundo pase a ser el penúltimo y el
penúltimo el segundo, etc.
Ejercicio 08. Crea una función que cuente el número de veces que aparece una cadena dentro de
otra.
Ejercicio 09. Haciendo uso de las funciones de manipulación de cadenas, crea una función que
elimine todos los espacios en blanco existentes en una cadena.
EJERCICIOS PARA PRACTICAR CON MATRICES
Ejercicio 10. Construye un programa que lea por teclado una matriz de tamaño 3 x 3 y muestre por
pantalla la matriz opuesta.
Ejercicio 11. Crea una función que devuelva la suma de todos los valores de una matriz, la cual se
le pasa como parámetro.
Ejercicio 12. Escribe una función que devuelva el mayor elemento de una matriz.
Ejercicio 13. Crea una función que compruebe si dos matrices (que se le pasan como argumento)
son idénticas.
10
Práct icas de Fundamentos de Informátic a – Curso 2009 – 2010
Diplomatu ra en Estadíst ica – Universidad de Granada
Ejercicio 14. Realiza una función que diga si una matriz de tamaño m x n es simétrica, es decir, si
tiene igual número de filas que de columnas (m = n) y además el elemento en la posición (i, j) es
igual al elemento de la posición (j, i), para 1 ≤ i ≤ m, 1 ≤ j ≤ n.
Ejercicio 15. Construye un programa que compruebe si una matriz de tamaño 3 x 3 es un cuadrado
mágico, es decir, si las filas, las columnas y las diagonales suman lo mismo. Por ejemplo, la
siguiente matriz es un cuadrado mágico, ya que todas las filas, columnas y diagonales suman 15.
4
3
8
9
5
1
2
7
6
Ejercicio 16. Escribe un procedimiento que obtenga la matriz suma de dos matrices. El
procedimiento recibirá tres parámetros, los dos primeros corresponderán a las matrices que se
quieran sumar, y el tercero corresponderá a la matriz en la que se desea guardar la suma. Recuerda
que debes pasar la matriz resultado por referencia en lugar de por copia.
Ejercicio 17. Crea un procedimiento que calcule la matriz traspuesta de una matriz cualquiera.
Este documento está protegido bajo una licencia Creative Commons.
No se permite un uso comercial de la obra ni la generación de obras derivadas.
Eduardo E isman – [email protected] – http://decsai.ug r.es/~eisman
Depart amento de Ciencias de la Computación e Inteligencia Art if icial – ETSIIT – Un iversid ad de Granada
11
Descargar