Documentos de Académico
Documentos de Profesional
Documentos de Cultura
En este capítulo se presenta una de las estructuras de datos más utilizadas en programación como
son los arrays. Dentro de este tipo de estructuras de datos se verán únicamente arrays de una
dimensión (también conocidos como vectores) y arrays de dos dimensiones (también conocidos
como matrices). Se explicará cómo declarar arrays en pseudocódigo, así como la forma en la que se
puede acceder a los elementos de un vector y de una matriz. Entre las operaciones fundamentales que
se pueden realizar con estas estructuras se explicará la asignación, la lectura/escritura de datos,
el recorrido de los elementos de un array y operaciones de actualización de elementos (añadir,
insertar y eliminar). Por último, se dedicará una sección a estudiar el tipo cadena y sus principales
operaciones, tipo que ya se introdujo brevemente en el tema anterior.
4.1 Introducción
En el primer tema de la asignatura se introdujeron brevemente los tipos de dato que generalmente
se suelen utilizar en programación para representar la información en el computador, diferenciando
entre tipos de dato simples y tipos de dato estructurados o estructuras de datos. Dentro
de los tipos estructurados podíamos diferenciar en estructuras estáticas y dinámicas, tal y como se
muestra en la Figura 4.1.
Los tipos de dato simples (también conocidos como básicos o primitivos) se caracterizan
porque no están compuestos de otras estructuras de datos, siendo el tipo entero, el tipo real y el
119
entero
real
Tipos simples caracter
logico
arrays
estáticos cadenas
registros
Tipos estructurados
listas
dinámicos árboles
grafos
tipo caracter los más frecuentes y utilizados por casi todos los lenguajes. Algunos lenguajes como
Python tienen integrado también el tipo logico (booleano o bool), que es considerado también en
programación un tipo de dato simple.
Los tipos de dato estructurados o estructuras de datos se construyen generalmente a
partir de los tipos simples de dato, siendo el ejemplo más representativo el tipo cadena (string).
Por tanto, se puede decir que los tipos de dato simples se pueden organizar en diferentes estructuras
de datos que, a su vez, pueden ser estáticas o dinámicas:
Las estructuras de datos estáticas son aquellas en las que el tamaño ocupado en memoria
se define antes de que el programa se ejecute (en tiempo de compilación), y dicho tamaño
no puede modificarse durante la ejecución del programa. Este tipo de estructuras están im-
plementadas en casi todos los lenguajes de programación y las principales son los arrays y
los registros. Aunque hay autores que consideran el tipo cadena como estructura de datos
estática por ser en sí un array de caracteres, existen lenguajes como Python en los que el tipo
cadena ya está implementado de forma nativa (tipo String) y no es obligatorio establecer el
tamaño ocupado en memoria para este tipo de objetos antes de utilizarlos, ya que se compor-
tan de forma dinámica en memoria. A pesar de esto, y por cuestiones de simplicidad, en esta
asignatura se considerará el tipo cadena como otro tipo más de estructura de datos estática
aparte del tipo array y el tipo registro.
120
La elección del tipo de estructura de datos idónea a cada problema que queramos resolver
dependerá esencialmente del tipo de problema y, en menor medida, del lenguaje de programación
utilizado, ya que en aquellos en que no está implementada una estructura esta deberá ser simulada
con el algoritmo adecuado, dependiendo del propio algoritmo y de las características del lenguaje,
o de su fácil o difícil solución.
Por último, una característica importante que diferencia a los tipos de dato es la siguiente:
los tipos de dato simples tienen como característica común que cada variable representa a un
elemento, mientras que los tipos de dato estructurados tienen como característica común que un
identificador (nombre) puede representar múltiples datos individuales, pudiendo cada uno de estos
ser referenciado independientemente.
4.2 Arrays
Un array es una estructura de datos estática que representa una colección finita y ordenada de
elementos homogéneos, es decir, un conjunto ordenado de elementos del mismo tipo. Por lo
general todo array se identifica mediante un nombre (identificador) y una serie de índices que toman
valores enteros positivos comenzando normalmente por 0 y que permiten diferenciar la posición de
los distintos elementos que lo constituyen.
Existen diferentes tipos de array en función del número de dimensiones y de los elementos que
lo componen. Según el número de dimensiones podemos diferenciar entre arrays de una dimensión
(vectores), de dos dimensiones (matrices) o de más de dos dimensiones (arrays multidimensionales).
En algunos lenguajes como en C, a los arrays unidimensionales cuyos elementos son caracteres
se les conoce también como cadenas (string). En esta asignatura sólo se estudiarán los arrays
unidimensionales y bidimensionales.
Un array unidimensional se puede considerar una lista ordenada de elementos del mismo tipo.
Debido a su similitud con el concepto matemático de vector los arrays unidimensionales también
se conocen con ese nombre, es decir, como vectores. Una característica fundamental de los vectores
es que llevan asociado un único índice que designa la posición de los elementos dentro de la
lista, comenzando en 0, por lo general. En lenguajes como Python o C el primer elemento de
un array siempre tiene índice 0. Por ejemplo, la Figura 4.2 representaría gráficamente un array
unidimensional identificado con el nombre habitantes que se podría utilizar como estructura para
almacenar el número de habitantes (en unidades de millar) de 100 ciudades diferentes, donde cada
posición del array representaría una ciudad distinta.
La estructura de datos array se suele emplear normalmente en programación cuando se desea
121
Figura 4.2: Representación gráfica de un array unidimensional
almacenar un conjunto de datos que guardan cierta relación, de forma que con un único identificador
y una posición específica nos podríamos referir a cualquier dato del conjunto. Para ello los arrays
se almacenan en la memoria principal del computador en un orden adyacente de manera que, en
el ejemplo anterior, el valor numérico de la posición 1 del array habitantes (valor entero 7) estaría
almacenado en memoria en la celda siguiente a la celda donde se almacena el valor numérico de
la posición 0 del array (valor entero 30), y así sucesivamente. De este modo, cada elemento de un
vector se puede procesar como si fuese una variable simple al ocupar una posición de memoria, por
lo que para hacer referencia a cualquier elemento del array se utilizaría la siguiente sintaxis:
identificador_array [ posición ]
Por tanto, siguiendo con el ejemplo del array habitantes y teniendo en cuenta que la primera posición
del array siempre tiene índice 0, si quisiéramos asignar un nuevo valor (por ejemplo 6) a la tercera
ciudad (representada por el índice 2), se haría de la siguiente manera:
habitantes[2]← 6
variables
< id_array_1 > [ < tamaño_array_1 ] : < tipo_elementos_array_1 >
< id_array_2 > [ < tamaño_array_2 ] : < tipo_elementos_array_2 >
...
Por tanto, el rango de valores que puede tomar el índice de un array unidimensional será desde
0 hasta tamaño_array − 1. Para el ejemplo del array habitantes, su declaración en pseudocódigo
se haría tal y como se muestra en el Algoritmo 4.2.
122
variables
...
habitantes [100] : entero
...
Las operaciones típicas que se pueden realizar con arrays en programación son las siguientes:
asignación, lectura/escritura, recorrido (acceso secuencial), actualizar (insertar, eliminar), ordena-
ción y búsqueda.
habitantes[2]← 6
En ese caso estaríamos asignando el valor entero 6 a la posición de índice 2 del array habitantes
(tercer lugar del array). Si se desea asignar valores a todos los elementos de un array se debe recurrir
por lo general a estructuras repetitivas, siendo la más habitual una estructura para. Para ello, se
utilizará la variable contador establecida en la estructura repetitiva como índice para recorrer
todas las posiciones del array. Por ejemplo, si quisiéramos inicializar todos los elementos del array
habitantes a 0 se podría hacer con una estructura iterativa para tal y como muestra el Algoritmo
4.3.
...
p a r a i ← 0 h a s t a 100 h a c e r
habitantes [ i ]← 0
fin_para
...
Algoritmo 4.3: Pseudocódigo para inicializar a 0 todos los elementos del array habitantes
En el ejemplo anterior se utiliza la variable contador i de la estructura para como índice para
recorrer todas las posiciones del array habitantes. Del mismo modo, la lectura/escritura de datos
123
en arrays u operaciones de entrada/salida normalmente se realizan con estructuras repetitivas.
Las instrucciones simples de lectura/escritura en arrays se representarán en pseudocódigo con las
mismas instrucciones leer y escribir utilizadas desde el principio de la asignatura. Así, podríamos
leer desde teclado todos los elementos del vector habitantes y después mostrarlos por pantalla tal
y como se realiza en el Algoritmo 4.4.
p a r a i ← 0 h a s t a 100 h a c e r
leer ( habitantes [ i ] )
e s c r i b i r ( habitantes [ i ] )
fin_para
Algoritmo 4.4: Pseudocódigo para leer y mostrar todos los elementos del array habitantes
A la operación de efectuar una acción general sobre todos los elementos de un array (por ejemplo,
leer desde teclado todos los elementos) se le denomina recorrido del vector o acceso secuencial
al vector. Lo habitual y recomendable en programación es realizar estas operaciones utilizando
estructuras repetitivas, cuyas variables de control o contador se utilizan como índice del vector (por
ejemplo, habitantes[i]). El incremento del contador del bucle producirá el tratamiento sucesivo de
los elementos del array.
Además de la estructura para (ver Algoritmo 4.4), los elementos de un array se pueden leer
también con estructuras iterativas tipo mientras o repetir. Los Algoritmos 4.5, 4.6 y 4.7 muestran
un ejemplo de cómo se podrían leer los elementos del vector habitantes con una estructura mientras
y repetir, esta última con sus dos variantes (mientras y hasta_que), respectivamente.
i←0
m i e n t r a s ( i < 100 ) h a c e r
leer ( habitantes [ i ] )
i←i+1
fin_mientras
Algoritmo 4.5: Pseudocódigo para leer los elementos del array habitantes con estructura mientras
124
i←0
repetir
leer ( habitantes [ i ] )
i←i+1
m i e n t r a s ( i < 100 )
Algoritmo 4.6: Pseudocódigo para leer los elementos del array habitantes con estructura repetir-
mientras
i←0
repetir
leer ( habitantes [ i ] )
i←i+1
hasta_que ( i = 100 )
Algoritmo 4.7: Pseudocódigo para leer los elementos del array habitantes con estructura repetir-
hasta_que
Un ejemplo típico donde se requiere hacer un recorrido secuencial de un array es cuando nos piden
calcular la media de una lista de valores. Por ejemplo, nos piden implementar un algoritmo que
calcule la media de puntos de un total de 50 puntuaciones obtenidas tras varias pruebas. Una
posible solución se muestra en la figura del Algoritmo 4.8.
a l g o r i t m o media_puntuaciones
constantes
TOTAL = 50
variables
i : entero
puntos [TOTAL] : r e a l
suma , media : r e a l
inicio
suma ← 0
125
e s c r i b i r ( "Dame l a s p u n t u a c i o n e s " )
p a r a i ← 0 h a s t a TOTAL h a c e r
l e e r ( puntos [ i ] )
suma ← suma + puntos[i]
fin_para
media ← suma/TOTAL
e s c r i b i r ( " La media e s " , media )
fin
La operación de actualizar un array se puede referir a dos operaciones elementales que se pueden
realizar con los elementos de dicho array:
algoritmo inserta_elemento_posicion_array
constantes
TAM_MAX = 5
variables
v e c t o r [TAM_MAX] : e n t e r o
tam_logico , p o s i c i o n , elem , i , temp : e n t e r o
inicio
# i n i c i a l i z a m o s e l tamaño l ó g i c o a 0
126
tam_logico ← 0
# asignamos elementos a l a s 3 primeras p o s i c i o n e s
# d e l a r r a y y a c t u a l i z a m o s e l tamaño l ó g i c o
v e c t o r [ 0 ] ← −3
vector [ 1 ] ← 2
vector [ 2 ] ← 5
tam_logico ← tam_logico + 3
# leemos l a p o s i c i ó n y e l elemento a i n s e r t a r
e s c r i b i r ( "Dame p o s i c i ó n ( e n t r e 0 y " , T AM _M AX − 1 , " ) " )
leer ( posicion )
e s c r i b i r ( "Dame e l e m e n t o a i n s e r t a r " )
l e e r ( elem )
s i ( t a m _ l o g i c o < TAM_MAX) e n t o n c e s
p a r a i ← posicion h a s t a tam_logico + 1 h a c e r
temp ← vector[i]
vector[i] ← elem
elem ← temp
fin_para
# incrementamos e l tamaño l ó g i c o en 1
tam_logico ← tam_logico + 1
fin_si
fin
Eliminar un elemento: consiste en borrar un elemento actual del array. Al contrario que
para la inserción, el eliminar un elemento implicará un desplazamiento hacia la izquierda de
los elementos situados a la derecha del elemento eliminado para compactar el array y que
no queden huecos vacíos en el interior del mismo. Obviamente este desplazamiento no será
necesario cuando el elemento eliminado sea el de la última posición del array. El Algoritmo
4.10 muestra un ejemplo de eliminación de un elemento de una posición interior de un array.
127
algoritmo elimina_posicion_elemento_array
constantes
TAM_MAX = 5
variables
v e c t o r [TAM_MAX] : e n t e r o
tam_logico , p o s i c i o n , i : e n t e r o
inicio
# i n i c i a l i z a m o s e l tamaño l ó g i c o a 0
tam_logico ← 0
# asignamos elementos a l a s 4 primeras p o s i c i o n e s
# d e l a r r a y y a c t u a l i z a m o s e l tamaño l ó g i c o
v e c t o r [ 0 ] ← −3
vector [ 1 ] ← 2
vector [ 2 ] ← 5
vector [ 3 ] ← 9
tam_logico ← tam_logico + 4
# leemos l a p o s i c i ó n d e l elemento a e l i m i n a r
e s c r i b i r ( "Dame p o s i c i ó n ( e n t r e 0 y " , tam_logico − 1 , " ) " )
leer ( posicion )
p a r a i ← posicion h a s t a tam_logico − 1 h a c e r
vector[i] ← vector[i+1]
fin_para
# decrementamos e l tamaño l ó g i c o en 1
tam_logico ← tam_logico − 1
fin
Una cadena de caracteres (string) es una secuencia de cero o más símbolos, que incluyen letras del
alfabeto, dígitos y caracteres especiales como el espacio en blanco. Por tanto, una cadena puede
verse como un array unidimensional cuyos elementos son de tipo carácter. La longitud de una
cadena es el número de caracteres que contiene y a la cadena que no contiene ningún carácter se le
denomina cadena vacía o nula, siendo su longitud cero. La cadena vacía no se debe confundir con
128
una cadena compuesta sólo de espacios en blanco, ya que esta tendrá como longitud el número de
blancos de la misma.
Ya se introdujo brevemente el tipo cadena en el Tema 3, indicando que en pseudocódigo se
utilizará el carácter comilla doble como delimitador del valor literal de una variable cadena. Dado
que el lenguaje de programación que vamos a emplear durante las prácticas de la asignatura tiene
implementado de forma nativa el tipo de dato cadena (str en Python), en esta asignatura se
permitirá declarar variables de tipo cadena en pseudocódigo, tal y como se muestra en el Algoritmo
4.11.
variables
...
cad1 , cad2 : cadena
...
Como se puede observar en la declaración de una variable de tipo cadena, no es necesario especificar
el número de caracteres que reservamos en memoria para la cadena, aspecto que sí es necesario
especificar cuando declaramos una variable de tipo array.
Las instrucciones básicas con cadenas son la asignación y la entrada/salida (leer/escribir). Estas
se realizan de un modo similar al tratamiento de dichas instrucciones con datos numéricos, y ya
se han explicado en temas anteriores. No obstante, existen otra serie de operaciones usuales con
cadenas que se describen a continuación:
4 + 5 + len(“prueba”) = 4 + 5 + 6 = 15
129
numérico del código o juego de caracteres que admite la computadora o el propio lenguaje
de programación. En esta asignatura utilizaremos el código ASCII como código numérico de
referencia. Así, el carácter ’A’ (código ASCII 65) será menor alfabéticamente que el carácter
’C’ (código ASCII 67). En la comparación de cadenas se pueden considerar dos operaciones
elementales:
• Desigualdad. Los criterios para comprobar la desigualdad entre dos cadenas son utilizados
por los operadores de relación <, <=, >=, >, !=, y se ajustan a una comparación
sucesiva de caracteres correspondientes en ambas cadenas hasta comparar dos caracteres
diferentes. A partir de ese momento se resuelve la comparación según los valores ASCII
de los dos caracteres diferentes en la misma posición de ambas cadenas y no es preciso
continuar. Además, las cadenas no tienen por qué tener la misma longitud para poder
ser comparadas.
Subcadena. Esta operación permite la extracción de una parte específica de una cadena, es
decir, una subcadena. La operación subcadena se representa en pseudocódigo con la siguiente
sintaxis:
donde cad es la cadena de la que debe extraerse la subcadena e inicio es un valor de tipo entero
que corresponde a la posición inicial de la subcadena. Recordemos que la posición (índice)
del primer carácter de cualquier cadena (al considerarse similar a un array) es siempre 0.
Por último, fin es un valor de tipo entero que se corresponde con la posición (índice) final
hasta la cual se extrae la subcadena (sin contar el carácter de esa posición). Por ejemplo, la
instrucción subcadena (“abcdef”, 1, 4) devolvería como resultado la cadena “bcd”.
Buscar. Una operación frecuente con cadenas es localizar si una determinada cadena forma
parte de otra cadena más grande o buscar la posición en que aparece un determinado carácter
o secuencia de caracteres en una cadena. Esta función suele ser interna en algunos lenguajes
y se define en pseudocódigo como find (encontrar en inglés), con la siguiente sintaxis:
130
find (cad, subcad)
Una operación habitual con las cadenas es recorrerlas carácter a carácter para hacer cualquier
tipo de procesamiento con ellas. Al igual que se ha explicado para los arrays unidimensionales y
dado que una cadena se puede considerar un array unidimensional cuando se necesite procesarla,
lo recomendable en programación es realizar este procesamiento utilizando estructuras repetitivas,
cuyas variables de control o contador se utilizan como índice para recorrer todas las posiciones
(caracteres) de la cadena. Como ejemplo, el Algoritmo 4.12 muestra por pantalla las veces que
aparece un carácter elegido por el usuario en una cadena leída por teclado.
algoritmo cuenta_caracter_en_cadena
variables
i , total : entero
cad : cadena
car : caracter
inicio
total ← 0
e s c r i b i r ( "Dame l a cadena " )
l e e r ( cad )
e s c r i b i r ( "Dame e l c a r á c t e r a b u s c a r " )
l e e r ( car )
# p r o c e s a m o s c a r á c t e r a c a r á c t e r l a cadena
p a r a i ← 0 h a s t a len(cad) h a c e r
s i ( cad [ i ] = c a r ) e n t o n c e s
total ← total + 1
fin_si
fin_para
131
e s c r i b i r ( " El c a r á c t e r " , c a r , " a p a r e c e " , t o t a l , " v e c e s " )
fin
Algoritmo 4.12: Pseudocódigo del algoritmo que calcula las veces que aparece un carácter en una
cadena
132
Figura 4.3: Representación gráfica de un array bidimensional
Figura 4.4: Ejemplo de representación del censo de habitantes de 100 ciudades en las 3 últimas
décadas
variables
< id_matriz_1 > [ < f i l a s _ 1 ] [ < columnas_1 > ] : < tipo_elementos_matriz_1 >
< id_matriz_2 > [ < f i l a s _ 2 ] [ < columnas_2 > ] : < tipo_elementos_matriz_2 >
133
Por ejemplo, en el extracto del Algoritmo 4.14 se declaran en pseudocódigo dos matrices m1 y
m2 de dimensiones 4x5 y 3x3, siendo los elementos de m1 de tipo entero y los de m2 de tipo real.
variables
m1 [ 4 ] [ 5 ] : entero
m2 [ 3 ] [ 3 ] : real
Al igual que cuando tratamos con arrays unidimensionales, una de las operaciones más frecuentes
con matrices es efectuar una acción general sobre todos los elementos de la matriz (leer cada
elemento, mostrarlo por pantalla, realizar un cálculo con cada elemento de la matriz, etc.), es decir,
procesar todos los elementos de la matriz. A esta operación se le conoce como recorrido de la matriz
o acceso secuencial a la matriz.
Como se puede intuir, este tipo de operaciones se realizan utilizando estructuras repetitivas,
cuyas variables de control o contadores se utilizan para representar los dos índices de la matriz. En
este caso se necesitará un contador que represente el incremento sucesivo de las filas de la matriz
y otro que represente el incremento sucesivo de las columnas. Así, por ejemplo, la lectura de todos
los elementos de la matriz habitantes se podría realizar con dos estructuras para anidadas, tal y
como se muestra en el extracto del Algoritmo 4.15.
p a r a i ← 0 h a s t a 100 h a c e r
para j ← 0 hasta 3 hacer
leer ( habitantes [ i ] [ j ] )
fin_para
fin_para
Algoritmo 4.15: Ejemplo de recorrido por filas de la matriz habitantes para leer sus elementos
Mientras que un array unidimensional sólo admite un tipo de recorrido, en un array bidimen-
sional se puede realizar un recorrido por filas o un recorrido por columnas. En el ejemplo mostrado
en el Algoritmo 4.15 se realiza una lectura de los valores de la matriz habitantes por filas (recorrido
por filas). Para realizar una lectura de los datos por columnas (recorrido por columnas) bastaría
134
con cambiar el orden de los bucles para, de manera que el bucle más interno sería el que recorrería
las filas, y el bucle más externo recorrería las columnas, tal y como se muestra en el Algoritmo 4.16.
Algoritmo 4.16: Ejemplo de recorrido por columnas de la matriz habitantes para leer sus elementos
A continuación se muestra un ejemplo típico de recorrido de una matriz. Supongamos que tene-
mos una matriz llamada notas de dimensión 40 x 10, es decir formada por 40 filas que representan
los 40 alumnos de los que queremos almacenar sus notas y 10 columnas que representan las 10
pruebas o exámenes realizados. Imaginemos que ya hemos introducido todos los valores en la ma-
triz de notas y queremos calcular la nota media de cada alumno. En ese caso se tendría que realizar
un recorrido de la matriz por filas, sumando todas las notas de cada fila y hallando su media, y así
sucesivamente con el resto de filas. El extracto del Algoritmo 4.17 muestra una posible solución al
problema planteado.
p a r a i ← 0 h a s t a 40 h a c e r
media ← 0
p a r a j ← 0 h a s t a 10 h a c e r
media ← media + notas[i][j]
fin_para
media ← media/10
e s c r i b i r ( " La media d e l alumno " , i +1 , " e s " , media )
fin_para
Observe cómo se ha utilizado la misma variable media para hacer la función de acumulador
(suma de las notas individuales) y para calcular la propia media (se podría haber utilizado otra
variable adicional suma para hacer esa función, pero no es necesario). También es importante
135
señalar el momento en el que se calcula la nota media de cada alumno: justo cuando termina de
iterar completamente el bucle más interno de la estructura repetitiva anidada, que es cuando se
ha calculado la suma de todas las notas. Otro aspecto fundamental es la inicialización a 0 de la
variable media antes de comenzar con las sumas de un nuevo alumno ya que, si no se hiciera esta
inicialización, las sumas acarrearían la media calculada del anterior alumno.
Por el contrario, si lo que se desea es calcular la nota media de cada asignatura habría que
realizar un recorrido de la matriz por columnas, sumando todos los elementos de cada columna y
hallando la media, y así sucesivamente con todas las columnas. En este caso, el bucle más externo
deberá ser el de las columnas, tal y como se muestra en el extracto del Algoritmo 4.18.
...
p a r a j ← 0 h a s t a 10 h a c e r
media ← 0
p a r a i ← 0 h a s t a 40 h a c e r
media ← media + notas[i][j]
fin_para
media ← media/40
e s c r i b i r ( " La media de l a a s i g n a t u r a " , j +1 , " e s " , media )
fin_para
...
136