06.05.2013 Views

CONTENIDO DE LA LECCIÓN 18

CONTENIDO DE LA LECCIÓN 18

CONTENIDO DE LA LECCIÓN 18

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

MIGUEL Á. TOLEDO MARTÍNEZ<br />

<strong>CONTENIDO</strong> <strong>DE</strong> <strong>LA</strong> <strong>LECCIÓN</strong> <strong>18</strong><br />

ALMACENAMIENTO <strong>DE</strong> DATOS EN ARREGLOS<br />

1. Introducción 3<br />

2. Estructura de un arreglo 3<br />

2.1. Elementos del arreglo 5<br />

2.2. Índice del arreglo 5<br />

3. Examen breve 34 76<br />

4. Definición de arreglos unidimensionales en C++ 5<br />

4.1. Formato para un arreglo unidimensional 5<br />

4.2. Ejemplo <strong>18</strong>.1 6<br />

5. Examen breve 35 76<br />

6. El acceso a los arreglos 6<br />

6.1. Inserción de elementos en los arreglos unidimensionales 6<br />

6.1.1. Asignación directa 6<br />

6.1.1.1. Formato de asignación directa (inserción de elementos en un arreglo) 6<br />

6.1.2. Sugerencia de depuración 7<br />

6.1.3. Lectura de los elementos del arreglo 7<br />

6.1.4. Inserción de elementos del arreglo con el uso de ciclos 8<br />

6.1.4.1. Inserción dentro de un arreglo unidimensional con el uso de un ciclo for 8<br />

7. Extracción de elementos de los arreglos unidimensionales 9<br />

7.1. Asignación directa 9<br />

7.1.1. Formato de asignación directa (extracción de elementos del arreglo) 9<br />

7.1.2. Escritura de elementos del arreglo 10<br />

7.1.3. Extracción de elementos del arreglo con el uso de ciclos 10<br />

7.1.4. Sugerencia de depuración 11<br />

8. Examen breve 36 76<br />

9. Ejemplos <strong>18</strong>.2, <strong>18</strong>.3, <strong>18</strong>.4, <strong>18</strong>.5, <strong>18</strong>.6, <strong>18</strong>.7, <strong>18</strong>.8, <strong>18</strong>.9, <strong>18</strong>.10, <strong>18</strong>.11, <strong>18</strong>.12, <strong>18</strong>.13, <strong>18</strong>.14,<br />

<strong>18</strong>.15, <strong>18</strong>.16, <strong>18</strong>.17. 12<br />

10. Paso de arreglos y elementos de arreglos a las funciones 21<br />

10.1. Ejemplos <strong>18</strong>.<strong>18</strong>, <strong>18</strong>.19, <strong>18</strong>.20, <strong>18</strong>.21, <strong>18</strong>.22, <strong>18</strong>.23, <strong>18</strong>.24, <strong>18</strong>.25 21<br />

11. Examen breve 37 76<br />

12. Ordenamiento de arreglos 31<br />

12.1. Ejemplos <strong>18</strong>.26, <strong>18</strong>.27, <strong>18</strong>.28, <strong>18</strong>.29, <strong>18</strong>.30, <strong>18</strong>.31, <strong>18</strong>.32 32<br />

13. Búsqueda en arreglos: Búsqueda lineal y búsqueda binaria 40<br />

13.1. Ejemplos <strong>18</strong>.33, <strong>18</strong>.34, <strong>18</strong>.35 40<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-1


MIGUEL Á. TOLEDO MARTÍNEZ<br />

14. Solución de problemas en acción: Búsqueda en un arreglo con iteración<br />

(búsqueda secuencial) 45<br />

14.1. Problema 45<br />

14.2. Definición del problema 45<br />

14.3. Planeación de la solución 46<br />

14.4. Codificación del programa 46<br />

15. Solución de problemas en acción: Como ordenar un arreglo con iteración<br />

(ordenación por inserción) 47<br />

15.1. Problema 47<br />

15.2. Definición del problema 47<br />

15.3. Planeación de la solución 48<br />

15.4. Codificación del problema 50<br />

16. Solución de problemas en acción: Búsqueda en un arreglo con recursión<br />

(búsqueda binaria) 51<br />

16.1. Problema 51<br />

16.2. Definición del problema 51<br />

16.3. Planeación de la solución 52<br />

16.4. Codificación del problema 55<br />

17. Ejemplos <strong>18</strong>.36, <strong>18</strong>.37 56<br />

<strong>18</strong>. Iniciación de arreglos 61<br />

<strong>18</strong>.1. Iniciación predeterminada de arreglos globales y estáticos 63<br />

19. Examen breve 38 77<br />

20. Arreglos que rebasan los 64 kbytes de memoria 65<br />

20.1. Ejemplos <strong>18</strong>.38 y <strong>18</strong>.39 65<br />

21. Lo que necesita saber 66<br />

22. Preguntas y problemas 68<br />

22.1. Preguntas 68<br />

22.2. Problemas 70<br />

22.3. Problemas de recursividad 75<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-2


MIGUEL Á. TOLEDO MARTÍNEZ<br />

<strong>LECCIÓN</strong> <strong>18</strong><br />

ALMACENAMIENTO <strong>DE</strong> DATOS EN ARREGLOS<br />

INTRODUCCIÓN<br />

Esta lección tratará un tema muy importante en cualquier lenguaje de programación: los<br />

arreglos. No es posible enfatizar sobremanera la importancia de los arreglos, pues ellos mismos<br />

dan origen a muchas aplicaciones.<br />

En muchas ocasiones, sus programas requerirán almacenar varios valores, tales como 50<br />

calificaciones, 10 títulos de libros, 1000 nombres de archivos, etc. Cuando sus programas<br />

necesitan almacenar varios valores, entonces define un arreglo, especificando su clase de datos,<br />

nombre y número de elementos que el arreglo almacenará.<br />

Un arreglo es una estructura de datos indexados que se utiliza para almacenar elementos de datos<br />

de la misma clase.<br />

Los arreglos simplemente proporcionan un medio organizado para localizar y almacenar<br />

datos, así como el apartado postal en el correo de su oficina postal local proporciona un medio<br />

organizado de localizar y clasificar el correo. Por esto a un arreglo se le conoce como una<br />

estructura de datos que se usa para almacenar cualquier clase de datos, incluyendo enteros,<br />

flotantes, caracteres, arreglos, apuntadores, y registros (structs) Además, los arreglos son tan<br />

versátiles que se pueden usar para implementar otras estructuras de datos, como pilas, colas,<br />

listas ligadas y árboles binarios, de hecho en algunos lenguajes corno FORTRAN, el arreglo es la<br />

única estructura de datos disponible para el programador, porque, por medio del uso de arreglos<br />

es posible implementar la mayor parte de otras estructuras.<br />

Los objetivos de esta lección son:<br />

• Presentar la estructura de datos de arreglo.<br />

• Declarar un arreglo dentro de su programa.<br />

• Comprender cómo se declaran e inicializan los arreglos y de qué manera se hace referencia a<br />

los elementos de un arreglo.<br />

• Aprender a pasar los arreglos a las funciones<br />

• Aprender a utilizar los arreglos para almacenar, ordenar y hacer búsquedas en listas y tablas<br />

de valores.<br />

• Discernir las técnicas básicas para el ordenamiento.<br />

ESTRUCTURA <strong>DE</strong> UN ARREGLO<br />

Un arreglo es una estructura de datos. En otras palabras, un arreglo consta de elementos<br />

de datos organizados o estructurados en una forma particular. Esta estructura de datos<br />

proporciona un medio conveniente para almacenar grandes cantidades de datos en la memoria<br />

primaria o del usuario. Existen arreglos unidimensionales o listas y multidimensionales.<br />

En esta lección revisaremos los arreglos unidimensionales; en la lección 19<br />

estudiaremos los arreglos multidimensionales.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-3


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Para obtener la idea de un arreglo, observe la ilustración de la figura <strong>18</strong>.1. En esta figura<br />

se puede ver una sola línea de cajas de apartados postales como se encuentran en cualquier<br />

oficina de correos. Como se sabe, cada caja tiene un número de apartado postal (A. P.) En la<br />

figura <strong>18</strong>.1, los números del A. P. empiezan con cero y van hasta un número finito n. ¿Cómo se<br />

localiza una determinada caja? Por medio del número de apartado postal, ¿correcto? Sin<br />

embargo, el número del A. P. no tiene nada que ver con lo que contiene la caja. Simplemente se<br />

usa para localizar una caja determinada. Desde luego, el contenido es la correspondencia enviada<br />

a esta caja. La razón por la que el servicio postal usa el método de apartado postal es que<br />

proporciona un método conveniente y bien organizado para almacenar y tener acceso a la<br />

correspondencia de sus clientes. Un arreglo hace lo mismo en un programa de computadora;<br />

proporciona un método conveniente y bien organizado para almacenar y tener acceso a los datos<br />

para usted, el programador. De modo que, ¿cuántos apartados postales hay en la figura <strong>18</strong>.1?<br />

Debido a que el primer número del apartado es 0 y el último es n, habrá n + 1 apartados.<br />

APARTADO<br />

POSTAL 0<br />

Figura <strong>18</strong>.1.Un arreglo unidimensional o lista es como una fila de buzones de apartados en la<br />

oficina de correos.<br />

Imagine que un arreglo unidimensional, como el que se muestra en la figura <strong>18</strong>.2, es<br />

similar a una línea de cajas de apartados postales. El arreglo unidimensional consiste en una sola<br />

fila de lugares de almacenamiento, cada una etiquetada con un número que se conoce con el<br />

nombre de índice. Cada localización del índice se utiliza para almacenar una clase de datos<br />

determinada. Los datos almacenados en una localización de índice determinada se conoce como<br />

elemento del arreglo. De esta manera, un arreglo unidimensional es una lista secuencial de<br />

lugares de almacenamiento que contiene elementos de datos individuales que se localizan o<br />

accedan por medio de índices.<br />

Elemento<br />

0<br />

APARTADO<br />

POSTAL 1<br />

Elemento<br />

1<br />

APARTADO<br />

POSTAL 2<br />

Elemento<br />

2<br />

APARTADO<br />

POSTAL 3<br />

Elemento<br />

3<br />

[0] [1] [2] [3] [n]<br />

ÍNDICES<br />

Figura <strong>18</strong>.2 Un arreglo unidimensional, también llamado lista, es una lista secuencial de<br />

localizaciones de almacenamiento que contiene los elementos de datos que se<br />

localizan por medio de los índices.<br />

Los dos componentes principales de un arreglo son los elementos almacenados en el<br />

arreglo y los índices que localizan los elementos almacenados. ¡No se confunda con estos dos<br />

componentes del arreglo! Aunque los elementos del arreglo y los índices se relacionan, son<br />

cantidades completamente separadas, al igual que el contenido de una caja de apartado postal es<br />

diferente de su número de apartado. Con esto presente, vamos a explorar los elementos e índices<br />

del arreglo un poco más a fondo.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-4<br />

...<br />

...<br />

APARTADO<br />

POSTAL n<br />

Elemento<br />

n


MIGUEL Á. TOLEDO MARTÍNEZ<br />

ELEMENTOS <strong>DE</strong>L ARREGLO<br />

Los elementos de un arreglo son los datos almacenados en éste y pueden ser de<br />

cualquier clase de datos que se hayan visto. De esta manera, un arreglo dado puede almacenar<br />

elementos enteros, elementos de punto flotante, caracteres, y elementos booleanos. Además,<br />

de estos elementos de clase de datos estándar, un arreglo también es útil para almacenar<br />

elementos de datos enumerados. De hecho, aun los elementos de un arreglo pueden ser otros<br />

arreglos. Sin embargo, existe una restricción importante que se aplica a los elementos del<br />

arreglo: todos los elementos de un arreglo determinado deberán ser de la misma clase de datos.<br />

Como se verá en breve, es necesario definir los arreglos en un programa C++. Parte de la<br />

definición es especificar la clase de los elementos que el arreglo almacenará. Una vez que se ha<br />

definido un arreglo determinado para cierta clase de datos, sólo los elementos de esa clase de<br />

datos se almacenarán en ese arreglo.<br />

ÍNDICES <strong>DE</strong>L ARREGLO<br />

Los índices del arreglo localizan a los elementos del arreglo, en C++, el compilador en<br />

forma automática asigna índices enteros a la lista de elementos del arreglo empezando con el<br />

índice 0. Por lo tanto, el primer elemento del arreglo en la figura <strong>18</strong>.2 se localiza en el índice 0,<br />

y el último elemento se localiza en el índice n. Los índices empiezan con 0 y van a n, por tanto<br />

habrá n + 1 elementos en el arreglo. También, debido a que es un arreglo unidimensional, o<br />

lista, decimos que tiene una dimensión de 1 ×××× (n + 1) lo cual significa que hay un renglón de n +<br />

1 elementos. La dimensión de un arreglo indica el tamaño del arreglo, justo como la dimensión<br />

de una pieza de madera indica su tamaño.<br />

<strong>DE</strong>FINICIÓN <strong>DE</strong> ARREGLOS UNIDIMENSIONALES EN C++<br />

cosas:<br />

En C++ todos los arreglos deberán estar definidos. Para definir un arreglo, especifique 3<br />

1. La clase de datos de los elementos del arreglo.<br />

2. El nombre del arreglo.<br />

3. El tamaño del arreglo.<br />

El formato general es como sigue:<br />

EXAMEN BREVE 34<br />

FORMATO PARA UN ARREGLO UNIDIMENSIONAL<br />

[];<br />

Lo primero que se ve en la definición es la clase de datos de los elementos del arreglo.<br />

La clase de datos del arreglo es seguida por el identificador del arreglo, su nombre, el cual es<br />

seguido por el número de elementos que almacena el arreglo dentro de los corchetes, [] La<br />

definición termina con un punto y coma. Por ejemplo, la siguiente es una definición de un<br />

arreglo de 10 caracteres cuyo nombre es caracteres.<br />

char caracteres [10];<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-5


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.1<br />

Escriba las definiciones para los siguientes arreglos:<br />

a. Un arreglo llamado enteros que almacenará 10 enteros.<br />

b. Un arreglo llamado reales que almacenará 5 valores de punto flotante.<br />

c. Un arreglo llamado caracteres que almacenará 11 caracteres.<br />

d. Un arreglo llamado clase que almacenará calificaciones de 25 estudiantes. Suponga que las<br />

calificaciones A, B, C, D y R se definen en una clase de datos enumerados denominada calificaciones.<br />

¿Qué índice localiza el último elemento en cada uno de los arreglos anteriores?<br />

a. int enteros[10];<br />

b. float reales[5];<br />

c. char caracteres[11];<br />

d. enum calificaciones {R, D, C, B, A};<br />

e. calificaciones clase[25];<br />

Solución<br />

El índice que localiza el último elemento en cada uno de los arreglos anteriores es uno<br />

menos que el tamaño definido del arreglo.<br />

En cada una de las definiciones anteriores se menciona primero la clase de datos del elemento, seguida por<br />

el identificador del arreglo, después el tamaño del arreglo encerrado en corchetes. Cada una de las<br />

definiciones es muy obvia, excepto quizá la definición del arreglo clase. En esta definición, la clase de<br />

datos del arreglo es la clase de datos enumerada llamada calificaciones, que deberá anunciarse antes de la<br />

definición del arreglo. Por tanto, diremos que el arreglo clase puede almacenar elementos cuya clase de<br />

datos sean calificaciones. De esta manera, los elementos que se pueden almacenar en el arreglo clase se<br />

limitan a los elementos de la clase de datos enumerados de R, D, C, B y A. Observe que el compilador no<br />

los considera como caracteres, sino como elementos de una clase de datos enumerados llamada<br />

calificaciones.<br />

EL ACCESO A LOS ARREGLOS<br />

Tener acceso al arreglo significa insertar elementos dentro del arreglo para almacenar u<br />

obtener elementos almacenados desde el arreglo.<br />

INSERCIÓN <strong>DE</strong> ELEMENTOS EN LOS ARREGLOS UNIDIMENSIONALES<br />

Hay básicamente 3 formas principales de insertar elementos dentro de un arreglo:<br />

mediante un enunciado de asignación directa, mediante lectura o usando ciclos.<br />

ASIGNACIÓN DIRECTA<br />

EXAMEN BREVE 35<br />

El formato general para insertar un elemento, dentro un arreglo, con asignación directa<br />

es como sigue:<br />

FORMATO <strong>DE</strong> ASIGNACIÓN DIRECTA (INSERCIÓN <strong>DE</strong> ELEMENTOS EN UN ARREGLO)<br />

[índice del arreglo] = valor del elemento;<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-6


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Con las siguientes definiciones de arreglos:<br />

char caracteres[6];<br />

int enteros[3];<br />

las asignaciones directas pueden ser como estas:<br />

caracteres [0] ='H';<br />

caracteres [5] ='\0';<br />

enteros [0] = 16;<br />

enteros [2] = -22;<br />

En cada uno de estos ejemplos se coloca un elemento en la primera y en la última<br />

posición de almacenamiento del arreglo respectivamente. El carácter 'H' se coloca en la primera<br />

posición del arreglo caracteres y el terminador nulo se coloca en la última posición de este<br />

arreglo. Recuerde que la primera posición de este arreglo es siempre [0] y la última posición del<br />

arreglo es siempre uno menos que el tamaño del arreglo. El entero 16 se coloca en la primera<br />

posición del arreglo enteros y el entero -22 se coloca en la última posición de este arreglo.<br />

Observe que se menciona el nombre respectivo del arreglo, seguido por el índice del<br />

arreglo dentro de corchetes. Entonces se usa un operador de asignación (=) seguido por el<br />

elemento que se va a insertar. La clase de datos del elemento que se inserta deberá ser la misma<br />

que aquella definida para los elementos del arreglo; de otra manera, se obtendrán resultados<br />

impredecibles cuando se trabaje con los elementos del arreglo.<br />

SUGERENCIA <strong>DE</strong> <strong>DE</strong>PURACIÓN<br />

Recuerde que los índices de un arreglo en C++ son valores enteros. Esto significa que cualquier índice<br />

especificado se convierte en su equivalente entero. Por ejemplo, es posible especificar un índice como un carácter<br />

como este: arreglo['A’]; sin embargo, C++ trata esto como arreglo[65], porque, desde el código ASCII, el<br />

equivalente entero del carácter ‘A’ es 65. De la misma manera, se puede especificar un índice usando un valor de<br />

punto flotante, como este: arreglo[1.414], sin embargo, C++ lo ve como arreglo[1], porque la parte entera de<br />

1.414 es 1. Los elementos de datos enumerados también se pueden usar como índices, porque el compilador iguala<br />

los elementos enumerados a enteros, de acuerdo con el orden listado en el enunciado de la clase de datos<br />

enumerados. Para evitar confusión y problemas potenciales, se sugiere utilizar siempre valores enteros en los<br />

índices, a menos que la aplicación específicamente indique otra cosa.<br />

LECTURA <strong>DE</strong> LOS ELEMENTOS <strong>DE</strong>L ARREGLO<br />

También es posible usar cualquiera de las funciones u objetos de entrada de C o C++ para<br />

insertar los elementos del arreglo desde un teclado, como sigue:<br />

cin > caracteres[1];<br />

cin > enteros[0];<br />

En este caso, el usuario deberá escribir el valor del elemento del arreglo respectivo desde<br />

el teclado y oprimir la tecla ENTER para ejecutar cada enunciado. Deberá escribir un carácter<br />

para el primer enunciado cin y un entero para el segundo cin. (¿Por qué?) El carácter escrito<br />

desde el teclado se almacenará en la segunda posición (índice[1]) del arreglo caracteres,<br />

mientras que el entero escrito desde el teclado se almacenará en la primera posición (índice[0])<br />

del arreglo enteros.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-7


MIGUEL Á. TOLEDO MARTÍNEZ<br />

INSERCIÓN ELEMENTOS <strong>DE</strong> ARREGLOS CON EL USO <strong>DE</strong> CICLOS<br />

La desventaja obvia al usar asignaciones directas para insertar elementos de arreglos es<br />

que se requiere un enunciado de asignación separado para llenar cada posición del arreglo. Puede<br />

automatizar el proceso de inserción usando una estructura de ciclo. Aunque cualquiera de las tres<br />

estructuras de ciclo (while, do/while, for) se puede emplear, la estructura for es la más común. A<br />

continuación está el formato general para el uso de un ciclo for:<br />

INSERCIÓN <strong>DE</strong>NTRO <strong>DE</strong> UN ARREGLO UNIDIMENSIONAL CON EL USO <strong>DE</strong> UN CICLO for<br />

Considere el siguiente programa:<br />

for(int indice = 0; indice < tamaño del arreglo; ++indice)<br />

<br />

//LLENADO <strong>DE</strong> UN ARREGLO CON UN CICLO for<br />

#include // Para cin y cout<br />

// <strong>DE</strong>C<strong>LA</strong>RA EL TAMAÑO <strong>DE</strong>L ARREGLO<br />

const int MAX = 10;<br />

void main(void)<br />

{<br />

int muestra[MAX]; // <strong>DE</strong>FINE UN ARREGLO ENTERO<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

del arreglo muestra[MAX – 1] Cuando el contador de ciclo se incremento al valor MAX al final<br />

de la última iteración de ciclo, éste se rompe y no se insertan más elementos dentro del arreglo.<br />

¡Eso es todo! ¡El arreglo está lleno!<br />

También puede usar ciclos para asignar valores a los elementos del arreglo. Por ejemplo,<br />

usando las definiciones anteriores, considere este ciclo:<br />

for (int i = 0; i < MAX; ++i)<br />

muestra[i] = 2 * i;<br />

Esta vez, los elementos del arreglo se asignan dos veces al valor del contador de ciclo con<br />

cada iteración de ciclo. ¿Qué valores se insertan realmente dentro del arreglo? ¿Qué pasa<br />

con los 10 enteros pares de 0 a <strong>18</strong>?<br />

EXTRACCIÓN <strong>DE</strong> ELEMENTOS <strong>DE</strong> LOS ARREGLOS UNIDIMENSIONALES<br />

Primero, se le advierte que la palabra extraer no es un buen término aquí. ¿Por qué?<br />

Porque, en general, la palabra extraer significa eliminar algo, cuando extraemos un elemento de<br />

un arreglo, ¡realmente no lo eliminamos! Simplemente copiamos su valor. El elemento<br />

permanece almacenado en el arreglo hasta que se reemplaza por otro valor usando una operación<br />

de inserción. Como con la inserción, es posible extraer elementos del arreglo usando uno de los<br />

tres métodos generales: asignación directa, escritura o ciclo.<br />

ASIGNACIÓN DIRECTA<br />

La extracción de los elementos del arreglo usando enunciados de asignación es lo<br />

inverso de la inserción de elementos utilizando un enunciado de asignación. Éste es el formato<br />

general:<br />

FORMATO <strong>DE</strong> ASIGNACIÓN DIRECTA (EXTRACCIÓN <strong>DE</strong> ELEMENTOS <strong>DE</strong>L ARREGLO)<br />

= [índice del arreglo]<br />

Como ejemplo, suponga que se hacen las siguientes definiciones:<br />

const int MAX = 10;<br />

int muestra[MAX];<br />

int x;<br />

Como puede observar, el arreglo muestra[] consta de 10 elementos enteros. Ahora,<br />

suponga que el arreglo está lleno, ¿Qué harán los siguientes enunciados?<br />

x = muestra[0];<br />

x = muestra[MAX - 1];<br />

x = muestra[3] * muestra[5];<br />

x = 2 * muestra[2] -3 * muestra[7];<br />

El primer enunciado asigna el elemento almacenado en la primera posición del arreglo a<br />

la variable x. El segundo enunciado asigna el elemento almacenado en la última posición del<br />

arreglo a la variable x. El tercer enunciado asigna el producto de los elementos localizados en los<br />

índices [3] y [5] a x. Por último, el cuarto enunciado asigna a x dos veces el elemento localizado<br />

en el índice[2] menos tres veces el elemento localizado en el índice [7] Los últimos dos<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-9


MIGUEL Á. TOLEDO MARTÍNEZ<br />

enunciados muestran cómo se pueden realizar las operaciones aritméticas con los elementos del<br />

arreglo.<br />

En todos los casos anteriores, los valores de los elementos del arreglo no se afectan por<br />

las operaciones de asignación. El principal requerimiento es que x debe estar definida como la<br />

misma clase de datos de los elementos del arreglo para no obtener resultados inesperados.<br />

Como ejemplo final, considere estos enunciados de asignación:<br />

muestra[0] = muestra[MAX - 1];<br />

muestra[1] = Muestra[2] + Muestra[3];<br />

¿Puede usted determinar qué pasa aquí? En el primer enunciado, el primer elemento<br />

del arreglo se reemplaza por medio del último elemento del arreglo, ¿se afecta el último<br />

elemento del arreglo? No, porque aparece del lado derecho del operador de asignación. En el<br />

segundo caso, el segundo elemento del arreglo en el índice [1] se reemplaza por la suma del<br />

tercero y cuarto elementos del arreglo en los índices [2] y [3] De nuevo, el tercero y cuarto<br />

elementos del arreglo no se afectan por esta operación, porque aparecen del lado derecho del<br />

operador de asignación.<br />

ESCRITURA <strong>DE</strong> ELEMENTOS <strong>DE</strong>L ARREGLO<br />

Los objetos cout se usan para mostrar los elementos del arreglo. Usemos el mismo<br />

arreglo para demostrar cómo escribir elementos del arreglo. Aquí está de nuevo la definición del<br />

arreglo:<br />

const int MAX = 10;<br />

int muestra[MAX];<br />

¿Qué se supone que harán los siguientes enunciados?<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

// MUESTRA UN ARREGLO CON UN CICLO for<br />

#include // Para cin y cout<br />

// ENUNCIA EL TAMAÑO <strong>DE</strong>L ARREGLO<br />

const int MAX = 10;<br />

void main(void)<br />

{<br />

int muestra[MAX]; // <strong>DE</strong>FINE UN ARREGLO ENTERO<br />

for(int i = 0; i < MAX; ++i)<br />

muestra[i] = i * i;<br />

for (int i = 0; i < MAX; ++i)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

A continuación se darán varios ejemplos en los que se utilicen los conocimientos antes<br />

adquiridos.<br />

Ejemplo <strong>18</strong>.2<br />

El siguiente programa, INICIALIZA.CPP, utiliza una estructura de repetición for para inicializar a cero los<br />

elementos de un arreglo de enteros llamado arreglo de diez elementos; luego imprime dicho arreglo en<br />

formato de tabla.<br />

/* El siguiente programa: INICIALIZA.CPP, inicializa a ceros a un arreglo de 10 elementos,<br />

posteriormente imprime el contenido de dicho arreglo.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.3<br />

}//Fin de main()<br />

int i, arreglo[10];<br />

for(i = 0; i < 10; i++)<br />

arreglo[i] = 0; //Inicializa el arreglo<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

que explícitamente inicializa a cero el primer elemento e implícitamente inicializa a cero a los otros nueve<br />

elementos, pues hay menos valores que elementos en el arreglo. Recuerde que los arreglos automáticos no<br />

se inicializan implícitamente a cero. El programador debe inicializar a cero cuando menos el primer<br />

elemento para que los demás se inicialicen a cero de manera automática.<br />

La siguiente declaración de arreglo:<br />

int arreglo[5] = {32, 27, 64, <strong>18</strong>, 95, 14};<br />

provocaría un error de sintaxis, pues hay 6 inicializadores y únicamente 5 elementos en el arreglo.<br />

Si se omite el tamaño del arreglo en la declaración por medio de una lista de inicio, el numero de elementos<br />

del arreglo será el número de elementos de dicha lista. Por ejemplo:<br />

Ejemplo <strong>18</strong>.4<br />

creará un arreglo de cinco elementos.<br />

int arreglo[] = {1, 2, 3, 4, 5};<br />

El siguiente programa, ELEMENTS.CPP, inicializa el arreglo llamado calificaciones y luego visualiza sus<br />

elementos.<br />

/* El siguiente programa: ELEMENTS.CPP, inicializa el arreglo calificaciones y<br />

luego visualiza sus elementos.<br />

*/<br />

#include //Para cout y cin<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.5<br />

int calificaciones[5] = {80, 70, 90, 85, 80};<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.6<br />

Ejemplo <strong>18</strong>.7<br />

int calificaciones[5] = {80, 70, 90, 85, 80};<br />

int i;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.8<br />

El siguiente programa, PARES.CPP, inicializa los elementos de un arreglo llamado arreglo de diez<br />

elementos a los enteros 2, 4, 6, ... , 20, e imprime el arreglo en formato de tabla. Estos números se generan<br />

multiplicando por 2 cada valor consecutivo del contador del ciclo y sumándole 2.<br />

/* Este programa: PARES.CPP inicializa un arreglo con los enteros pares comprendidos<br />

entre 2 y 20 inclusive.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.9<br />

const int TAMANO_ARREGLO = 10;<br />

int j, arreglo[TAMANO_ARREGLO];<br />

for(j = 0; j < TAMANO_ARREGLO;j++) //Inicializa arreglo<br />

arreglo[j] = 2 + 2 * j;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.10<br />

El siguiente programa, SUMAVALORES.CPP, suma los valores contenidos en el arreglo de enteros de<br />

doce elementos.<br />

/* El siguiente programa: SUMAVALORES.CPP, Calcula la suma de los elementos de un arreglo. */<br />

#include //Para cout y cin<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.11<br />

const int TAMANO_ARREGLO = 12;<br />

int arreglo[TAMANO_ARREGLO] = {1, 3, 5, 4, 7, 2, 99, 16, 45, 67, 89, 45};<br />

int total = 0;<br />

for(int i = 0; i < TAMANO_ARREGLO; i++)<br />

total += arreglo[i];<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.12<br />

El siguiente programa, PROMEDIO1.CPP, calcula el promedio de los elementos de un arreglo. Los<br />

elementos del arreglo son preasignados.<br />

/* El siguiente programa: PROMEDIO1.CPP, calcula el valor promedio de un arreglo.<br />

Los elementos del arreglo están preasignados.<br />

*/<br />

#include //Para cout y cin<br />

const int TAMANO_ARREGLO = 10;<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.13<br />

double arreglo[TAMANO_ARREGLO] = { 12.2, 45.4, 67.2, 12.2, 34.6, 87.4,<br />

83.6, 12.3, 14.8, 55.5 };<br />

double suma = 0;<br />

for (int ix = 0; ix < TAMANO_ARREGLO; ++ix)<br />

{<br />

suma += arreglo[ix];<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.14<br />

Nuestro siguiente programa, HISTOGRAMA.CPP, lee los números de un arreglo llamado arreglo y traza<br />

la información en forma de un gráfico de barras o histograma; cada número se imprime, seguido de una<br />

barra consistente en la misma cantidad de asteriscos.<br />

/* El siguiente programa: HISTOGRAMA.CPP, imprime un histograma. */<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

void main(void)<br />

{<br />

}//Fin de main()<br />

Ejemplo <strong>18</strong>.15<br />

// Ahora obtiene el promedio<br />

double suma = 0;<br />

for (int ix = 0; ix < numeroElementos; ++ix)<br />

suma += arreglo[ix];<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.16<br />

El siguiente programa, CARACTERES.CPP, muestra la inicialización de un arreglo de caracteres con una<br />

literal de cadena; la lectura de una cadena para dejarla en un arreglo de caracteres; la impresión de un<br />

arreglo de caracteres como cadena y el acceso a los caracteres individuales de una cadena.<br />

Ejemplo <strong>18</strong>.17<br />

const int TAMANO_ARREGLO = 7;<br />

int cara, frecuencia[TAMANO_ARREGLO] = {0};<br />

srand(time(0));<br />

for(int tirada = 1; tirada


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: ESTAUTO.CPP, ilustra el uso de arreglos estáticos y automáticos. */<br />

#include //Para cout y cin<br />

void arregloEstatico(void);<br />

void arregloAutomatico(void);<br />

void main(void)<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

PASO <strong>DE</strong> ARREGLOS Y ELEMENTOS <strong>DE</strong> ARREGLOS A <strong>LA</strong>S FUNCIONES<br />

Es posible pasar un arreglo completo a una función o pasar sólo elementos de un arreglo a<br />

una función. Lo importante de recordar es que para pasar un arreglo completo, deberá pasar la<br />

dirección del arreglo. En C y C++, el nombre del arreglo es la dirección del primer elemento<br />

(índice[0]) del arreglo. Empecemos viendo el encabezado de la función. Éste es el prototipo para<br />

pasar un arreglo unidimensional a una función:<br />

void raro(char arreglo[TAMANO_ARREGLO]);<br />

o lo que es más correcto<br />

void raro(char arreglo[], int tamanoArreglo);<br />

Observe el prototipo, vea que la función no regresa un valor. Hay un parámetro de<br />

caracteres llamado arreglo[TAMANO_ARREGLO] La única serie de corchetes después del<br />

identificador del parámetro implica que el parámetro es un arreglo unidimensional con un<br />

tamaño TAMANO_ARREGLO. Cuando se pasan los arreglos a una función, la función deberá<br />

saber qué tan grande es el arreglo que aceptará. Ahora, el identificador del arreglo hace<br />

referencia a la dirección del arreglo, así el arreglo pasa por referencia a la función. De esta<br />

manera, cualquier operación en el arreglo dentro de la función afectará el contenido original del<br />

arreglo en el programa llamador. Asimismo, dado que el parámetro es la dirección del arreglo, no<br />

se requiere ningún símbolo ampersand, (&), para pasar el arreglo por referencia. De hecho, el<br />

uso de un símbolo ampersand antes del parámetro del arreglo originará un error de compilación.<br />

Después, para llamar esta función y pasar el arreglo, simplemente utilice el siguiente<br />

enunciado:<br />

raro(nombreArreglo);<br />

o lo que es más correcto<br />

raro(nombreArreglo, tamanoArreglo);<br />

Desde luego, esta llamada supone que nombreArreglo es la denominación del arreglo en<br />

el programa llamador. (Recuerde que el identificador del argumento real y el identificador del<br />

parámetro formal pueden ser diferentes.) La llamada a nombreArreglo da referencia de la<br />

dirección del arreglo, de manera que, la dirección del arreglo pasa a la función más que una<br />

copia del arreglo. Así, cualquier operación en el arreglo dentro de la función afectará los<br />

elementos originales del arreglo. Un programa completo es como sigue:<br />

Ejemplo <strong>18</strong>.<strong>18</strong><br />

/* El siguiente programa: PASARRE.CPP, ilustra como se pasa un arreglo a una función. */<br />

#include // Para cin y cout<br />

// <strong>DE</strong>C<strong>LA</strong>RA EL TAMAÑO <strong>DE</strong>L ARREGLO<br />

const int TAMANO_ARREGLO = 3;<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-21


MIGUEL Á. TOLEDO MARTÍNEZ<br />

// FUNCIÓN PROTOTIPO<br />

void raro(char arreglo[TAMANO_ARREGLO]);<br />

void main(void)<br />

{<br />

//<strong>DE</strong>FINE UN ARREGLO <strong>DE</strong> CARACTERES<br />

char nombre[TAMANO_ARREGLO];<br />

//LLENE EL ARREGLO nombre CON CARACTERES<br />

nombre[0] ='I';<br />

nombre[1] ='B';<br />

nombre[2] ='M';<br />

//MUESTRA EL ARREGLO nombre<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

void pasaPorValor(int elementoArreglo);<br />

El encabezado dice que la función no regresa ningún valor y espera recibir un valor entero desde el<br />

programa llamador. Suponga que se hace un llamado a la función como sigue:<br />

pasaPorValor(registros[0]);<br />

Observe que el argumento real en la llamada de la función es registros[0] Esto genera una copia del<br />

elemento almacenado en el índice [0] en el arreglo registros[] que será transferido a la función por valor.<br />

Como resultado, cualquier operación en este elemento dentro de la función no afectará el valor del<br />

elemento en el arreglo registros[] original. Si quiere que el elemento manifieste algún cambio dentro de la<br />

función, deberá pasarla por referencia usando el símbolo ampersand en la función prototipo, como ésta:<br />

void pasaPorReferencia(int &elementoArreglo);<br />

Ahora, cualquier llamada a la función pasará la dirección del elemento a la función, pasando de esta manera<br />

el elemento por referencia.<br />

Ejemplo <strong>18</strong>.19<br />

El siguiente programa muestra cómo los elementos de un arreglo pasan por valor o por referencia.<br />

/* El siguiente programa: PASVALREF.CPP, ilustra el uso de paso de elementos de un arreglo por<br />

valor y por referencia.<br />

*/<br />

#include // Para cin y cout<br />

//ENUNCIA EL TAMAÑO <strong>DE</strong>L ARREGLO<br />

const int TAMANO_ARREGLO = 3;<br />

//FUNCIONES PROTOTIPO<br />

void pasaPorValor(int elementoArreglo);<br />

void pasaPorReferencia(int &elementoArreglo);<br />

void main(void)<br />

{<br />

int registros[TAMANO_ARREGLO];<br />

registros[0] = 10;<br />

registros[1] = 20;<br />

registros[2] = 30;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

void pasaPorValor(int elementoArreglo)<br />

{<br />

++elementoArreglo;<br />

} // Final de pasaPorValor()<br />

void pasaPorReferencia(int &elementoArreglo)<br />

{<br />

++elementoArreglo;<br />

} // Final de pasaPorReferencia()<br />

La salida que produce el programa manifiesta el efecto de las dos funciones en el elemento del arreglo.<br />

El valor del elemento en registro[0] antes de pasaPorValor() es : 10<br />

El valor del elemento en registro[0] después de pasaPorValor() es : 10<br />

El valor del elemento en registro[0] antes de pasaPorReferencia() : 10<br />

El valor del elemento en registro[0] después de pasaPorReferencia(): 11<br />

Estudie los dos programas siguientes para asegurarse que comprende cómo pasan a las<br />

funciones los arreglos completos y los elementos individuales del arreglo.<br />

Ejemplo <strong>18</strong>.20<br />

El siguiente programa, PASOARRE2.CPP, muestra la diferencia entre pasar un arreglo completo y pasar<br />

un elemento del arreglo.<br />

/* El siguiente programa: PASOARRE2.CPP, pasa un arreglo y elementos del arreglo a funciones. */<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

void modificarArreglo(int[], int);<br />

void modificarElemento(int);<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 5;<br />

int i, arreglo[TAMANO_ARREGLO] = {0, 1, 2, 3, 4};<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.21<br />

Ejemplo <strong>18</strong>.22<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: ARRPARAM.CPP, pasa tres arreglos diferentes (de diferentes tamaños)<br />

a la función mostrarValores().<br />

*/<br />

#include //Para cout y cin<br />

void mostrarValores(int valores[], int numeroElementos)<br />

{<br />

int i;<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.23<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

int buscaMinimo(int arreglo[], int tamano)<br />

{<br />

int pequeno = arreglo[0];<br />

Ejemplo <strong>18</strong>.24<br />

for (int i = 1; i < tamano; i++)<br />

if (arreglo[i] < pequeno)<br />

pequeno = arreglo[i];<br />

return pequeno;<br />

}//Fin de buscaMinimo()<br />

int buscaMaximo(int arreglo[], int tamano)<br />

{<br />

int grande = arreglo[0];<br />

void main(void)<br />

{<br />

for (int i = 1; i < tamano; i++)<br />

if (arreglo[i] > grande)<br />

grande = arreglo[i];<br />

return grande;<br />

}//Fin de buscaMaximo()<br />

int arreglo[MAX], numElementos;<br />

numElementos = obtenNumPuntos(MIN, MAX);<br />

// Pide datos al usuario<br />

for (int i = 0; i < numElementos; i++)<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Función obtenerCalificaciones(): Obtiene del usuario los registros de los exámenes y los<br />

coloca en un arreglo.<br />

Acepta: El número de calificaciones y el arreglo de las<br />

calificaciones con un tamaño máximo de MAX.<br />

Regresa: El número de calificaciones y el arreglo que llena el<br />

usuario con las calificaciones.<br />

Es necesario que la interfaz de la función acepte y regrese la estructura del arreglo. Supongamos que las<br />

calificaciones son valores decimales y, por lo tanto, se necesita un arreglo de punto flotante. La función<br />

prototipo será:<br />

void obtenerCalificaciones(int &numero, float calificaciones[MAX])<br />

A partir de esto, es fácil la escritura de la función. Emplearemos un enunciado cin dentro de un ciclo for en<br />

el cuerpo de la función para llenar el arreglo con las calificaciones.<br />

A continuación la función completa:<br />

void obtenerCalificaciones(int &numero, float calificaciones[MAX])<br />

{<br />

cout > numero;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

El cuerpo de la función simplemente suma todas las calificaciones del arreglo y los divide entre su número.<br />

A continuación se ve la función completa:<br />

float promedio(int numero, float calificaciones[MAX])<br />

{<br />

float total = 0.0;<br />

for (int i = 0; i < numero; ++i)<br />

total +=calificaciones[i];<br />

return total/numero;<br />

} // Fin de promedio()<br />

Hay dos variables locales de función definidas: total e i. total actuará como una variable temporal para<br />

acumular la suma de las calificaciones y la variable i es la variable contador del ciclo. Primero, la variable<br />

total se inicializa a 0. Después se usa el ciclo para obtener los elementos del arreglo, uno por uno y<br />

adicionarlos a total. Observe que el contador de ciclo (i) actúa como el índice del arreglo dentro del ciclo.<br />

De esta manera se extraen los elementos del arreglo, desde el índice [0] hasta [numero – 1], en forma<br />

secuencial con cada ciclo de iteración y se adicionan a total. La última calificación se localiza en el índice<br />

[numero – 1]. Una vez que el ciclo calcula la suma total de todas las calificaciones, se usa un enunciado<br />

return para regresar el promedio calculado.<br />

Por último, la función mostrarResultado() mostrará las calificaciones individuales obtenidas del usuario<br />

junto con sus promedios. Para hacer esto, el arreglo deberá pasar a la función para obtener las<br />

calificaciones. Aquí está la descripción de la función:<br />

Función mostrarResultado(): Muestra las calificaciones individuales y su<br />

promedio.<br />

Acepta: El número de calificaciones para mostrarlas en<br />

pantalla y el arreglo de las calificaciones.<br />

Regresa: Nada.<br />

Para mostrar el promedio, sólo se llamará a la función promedio() dentro de esta función como parte de un<br />

enunciado cout. La función completa entonces se convierte en:<br />

void mostrarResultado(int numero, float calificaciones[MAX])<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: ARREGLOS.CPP muestra el uso de los arreglos. */<br />

/*******************************************************************************<br />

Este programa calculará un promedio de calificaciones desde registros escritos<br />

por el usuario en un arreglo.<br />

*******************************************************************************/<br />

#include // Para cin y cout<br />

// Constante global<br />

const int MAX = 25; // Número máximo de registros.<br />

// Funciones prototipo<br />

void obtenerCalificaciones(int &numero, float calificaciones[MAX]);<br />

float promedio(int numero, float registros[MAX]);<br />

void mostrarResultados(int numero, float calificaciones[MAX]);<br />

void main(void)<br />

{<br />

// Define la variable numero y el arreglo<br />

int numero = 0; // Número de calificaciones<br />

float calificaciones[MAX]; // Definición del arreglo<br />

// LLama a las funciones para obtener las calificaciones y mostrar resultados<br />

obtenerCalificaciones(numero, calificaciones);<br />

mostrarResultados(numero, calificaciones);<br />

} // Fin de main()<br />

/*******************************************************************************<br />

Esta función obtiene los registros del usuario y los coloca en el arreglo<br />

calificaciones.<br />

*******************************************************************************/<br />

void obtenerCalificaciones(int &numero, float calificaciones[MAX])<br />

{<br />

cout numero;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/*******************************************************************************<br />

Esta función muestra las calificaciones del arreglo y el promedio final.<br />

*******************************************************************************/<br />

void mostrarResultados(int numero, float calificaciones[MAX])<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.26<br />

El siguiente programa, BURBUJA1.CPP, ordena los valores del arreglo de diez elementos arreglo en<br />

orden ascendente. La técnica de la que nos valemos se llama ordenamiento de burbuja u ordenamiento<br />

por hundimiento(dependiendo si se ordena en orden descendente o ascendente), pues los valores más<br />

pequeños gradualmente burbujean hacia la parte alta del arreglo como las burbujas de aire que ascienden en<br />

el agua, mientras que los valores más grandes se hunden al fondo del arreglo. La técnica es pasar varias<br />

veces por el arreglo. En cada pasada, se comparan pares sucesivos de elementos. Si uno de los pares está en<br />

orden ascendente (o son idénticos los valores), se queda tal cual. Si está en orden descendente, se<br />

intercambian sus valores en el arreglo.<br />

/* El siguiente programa: BURBUJA1.CPP, ordena los valores de un arreglo en orden ascendente<br />

utilizando el método de la burbuja.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 10;<br />

int arreglo[TAMANO_ARREGLO] = {2, 6, 4, 8, 10, 12, 89, 68, 45, 37};<br />

int i, temporal;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.27<br />

El problema anterior puede mejorarse solicitando el número de datos a ordenar, llamaremos a este programa,<br />

BURBUJA2.CPP. Es importante que observe algunos cambios que hicimos en la función clasifBurbuja()<br />

/* El siguiente programa: BURBUJA2.CPP, ordena arreglos usando el método de ordenamiento<br />

de la burbuja.<br />

*/<br />

#include //Para cout y cin<br />

const int MIN = 2;<br />

const int MAX = 10;<br />

int obtenNumPuntos(int minimo, int maximo)<br />

{<br />

int numPuntos;<br />

do<br />

return numPuntos;<br />

}//Fin de obtenNumPuntos()<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

void main(void)<br />

{<br />

Ejemplo <strong>18</strong>.28<br />

}//Fin de clasifBurbuja()<br />

int arr[MAX];<br />

int numElementos;<br />

{<br />

int temp = intArr[i];<br />

intArr[i] = intArr[j];<br />

intArr[j] = temp;<br />

}//Fin de for<br />

numElementos = obtenNumPuntos(MIN, MAX);<br />

entradaArreglo(arr, numElementos);<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.29<br />

El método de la burbuja, puede mejorarse disminuyendo el número de elementos en cada pasada, a este método se<br />

le conoce con el nombre de selección. El siguiente programa, SE<strong>LECCIÓN</strong>.CPP, ilustra este método.<br />

Ejemplo <strong>18</strong>.30<br />

metodoBurbuja(valores, 30);<br />

for (i = 0; i < 30; i++)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: METSHELL.CPP, utiliza el método Shell para ordenar<br />

un arreglo que contiene 50 elementos generados aleatoriamente.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para rand()<br />

void ordenarShell(int arreglo[], int tamano)<br />

{<br />

int temp, espacio, i, banderaCambio;<br />

Ejemplo <strong>18</strong>.31<br />

espacio = tamano / 2;<br />

do<br />

{<br />

do<br />

{<br />

banderaCambio = 0;<br />

for (i = 0; i < tamano - espacio; i++)<br />

if (arreglo[i] > arreglo[i + espacio])<br />

{<br />

temp = arreglo[i];<br />

arreglo[i] = arreglo[i + espacio];<br />

arreglo[i + espacio] = temp;<br />

banderaCambio = 1;<br />

}//Fin de if<br />

} while (banderaCambio);<br />

} while (espacio = espacio / 2);<br />

}//Fin de ordenarShell()<br />

void main(void)<br />

{<br />

int valores[50], i;<br />

for(i = 0; i < 50; i++)<br />

valores[i] = rand() % 100;<br />

ordenarShell(valores, 50);<br />

for (i= 0; i < 50; i++)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: RAPIDO.CPP, utiliza el método de clasificación ordenamiento<br />

rápido, para ordenar un arreglo que contiene 100 elementos generados en forma<br />

aleatoria.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para rand()<br />

void ordenarRapido(int arreglo[], int primero, int ultimo)<br />

{<br />

int temp, bajo, alto, separadorLista;<br />

do<br />

Ejemplo <strong>18</strong>.32<br />

bajo = primero;<br />

alto = ultimo;<br />

separadorLista = arreglo[(primero + ultimo) / 2];<br />

{<br />

while (arreglo[bajo] < separadorLista)<br />

bajo++;<br />

while (arreglo[alto] > separadorLista)<br />

alto--;<br />

if (bajo


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Cada una de las respuestas es un número del 1 al 9. El programa calcula la media, la mediana y la moda de<br />

los 99 valores.<br />

/* El siguiente programa: ESTADISTICA.CPP, presenta el tema del análisis de información<br />

de una encuesta. Calcula la media, la mediana y la moda de los datos.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para setw(w)<br />

void media(const int [], int);<br />

void mediana(int [], int);<br />

void moda(int [], int [], int);<br />

void burbuja(int [], int);<br />

void escribirArreglo(const int[], int);<br />

void main(void)<br />

{<br />

const int TAMANO_RESPUESTAS = 99;<br />

int frecuencia[10] = {0},<br />

respuestas[TAMANO_RESPUESTAS] = {6, 7, 8, 9, 8, 7, 8, 9, 8, 9,7, 8, 9, 5, 9, 8, 7, 8, 7, 8,<br />

6, 7, 8, 9, 3, 9, 8, 7, 8, 7,<br />

7, 8, 9, 8, 9, 8, 9, 7, 8, 9,<br />

6, 7, 8, 7, 8, 7, 9, 8, 9, 2,<br />

7, 8, 9, 8, 9, 8, 9, 7, 5, 3,<br />

5, 6, 7, 2, 5, 3, 9, 4, 6, 4,<br />

7, 8, 9, 6, 8, 7, 8, 9, 7, 8,<br />

7, 4, 4, 2, 5, 3, 8, 7, 5, 6,<br />

4, 5, 6, 1, 6, 5, 7, 8, 7};<br />

media(respuestas, TAMANO_RESPUESTAS);<br />

mediana(respuestas, TAMANO_RESPUESTAS);<br />

moda(frecuencia, respuestas, TAMANO_RESPUESTAS);<br />

}//Fin de main()<br />

void media(const int contestacion[], int tamanoArreglo)<br />

{<br />

int total = 0;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

escribirArreglo(contestacion, tamano);<br />

burbuja(contestacion, tamano);<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

a[j] = a[j + 1];<br />

a[j + 1] = temporal;<br />

}//Fin de if<br />

}//Fin de burbuja()<br />

void escribirArreglo(const int a[], int tamano)<br />

{<br />

for(int j = 0; j < tamano; j++)<br />

{<br />

if(j %20 == 0)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: BUSLINEAL.CPP, ilustra el método de búsqueda lineal en un arreglo. */<br />

#include //Para cout y cin<br />

int busquedaLineal(const int[], int, int);<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 100;<br />

int a[TAMANO_ARREGLO], claveBusqueda, elemento;<br />

for(int x = 0; x < TAMANO_ARREGLO; x++) //Crea algunos datos<br />

a[x] = 2 * x;<br />

cout > claveBusqueda;<br />

elemento = busquedaLineal(a, claveBusqueda, TAMANO_ARREGLO);<br />

if(elemento != -1)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

búsqueda binaria de cualquier arreglo ordenado puede determinarse encontrando la primera potencia de 2<br />

mayor que el número de elementos del arreglo.<br />

Ejemplo <strong>18</strong>.34<br />

El siguiente programa, BUSBIN.CPP, presenta la versión iterativa de la función busquedaBinaria() La<br />

función recibe cuatro argumentos: un arreglo de enteros b, un entero claveBusqueda, el índice bajo del<br />

arreglo y el índice alto del arreglo. Si la clave de búsqueda no es igual al elemento de la mitad de un<br />

subarreglo, se ajusta el índice bajo o alto para poder hacer la búsqueda en un subarreglo más pequeño. Si la<br />

clave de búsqueda es menor que el elemento central, el índice alto se establece a mitad – 1 y se continúa la<br />

búsqueda en los elementos de bajo a mitad – 1. Si la clave de búsqueda es mayor que el elemento central, el<br />

índice bajo se establece a mitad + 1 y se continúa la búsqueda en los elementos de mitad + 1 a alto. El<br />

programa emplea un arreglo de 15 elementos. La primera potencia de 2 mayor que la cantidad de elementos<br />

de este arreglo es 16 (2 4 ), por lo que se necesitan un máximo de 4 comparaciones para encontrar la clave de<br />

búsqueda. La función imprimirEncabezado() envía a la salida los índices del arreglo y la función<br />

imprimirFila() envía a la salida cada subarreglo generado durante el proceso de búsqueda binaria. El<br />

elemento central de cada subarreglo se marca con un asterisco (*), para indicar el elemento con el que se<br />

compara la clave de búsqueda.<br />

/* El siguiente programa: BUSBIN.CPP, ilustra el uso de la búsqueda binaria en un arreglo. */<br />

#include //Para cout y cin<br />

#include //Para setw()<br />

int busquedaBinaria(int[], int, int, int, int);<br />

void imprimirEncabezado(int);<br />

void imprimirFila(int[], int, int, int, int);<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 15;<br />

int a[TAMANO_ARREGLO], clave, resultado;<br />

for(int i = 0; i < TAMANO_ARREGLO; i++)<br />

a[i] = 2 * i; //Crea los elementos del arreglo<br />

cout > clave;<br />

imprimirEncabezado(TAMANO_ARREGLO);<br />

resultado = busquedaBinaria(a, clave, 0, TAMANO_ARREGLO - 1, TAMANO_ARREGLO);<br />

if(resultado != -1)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.35<br />

{<br />

mitad = (bajo + alto) / 2;<br />

imprimirFila(b, bajo, mitad, alto, tamano);<br />

if(claveBusqueda == b[mitad]) //coincidencia<br />

return mitad;<br />

else if(claveBusqueda < b[mitad])<br />

alto = mitad - 1; //Busca en la parte baja del arreglo<br />

else<br />

bajo = mitad + 1; //Busca en la parte alta del arreglo<br />

}//Fin de while<br />

return -1; //No se encontró claveBusqueda<br />

}//Fin de busquedaBinaria()<br />

//Imprime el encabezado para la salida<br />

void imprimirEncabezado(int tamano)<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

/* El siguiente programa: BINARIO.CPP, utiliza una búsqueda binaria para localizar<br />

valores en el arreglo llamado contador, el cual contiene los valores de 1 a<br />

100. La función busquedaBinaria imprime mensajes que describen el proceso.<br />

*/<br />

#include //Para cout y cin<br />

int busquedaBinaria(int arreglo[], int valor, int tamano)<br />

{<br />

int encontrado = 0;<br />

int alto = tamano, bajo = 0, enmedio;<br />

void main(void)<br />

{<br />

enmedio = (alto + bajo) / 2;<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

SOLUCIÓN <strong>DE</strong> PROBLEMAS EN ACCIÓN: Búsqueda en un arreglo con iteración<br />

(Búsqueda secuencial)<br />

PROBLEMA<br />

Diversas aplicaciones requieren de un programa para buscar un determinado elemento en un arreglo. Para<br />

realizar esta tarea se usan dos algoritmos comunes que son búsqueda secuencial o serial y búsqueda<br />

binaria. Por lo común, la búsqueda secuencial se utiliza para arreglos no ordenados y la búsqueda binaria<br />

en arreglos ordenados. En el siguiente problema veremos la búsqueda secuencial; en un problema posterior<br />

veremos la búsqueda binaria.<br />

Desarrolle una función que busque, en forma secuencial, en un arreglo de enteros, el valor de un elemento<br />

dado y que regrese el índice del elemento si éste se encuentra en el arreglo.<br />

<strong>DE</strong>FINICIÓN <strong>DE</strong>L PROBLEMA<br />

Debido a que se trata de una función, la definición del problema se enfocará a la interfaz de la función. Por<br />

consiguiente, se debe considerar que la función aceptará y regresará algo. Llamaremos a la función<br />

busquedaSec() A partir del enunciado del problema, la función deberá buscar en un arreglo de enteros un<br />

valor de un elemento determinado. De esta manera, la función necesita dos cosas para realizar este trabajo:<br />

(1) el arreglo y (2) el elemento que se va a buscar. Estos serán los parámetros de la función, ¿deberán ser<br />

de valor o de referencia? Bueno, la función no cambiará ni al arreglo ni al elemento a buscar, ¿es<br />

correcto? Por lo tanto, los parámetros serán por valor.<br />

Después, necesitamos determinar que va a regresar la función al programa llamador. A partir del enunciado<br />

del problema, se observa que la función necesita regresar el índice del elemento buscado, si se encuentra en<br />

el arreglo. En C++ todos los índices de los arreglos son enteros, por lo tanto la función regresará un valor<br />

entero. Pero, ¿qué pasa si el elemento que se busca no se encuentra en el arreglo? Se regresará algún<br />

valor entero que aclare esta situación. Dado que, en C++ los índices de los arreglos se encuentran en un<br />

rango de 0 a algún entero positivo finito, si el elemento no se encuentra en el arreglo, regresará el entero -1.<br />

De esta manera usaremos –1 para indicar la condición no encontrado, porque en C++ ningún índice de<br />

arreglo tiene este valor. La descripción de la interfaz de la función será:<br />

Función busquedaSec(): Busca en un arreglo entero un valor de elemento<br />

dado.<br />

Acepta: Un arreglo de enteros y el elemento que se busca.<br />

Regresa: El índice del arreglo del elemento, si se encuentra, o<br />

el valor –1 si no se encuentra el elemento.<br />

La descripción de interfaz de la función anterior proporciona toda la información necesaria para escribir la<br />

interfaz de la función, como sigue:<br />

int busquedaSec(int arreglo[MAX], int elemento)<br />

La interfaz indica que la función aceptará dos cosas: (1) un arreglo de elementos enteros MAX y (2) un<br />

valor entero, llamado elemento, que será el valor que se busca.<br />

La siguiente tarea es desarrollar el algoritmo de búsqueda secuencial.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-45


MIGUEL Á. TOLEDO MARTÍNEZ<br />

P<strong>LA</strong>NEACIÓN <strong>DE</strong> <strong>LA</strong> SOLUCIÓN<br />

¿Qué quiere decir exactamente búsqueda secuencial? Rastreo en el arreglo en forma secuencial, de un<br />

elemento al siguiente, empezando en la primera posición del arreglo y deteniéndose al encontrar el<br />

elemento o al llegar al final del arreglo. De esta manera, el algoritmo deberá verificar el elemento<br />

almacenado en la primera posición del arreglo, después en la segunda posición del arreglo, enseguida en la<br />

tercera y así sucesivamente, hasta que encuentre el elemento o hasta que se agoten los elementos del<br />

arreglo. Desde luego, ésta es una tarea repetitiva de verificación de un elemento en el arreglo, luego<br />

moverse al siguiente elemento y verificar otra vez y así sucesivamente. Considere el siguiente algoritmo<br />

que emplea un ciclo while para realizar la operación de verificación repetitiva:<br />

Algoritmo busquedaSec()<br />

busquedaSec()<br />

INICIO<br />

encuentra = falso.<br />

indice = primer índice del arreglo.<br />

while(elemento no se Encuentra) AND (Indice


MIGUEL Á. TOLEDO MARTÍNEZ<br />

// Busca en el arreglo hasta encontrar o alcanzar el final del arreglo<br />

while((!encuentra) && (i < MAX))<br />

{<br />

if (a[i] == elemento) // Verifica el elemento del arreglo<br />

encuentra = Verdadero; // Si es igual, establece<br />

else // encuentra a Verdadero<br />

++i;<br />

} // Fin del while<br />

// Si se encuentra el elemento, regresa la posición del elemento en el arreglo<br />

// Si no regresa –1<br />

if(encuentra)<br />

return i;<br />

else<br />

return –1;<br />

} // Fin de busquedaSec()<br />

No debe haber sorpresas en este código. En la parte superior de la función, verá el encabezado que es<br />

idéntico a la interfaz de la función desarrollada anteriormente. Después verá una clase de datos enumerada<br />

creada para definir Falso y Verdadero. Recuerde que los valores predeterminados para elementos de datos<br />

enumerados son enteros, empezando con 0. De esta manera, Falso se define con el valor 0 y Verdadero se<br />

define con el de 1. Esto permite la utilización de los identificadores Falso y Verdadero dentro del programa<br />

para representar los valores enteros 0 y 1 respectivamente. Además, las verificaciones booleanas se pueden<br />

hacer contra estos valores, porque C++ interpreta un 0 como un Falso lógico y 1 como un Verdadero<br />

lógico.<br />

La variable encuentra se define como un objeto de clases de datos booleanos enumerados y se establece a<br />

Falso. Utilizaremos la variable i como variable índice del arreglo. Esta variable se define como un entero y<br />

establece a 0 el primer índice del arreglo. Recuerde que los arreglos en C++ siempre empiezan con el índice<br />

0. El ciclo while emplea el operador AND (&&) para verificar los valores de encuentra e i. El ciclo se<br />

repetirá hasta que se encuentre el elemento (encuentra) y el valor de i sea menor que el tamaño MAX del<br />

arreglo. Recuerde que cuando el tamaño del arreglo es MAX, el último índice del arreglo es MAX – 1. Por<br />

lo tanto, cuando i excede el índice máximo del arreglo, MAX – 1, el ciclo se rompe. Cuando el ciclo se<br />

rompe, el valor de encuentra se verifica. Si encuentra es Verdadero, se regresa el valor de i; si encuentra<br />

es Falso, el valor –1 se regresa para indicar que el elemento no se encontró en el arreglo.<br />

SOLUCIÓN <strong>DE</strong> PROBLEMAS EN ACCIÓN: Como ordenar un arreglo con iteración<br />

(Ordenación por inserción)<br />

PROBLEMA<br />

Ordenar un arreglo significa colocar los elementos del arreglo en orden ascendente o descendente desde el<br />

principio al final del arreglo. Hay muchos algoritmos comunes utilizados para ordenación. Hay<br />

clasificación por inserción, clasificación por burbuja, clasificación por selección, clasificación rápida,<br />

clasificación combinada y clasificación apilada, sólo por mencionar algunas. En un curso de estructura de<br />

datos, es muy probable que aprenda y analice todos estos algoritmos de ordenación. En este problema se<br />

desarrollará el algoritmo de clasificación por inserción y se codificará como una función en C++.<br />

Desarrolle una función que se pueda llamar para ordenar un arreglo de caracteres en orden ascendente<br />

utilizando el algoritmo clasificación por inserción.<br />

<strong>DE</strong>FINICIÓN <strong>DE</strong>L PROBLEMA<br />

De nuevo, codificaremos el algoritmo como una función C++, así la definición del problema se enfocará en<br />

la interfaz de la función, guiándonos a la función prototipo. Llamaremos a la función clasifPorInser()<br />

Piense que necesita clasifPorInser() para hacer un trabajo. Bueno, deberá recibir un arreglo de caracteres<br />

no clasificados y regresar el mismo arreglo como un arreglo clasificado, ¿correcto? ¿Necesita algo más?<br />

No, la función no requiere datos adicionales, porque lo único que se opera es el arreglo mismo.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-47


MIGUEL Á. TOLEDO MARTÍNEZ<br />

¿Qué hay de los valores de regreso? ¿Necesita regresar la función un valor sencillo o una serie de<br />

valores? La función no necesita regresar ningún valor sencillo, deberá regresar el arreglo ordenado. Por lo<br />

tanto, la clase de valor regresado será void y el arreglo será un parámetro de referencia, ¿correcto?<br />

Recuerde que cuando se pasan los arreglos a las funciones C++, siempre son tratados como parámetros de<br />

referencia porque el nombre del arreglo representa una dirección en memoria. Por lo tanto, aquí está la<br />

descripción de la interfaz de la función clasifPorInser():<br />

Función clasifPorInser(): Clasifica un arreglo de caracteres en orden ascendente.<br />

Acepta: Un arreglo de caracteres sin clasificar.<br />

Regresa: Un arreglo de caracteres clasificados.<br />

De la descripción anterior, la interfaz de la función se codifica fácilmente como:<br />

void clasifPorInser(char arreglo[MAX])<br />

La interfaz dice que clasifPorInser() recibirá un arreglo de caracteres de tamaño MAX. El tipo regresado es<br />

void, porque no se regresa ningún valor sencillo. Sin embargo, debido a que el arreglo completo se pasa a la<br />

función, cualquier operación de clasificación sobre el arreglo dentro de la función se reflejará en el<br />

programa llamador.<br />

P<strong>LA</strong>NEACIÓN <strong>DE</strong> <strong>LA</strong> SOLUCIÓN<br />

Antes de establecer el algoritmo, vamos a ver cómo trabaja la clasificación por inserción. Vea la figura<br />

<strong>18</strong>.3. Suponga que vamos a clasificar un arreglo de 5 caracteres en orden ascendente. Antes de entrar en<br />

detalle, vea la figura de arriba abajo y de izquierda a derecha. El arreglo sin ordenar se muestra en la parte<br />

superior de la figura <strong>18</strong>.3 y el arreglo ordenado se muestra en la parte inferior de la figura <strong>18</strong>.3. Observe<br />

que el sombreado se emplea en la figura para mostrar el proceso de clasificación de arriba a abajo.<br />

Conforme procedemos desde el arreglo sin clasificar en la parte superior, el sombreado se incrementa,<br />

mostrando la porción del arreglo que está clasificado, hasta que el arreglo completo está sombreado en la<br />

parte inferior de la figura <strong>18</strong>.3.<br />

La secuencia descendente muestra que se harán cuatro pasos a lo largo del arreglo para obtener al arreglo<br />

clasificado mostrado en la parte inferior de la figura. Con cada paso, un elemento se coloca dentro de su<br />

posición clasificada relativa a los elementos que se encuentran antes en el arreglo. El primer paso empieza<br />

con el primer elemento ‘E’, clasificado como se indica por medio del sombreado. Se considera que el<br />

carácter individual ‘E’ se clasifica por sí mismo, porque no tiene ningún elemento antes que él. De esta<br />

manera, la tarea en este primer paso es clasificar el segundo elemento, ‘D’, relativo al carácter ‘E’ que lo<br />

precede.<br />

El segundo paso empieza con los caracteres clasificados ‘D’ y ‘E’, como se indica por medio del<br />

sombreado. La tarea en este paso es clasificar el tercer carácter, ‘C’, en relación con estos dos caracteres.<br />

En el tercer paso se empieza con los caracteres clasificados ‘C’, ‘D’ y ‘E’, y la tarea es clasificar el carácter<br />

‘B’ en relación con estos caracteres. Recuerde, en cada paso, la tarea es clasificar el primer carácter de la<br />

parte no clasificada del arreglo en relación con los caracteres que le preceden. El proceso continúa hasta<br />

que se clasifican todos los caracteres, como se muestra en la parte inferior de la figura <strong>18</strong>.3. En cada paso<br />

se repite prácticamente lo que se hizo en el paso anterior. Como resultado, es posible identificar un proceso<br />

de repeticiones paso a paso, de arriba hacia debajo de la figura <strong>18</strong>.3. Esta repetición dará origen a una<br />

estructura de ciclo en nuestro algoritmo.<br />

Ahora, la pregunta es: ¿qué sucede durante cada paso para clasificar finalmente al arreglo completo?<br />

Bueno, durante cada paso, el primer elemento en la parte no clasificada (sin sombrear) del arreglo se<br />

examina comparándolo a la secuencia clasificada de los elementos que le preceden. Si este elemento es<br />

menor que el anterior, estos dos elementos se intercambian y de nuevo el elemento anterior se compara con<br />

su predecesor, si es menor se intercambian y así sucesivamente.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-48


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Paso 1<br />

Paso 2<br />

[0] [1] [2] [3] [4]<br />

[0] [1] [2] [3] [4] [0] [1] [2] [3] [4]<br />

[0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4]<br />

CICLO EXTERNO<br />

Paso 3<br />

Paso 4<br />

E D C B A<br />

E D C B A D E C B A<br />

D E C B A D C E B A<br />

[0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4]<br />

[0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4] [0] [1] [2] [3] [4]<br />

[0] [1] [2] [3] [4]<br />

ARREGLO C<strong>LA</strong>SIFICADO<br />

C D E B A<br />

C D E B A C D B E A C B D E A<br />

CICLO INTERNO<br />

B C D E A<br />

B C D E A B C D A E B C A D E B A C D E A B C D E<br />

A B C D E<br />

Figura <strong>18</strong>.3. La clasificación por inserción es un proceso de repeticiones anidadas<br />

Este proceso se repite hasta que sucede una de dos cosas: (1) el elemento es mayor o igual a su predecesor,<br />

o (2) el elemento está en la primera posición del arreglo (índice [0]) En otras palabras, el proceso de<br />

comparación o intercambio de izquierda a derecha que se muestra en la figura <strong>18</strong>.3 termina cuando el<br />

elemento examinado se ha insertado en su posición adecuada en la parte clasificada del arreglo. Este<br />

proceso de comparación o intercambio que representa la repetición de izquierda a derecha en la figura <strong>18</strong>.3<br />

dará como resultado otra estructura de ciclo en nuestro algoritmo. Por lo tanto, es posible identificar dos<br />

procesos repetitivos en la figura <strong>18</strong>.3, uno de arriba hacia abajo y otro de izquierda a derecha. ¿Cómo se<br />

relacionan los dos procesos repetitivos? Bien, parece que por cada paso de arriba abajo a través del<br />

arreglo, el proceso de comparación o intercambio se ejecuta de izquierda a derecha. De esta manera, el<br />

proceso de izquierda a derecha deberá anidarse dentro del proceso de arriba abajo. Esto se reflejará en<br />

nuestro algoritmo por medio de dos estructuras de ciclo: una controla el proceso de comparación o<br />

intercambio de izquierda a derecha que deberá anidarse dentro del segundo ciclo que controla el proceso de<br />

arriba abajo. Observe de nuevo la figura <strong>18</strong>.3 para asegurarse que ve esta repetición anidada. Ahora que<br />

tiene una idea de cómo funciona la ordenación por inserción, analice el algoritmo formal:<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-49


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Algoritmo clasifPorInser()<br />

clasifPorInser()<br />

INICIO<br />

Establece i = segundo índice del arreglo.<br />

mientras(i primer índice del arreglo) AND (A[j] < A[j – 1]))<br />

Inicio<br />

Intercambia A[j] y A[j – 1].<br />

Decrementa j.<br />

Fin.<br />

Incrementa i.<br />

Fin.<br />

FIN.<br />

La variable i controla el ciclo externo y j controla el ciclo interno. Observe que i empieza en el segundo<br />

índice del arreglo. ¿Por qué no en el primer índice del arreglo? Porque el primer elemento en el arreglo<br />

se clasifica siempre relativo a cualquier elemento precedente, ¿correcto? Por lo tanto, el primer paso<br />

comienza con el segundo elemento del arreglo. El primer enunciado en el ciclo externo establece a j = i. De<br />

esta manera, i y j localizan el primer elemento en la parte no clasificada del arreglo al principio de cada<br />

paso. Ahora, el ciclo interno intercambiará al elemento localizado por j, el cual es A[j], con su elemento<br />

predecesor, el cual es A[j – 1], siempre y cuando j sea mayor que el primer índice del arreglo y el elemento<br />

A[j] sea menor que el elemento A[j – 1] Una vez que se hace el intercambio, se decrementa j. Esto obliga a<br />

j a seguir siendo el elemento insertado dentro de la parte del arreglo ordenado. El intercambio continúa<br />

hasta que no hay ningún elemento que preceda al elemento A[j] que sea menor que el A[j]<br />

Una vez que se rompe el ciclo interno, el elemento A[j] se inserta en su posición correcta con relación con<br />

los elementos que le preceden. Después, se hace otro paso incrementando la variable externa para el control<br />

del ciclo i, estableciendo j a i, y ejecutando de nuevo el ciclo interno. Este proceso de ciclo anidado<br />

continúa hasta que i se incrementa más allá de la última posición del arreglo.<br />

Estudie el algoritmo anterior y compárelo con la figura <strong>18</strong>.3 hasta que esté seguro que comprende<br />

clasifPorInser() A continuación el código en C++.<br />

CODIFICACIÓN <strong>DE</strong>L PROBLEMA<br />

Hemos desarrollado la interfaz de la función clasifPorInser() En C++, el algoritmo se codifica fácilmente<br />

como una función semejante a ésta:<br />

// Función de intercambio()<br />

void interCambio(char &x, char &y)<br />

{<br />

char temp; // Crea una variable temporal<br />

temp = x;<br />

x = y;<br />

y = temp;<br />

} // Fin de interCambio()<br />

// Función clasificación por inserción<br />

void clasifPorInser(char A[MAX])<br />

{<br />

int i; // Variable que controla el ciclo exterior<br />

int j; // Variable que controla el ciclo interior<br />

i = 1; // Establece i al índice del segundo elemento<br />

while(i < MAX)<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-50


MIGUEL Á. TOLEDO MARTÍNEZ<br />

{<br />

j = i; // Localiza el primer elemento del arreglo no clasificado<br />

while((j > 0) && (A[j] < A[j – 1]))<br />

{<br />

interCambio(A[j], A[j – 1]);<br />

--j; // Hace que j siga al elemento insertado<br />

} // Final del while interno<br />

++i; // Hace que i localice el primer elemento de la parte no<br />

clasificada.<br />

} // Fin del while externo<br />

} // Fin de clasifPorInser()<br />

En este caso se pueden ver dos funciones codificadas en C++. Recuerde que el algoritmo clasifPorInser()<br />

requiere una operación de intercambio. Para llevar a cabo esta tarea se ha codificado una función llamada<br />

interCambio() Observe que esta función tiene dos parámetros de referencia que son caracteres. De esta<br />

manera, la función recibe dos caracteres que se intercambian utilizando la variable local temporal (temp)<br />

dentro de la función. Los caracteres de intercambio se envían de regreso al programa llamador por medio de<br />

los parámetros de referencia. Desde luego, el programa llamador será la función clasifPorInser()<br />

El código de clasifPorInser() debe ser directo a partir del algoritmo que se analizó. Estudie el código y<br />

compárelo con el algoritmo. Encontrará que son idénticos desde un punto de vista lógico y estructural.<br />

Debe notar cómo se llama a la función intercambio() dentro de clasifPorInser() Los elementos del arreglo<br />

A[j] y A[j – 1] se pasan a la función. Estos elementos son caracteres sencillos, ¿correcto? Por lo tanto, la<br />

función recibe dos caracteres y los intercambia. Los caracteres respectivos en el arreglo reflejan la<br />

operación de intercambio, porque intercambio() emplea parámetros de referencia.<br />

SOLUCIÓN <strong>DE</strong> PROBLEMAS EN ACCIÓN: Búsqueda en un arreglo con recursión<br />

(Búsqueda binaria)<br />

PROBLEMA<br />

En este problema desarrollaremos otro popular algoritmo de búsqueda, llamado búsqueda binaria. El<br />

algoritmo de búsqueda binaria que desarrollaremos empleará recursividad, aunque también se puede hacer<br />

utilizando iteración. Una de las principales diferencias entre búsqueda binaria y búsqueda secuencial es que<br />

la primera requiere que el arreglo se ordene antes de la búsqueda, mientras que la segunda no tiene este<br />

requerimiento. Sin embargo, si va a empezar con un arreglo ordenado, la búsqueda binaria es mucho más<br />

rápida que la secuencial, especialmente para arreglos grandes. Por ejemplo, si fuera a aplicar una búsqueda<br />

secuencia a un arreglo de 1000 enteros, el algoritmo de búsqueda secuencial hará un promedio de 500<br />

comparaciones para encontrar el elemento deseado. Peor aún, si el elemento deseado está en la última<br />

posición del arreglo, la búsqueda secuencial hará mil comparaciones para encontrar el elemento. Por otra<br />

parte, la búsqueda binaria requerirá un máximo de 10 comparaciones para encontrar el elemento, ¡aún si<br />

está en la última posición del arreglo! Desde luego, se debe pagar un precio por esta mayor eficiencia. El<br />

precio que se paga es un algoritmo más complejo. Por lo tanto, cuando busque en un arreglo ordenado, la<br />

ventaja de la búsqueda secuencial es simplicidad, mientras que la ventaja de la búsqueda binaria es<br />

eficiencia.<br />

Desarrolle una función en C++ que se pueda llamar para buscar en un arreglo ordenado de enteros un<br />

elemento con determinado valor y que regrese el índice del elemento si se encuentra en el arreglo. Utilice<br />

una búsqueda binaria recursiva para realizar esta tarea.<br />

Se desarrollará una función en C++, así la definición del problema se enfocará de nuevo a la interfaz de la<br />

función. Sin embargo, antes de considerar la interfaz de la función, veamos cómo funciona una búsqueda<br />

binaria recursiva, porque el algoritmo de búsqueda dictará los parámetros de la función. Por lo tanto,<br />

primero trataremos el algoritmo y después desarrollaremos la interfaz de la función.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-51


MIGUEL Á. TOLEDO MARTÍNEZ<br />

P<strong>LA</strong>NEACIÓN <strong>DE</strong> <strong>LA</strong> SOLUCIÓN<br />

La búsqueda binaria representa una operación recursiva natural. Recuerde que la idea detrás de la<br />

recursividad es dividir un problema en subproblemas. Dividir un problema en subproblemas más simples de<br />

exactamente el mismo tipo hasta que ocurra una condición primitiva. Esto no es lo mismo que el diseño de<br />

software descendente, que divide los problemas en subproblemas más simples. La diferencia con la<br />

recursividad es que los subproblemas son exactamente del mismo tipo de problema que el problema<br />

original. Por ejemplo, suponga que está buscando un nombre en un directorio. Imagine que empieza al<br />

principio del directorio y ve cada nombre hasta que encuentra el correcto. Esto es exactamente lo que hace<br />

la búsqueda secuencial. ¿No sería más rápido, en promedio, abrir el directorio a la mitad? Después,<br />

determinar qué mitad del directorio contiene el nombre que está buscando, dividir esta sección del<br />

directorio a la mitad y así sucesivamente, hasta que obtiene la página en la cual aparece el nombre deseado.<br />

Aquí está un algoritmo que describe la búsqueda en el directorio como se describió.<br />

UN ALGORITMO <strong>DE</strong> BÚSQUEDA RECURSIVA EN UN DIRECTORIO<br />

buscaTel()<br />

INICIO<br />

si(el directorio telefónico sólo tiene una página) entonces<br />

Busca el nombre en la página.<br />

sino<br />

Abre el libro a la mitad.<br />

si(el nombre está en la primera mitad) entonces<br />

buscaTel(primera mitad del directorio para el nombre)<br />

sino<br />

buscaTel(segunda mitad del directorio para el nombre)<br />

FIN.<br />

¿Observa cómo esta búsqueda es recursiva? Se mantiene realizando las mismas operaciones básicas<br />

hasta que llega a la página que contiene el nombre que está buscando. En otras palabras, la función<br />

buscaTel() se mantiene llamándose a sí misma en el enunciado anidado si/sino hasta que se encuentra la<br />

página correcta. La razón por la que se llama al proceso de búsqueda binaria es que deberá dividir el<br />

directorio entre 2 (bi) cada vez que se llama a sí mismo el algoritmo.<br />

Ahora, vamos a ver cómo se puede aplicar este proceso a la búsqueda en un arreglo de enteros. Se llamará a<br />

la función de búsqueda binaria recursiva busquedaBin() y se desarrollará el algoritmo en varios pasos.<br />

Aquí esta el primer nivel del algoritmo.<br />

Algoritmo busquedaBin(): Primer nivel<br />

busquedaBin()<br />

INICIO<br />

si(el arreglo tiene sólo un elemento) entonces<br />

Determine si este elemento es el elemento buscado.<br />

sino<br />

Encuentre el punto medio del arreglo.<br />

si(el elemento está en la primera mitad) entonces<br />

busquedaBin(primera mitad)<br />

sino<br />

busquedaBin(segunda mitad)<br />

FIN.<br />

Observe cómo este algoritmo es casi idéntico al algoritmo buscaTel() Aquí el proceso de búsqueda se<br />

continúa hasta que el arreglo se reduce a un elemento que se verifica contra el elemento que se está<br />

buscando. ¿Observa cómo la búsqueda se mantiene llamándose a sí misma hasta que ocurre la<br />

condición primitiva? Aunque este algoritmo proporciona una idea general de búsqueda binaria, se necesita<br />

mayor detalle para codificar el algoritmo. Para hacerlo, debemos preguntarnos que datos necesita<br />

busquedaBin() para realizar esta tarea. Bueno, al igual que la búsqueda secuencial, ésta necesita un arreglo<br />

en dónde buscar y el elemento que se va a buscar ¿correcto? Sin embargo, la búsqueda secuencial trata con<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-52


MIGUEL Á. TOLEDO MARTÍNEZ<br />

un tamaño de arreglo dado, mientras que la búsqueda binaria necesita tratar con arreglos de tamaños<br />

diferentes conforme sigue dividiendo al arreglo original a la mitad. No solamente son estos arreglos de<br />

diferente tamaño, sino el primero y el último índices de cada mitad son diferentes. Como resultado,<br />

debemos proporcionar a busquedaBin() los límites del arreglo que está tratando en cualquier momento<br />

dado. Esto se puede hacer pasando el primero y último índices del arreglo dado a la función. Llamemos a<br />

estos índices primero y ultimo.<br />

Estamos listos para escribir la descripción de la interfaz de la función:<br />

Función busquedaBin(): Busca en un arreglo de enteros ordenado un valor<br />

determinado.<br />

Acepta: Un arreglo de enteros, un elemento de búsqueda, el primero<br />

y el último índices del arreglo en el cual se busca.<br />

Regresa: El índice del elemento, si se encuentra, o el valor -1 si el<br />

elemento no se encuentra.<br />

Esta descripción da suficiente información para escribir la interfaz de la función C++, como sigue:<br />

int busquedaBin(int A[], int elemento, int primero, int ultimo)<br />

Aquí, busquedaBin() regresará un valor entero que representa el índice del elemento que se busca. De<br />

nuevo, verá que regresará el valor -1 si el elemento no se encuentra en el arreglo. La función recibe el<br />

arreglo de enteros que se busca (A[]), el elemento que se busca (elemento), el primer índice del arreglo<br />

(primero) y el último índice del arreglo (ultimo) Observe que ningún tamaño se proporciona para el arreglo<br />

en que se busca porque la función buscará en forma recursiva en arreglos de diferentes tamaños.<br />

El siguiente problema es determinar qué valor de primero y ultimo se utilizarán para cualquier arreglo<br />

durante la búsqueda. Bueno, recuerde que se deberá dividir cualquier arreglo dado a la mitad para producir<br />

dos nuevos arreglos cada vez que se hace una llamada recursiva busquedaBin() Dado cualquier arreglo<br />

donde el primer índice es primero y el último índice es ultimo, se puede determinar el índice medio, como<br />

sigue:<br />

mitad = (primero + ultimo) / 2<br />

Con este cálculo, la primera mitad del arreglo empieza en primero y finaliza en mitad - 1, y la segunda<br />

mitad del arreglo empieza en mitad + 1 y finaliza en ultimo. Esta idea se muestra en la figura <strong>18</strong>.4.<br />

Pero, observe que ninguna mitad del arreglo contiene el elemento medio. Por me- dio de la utilización de<br />

esta técnica, las dos mitades no hacen un todo, ¿correcto? Por lo tanto, antes que se haga la división,<br />

suponga que verificamos el elemento medio para ver si es el elemento que se está buscando. La siguiente<br />

verificación realiza el trabajo.<br />

si (A[mitad] == elemento) entonces<br />

regresar mitad.<br />

Si esta verificación es verdadera antes de la división, se habrá encontrado el elemento que se está buscando<br />

y es posible terminar las llamadas recursivas. De otra manera, el elemento almacenado en A[mitad] no es el<br />

elemento que se está buscando, y esta posición del arreglo se puede ignorar durante el resto de la búsqueda.<br />

Si éste es el caso, se dividirá el arreglo y continuará el proceso recursivo. Sin embargo, se tiene que<br />

adicionar una segunda condición primitiva para el algoritmo recursivo. Aquí están las dos condiciones<br />

primitivas que se han hecho:<br />

1. El arreglo que se busca tiene sólo un elemento.<br />

2. A [mitad] == elemento.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-53


MIGUEL Á. TOLEDO MARTÍNEZ<br />

mitad = (primero + ultimo) / 2<br />

[primero] [ultimo]<br />

[primero] [mitad – 1] [mitad + 1] [ultimo]<br />

Figura <strong>18</strong>.4. La búsqueda binaria recursiva requiere que un arreglo sea dividido en mitades con cada llamada recursiva.<br />

Cualquiera de estas condiciones primitivas hará que termine la llamada recursiva. Ahora, vamos a<br />

considerar la primera condición primitiva más de cerca. ¿Cómo saber si el arreglo que se busca tiene<br />

solamente un elemento? Bueno, conforme continúan las llamadas recursivas sin encontrar el elemento,<br />

finalmente el arreglo se reducirá a un elemento sencillo. Si éste es el que se está buscando, la verificación si<br />

A[mitad] == elemento será verdadera, y las llamadas recursivas se detendrán. Si no lo es, el valor de<br />

primero se hará más grande que el valor de ultimo en la siguiente división. ¿Por qué? Porque si piensa en<br />

la acción de división del algoritmo, se dará cuenta que cada llamada recursiva hace que primero se<br />

incremento y ultimo se decremente. De esta manera, si el elemento no está en el arreglo, el valor de<br />

primero se hace finalmente más grande que el valor de ultimo. Por lo tanto se puede usar esta idea para<br />

verificar que el elemento no está en el arreglo, también para usarlo como una condición primitiva. De esta<br />

manera, se reemplazará la condición primitiva original con el siguiente enunciado:<br />

si (primero > ultimo) entonces<br />

regresar – 1<br />

Si ocurre esta condición, se regresa el valor -1, indicando que no se encontró el elemento y terminan las<br />

llamadas recursivas.<br />

Ahora, vamos a aplicar este conocimiento a un segundo nivel del algoritmo. Como sigue:<br />

Algoritmo busquedaBin(): Segundo nivel<br />

busquedaBin(A, elemento, primero, ultimo)<br />

INICIO<br />

si(primero > ultimo) entonces<br />

regresar -1.<br />

sino<br />

Establecer mitad = (primero + ultimo) / 2.<br />

si (A[mitad] == elemento) entonces<br />

regresar mitad.<br />

sino<br />

si (el elemento está en la primera mitad) entonces<br />

busquedaBin(A, elemento, primero, mitad - l)<br />

sino<br />

busquedaBin(A, elemento, mitad + 1, ultimo)<br />

FIN.<br />

Es evidente ahora que el algoritmo realiza la recursividad, porque se puede ver la función llamándose a sí<br />

misma en uno o dos lugares, dependiendo de en qué mitad del arreglo dividido es probable que se encuentre<br />

el elemento. También, observe en dónde se verifican los dos casos primitivos. Si, al inicio de una llamada<br />

recursiva, primero > ultimo, el elemento no está en el arreglo y las llamadas recursivas terminan. Además,<br />

si después de calcular mitad, se encuentra el elemento en A[mitad], terminará la llamada recursiva. En<br />

ambos casos, la función ha terminado su ejecución y regresa un valor al programa llamador. Lo último que<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-54


MIGUEL Á. TOLEDO MARTÍNEZ<br />

necesita el algoritmo es una forma para determinar si el elemento que se busca es muy probable que se<br />

encuentre en la primera mitad o en la segunda mitad del arreglo dividido. Aquí es donde viene el<br />

requerimiento para un arreglo ordenado. Si el arreglo está ordenado, es muy probable que el elemento se<br />

encuentre en la primera mitad del arreglo cuando elemento < A[mitad]; de otra manera, es muy probable<br />

que el elemento se encuentre en la segunda mitad del arreglo. Observe que usamos el término es muy<br />

probable. Nosotros no podemos garantizar que el elemento se encuentre en cualquier mitad, ¡ya que,<br />

inclusive, podría no estar en el arreglo! Todo lo que se puede hacer es dirigir la búsqueda a la mitad<br />

donde es muy probable que se encuentre el elemento, dependiendo del orden de clasificación de los<br />

elementos. Por lo tanto, se puede completar el algoritmo usando esta idea. Aquí está el algoritmo final:<br />

Algoritmo busquedaBin()<br />

busquedaBin(A, elemento, primero, ultimo)<br />

INICIO<br />

si(primero > ultimo) entonces<br />

regresar -1.<br />

sino<br />

Establecer mitad = (primero + ultimo) / 2.<br />

si (A[mitad] == elemento) entonces<br />

regresar mitad.<br />

sino<br />

si (elemento < A[mitad]) entonces<br />

busquedaBin(A, elemento, mitad - l).<br />

sino<br />

busquedaBin(A, elemento, mitad + 1, ultimo)<br />

FIN.<br />

Observe qué elegante es el algoritmo. Por elegante se debe entender que más que un proceso complicado<br />

de búsqueda binaria, se trata de sólo unos cuantos enunciados. Se sabe que hay mucho por recorrer todavía,<br />

pero la recursividad permite expresar todo este procedimiento en sólo unos cuantos enunciados. Como<br />

puede ver, a menudo los algoritmos recursivos proporcionan soluciones simples a problemas de gran<br />

complejidad, en donde una solución iterativa equivalente puede ser compleja. Éste no es siempre el caso,<br />

porque algunas soluciones recursivas son relativamente poco prácticas para la eficiencia de velocidad y de<br />

memoria. Recuerde la siguiente regla cuando considere la recursividad: considere una solución recursiva<br />

para un problema sólo cuando no sea posible una solución iterativa sencilla. Tome en cuenta que la<br />

búsqueda binaria tiene una solución iterativa relativamente sencilla. Se codificará esta solución para uno de<br />

los problemas al final de esta lección.<br />

CODIFICACIÓN <strong>DE</strong>L PROGRAMA<br />

La función que requiere C++ ahora se puede codificar con facilidad a partir del algoritmo final. Como<br />

sigue:<br />

int busquedaBin(int[A], int elemento, int primero, int ultimo)<br />

{<br />

int mitad; // PUNTO MEDIO <strong>DE</strong>L ARREGLO<br />

if (primero > ultimo) // SI EL ELEMENTO NO ESTÁ EN EL ARREGLO<br />

return -l; // REGRESA -1, SI NO CONTINÚA <strong>LA</strong> BÚSQUEDA<br />

else<br />

{<br />

mitad = (primero + ultimo) / 2; // ENCUENTRA EL PUNTO<br />

// MEDIO <strong>DE</strong>L ARREGLO<br />

if (elemento == A[mitad]) // Si EL ELEMENTO ESTÁ EN<br />

// A[mitad]<br />

return mitad; // REGRESA mitad<br />

else // Si NO, BUSCA <strong>LA</strong> MITAD APROPIADA<br />

if (elemento < A[mitad])<br />

return busquedaBin(A, elemento, primero, mitad - l);<br />

else<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-55


MIGUEL Á. TOLEDO MARTÍNEZ<br />

return busquedaBin(A, elemento, mitad + 1, ultimo);<br />

} / /FINAL <strong>DE</strong> else EXTERNO<br />

} // FINAL <strong>DE</strong> busquedaBin()<br />

No deberá tener ningún problema para comprender este código, ya que refleja la interfaz de la función y<br />

al algoritmo que se desarrolló. Aquí la única diferencia es que las llamadas recursivas en busquedaBin()<br />

forman parte de un enunciado return. Recuerde que C++ requiere que todos los caminos de ejecución de<br />

una función sin void den origen a un enunciado return.<br />

Ejemplo <strong>18</strong>.36<br />

El siguiente programa, BÚSQUEDA.CPP, ilustra los métodos de búsqueda lineal y binaria. Es bastante<br />

interesante la solución que se propone, por lo que se le pide al lector que lea con detenimiento la<br />

codificación.<br />

/* El siguiente programa: BUSQUEDA.CPP, busca en arreglos usando los métodos de búsqueda lineal<br />

y binaria.<br />

*/<br />

#include <br />

#include <br />

#include <br />

typedef int (*funcBusqueda)(int,int[],int);<br />

const int MIN = 2;<br />

const int MAX = 10;<br />

const int NO_ENCONTRADO = -1;<br />

// Pide al usuario la cantidad de elementos del arreglo<br />

int obtenNumPuntos(int minimo, int maximo)<br />

{<br />

int numPuntos;<br />

do<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

{<br />

for (int i = 0; i < num; i++)<br />

{<br />

cout.width(5);<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Ejemplo <strong>18</strong>.37<br />

while (debeBuscar(tipoBusqueda))<br />

{<br />

cout > valorBuscar;<br />

index = buscar(valorBuscar, intArr, num);<br />

if (index != NO_ENCONTRADO)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

// Compara dos enteros<br />

int cmpEnt(const void *item1, const void *item2)<br />

{<br />

return *(int*)item1 - *(int*)item2;<br />

}//Fin de cmpEnt()<br />

// Pide al usuario el número de elementos del arreglo<br />

int obtenNumPuntos(int minimo, int maximo)<br />

{<br />

int numPuntos;<br />

do<br />

{<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

}//Fin de busquedaBinaria()<br />

// Verificar la continuidad de búsqueda<br />

bool debeBuscar(const char *tipoBusqueda)<br />

{<br />

char ch;<br />

cout valorBuscar;<br />

indice = buscar(valorBuscar, intArr, num);<br />

if (indice)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

INICIACIÓN <strong>DE</strong> ARREGLOS<br />

Antes de terminar esta lección, es necesario saber cómo inicializar los arreglos en el<br />

momento en que se definen. Los arreglos, como las variables, se pueden inicializar cuando se<br />

crean. Se pueden suministrar valores de iniciación para cualquier arreglo, mientras esté definido<br />

en el programa. Consideremos algún ejemplo de definición de arreglo para mostrar cómo se<br />

inicializan los arreglos.<br />

int enteros[3] = {10,20,30};<br />

En esta definición, se ha presentado un arreglo entero de tres elementos. Los tres<br />

elementos enteros se han inicializado con los valores 10, 20 y 30, respectivamente. Observe la<br />

sintaxis. La definición del arreglo es seguida por un operador de asignación, al cual le suceden<br />

los valores de inicialización encerrados dentro de llaves. Esto es lo que verá si inspecciona al<br />

arreglo usando un depurador (debugger):<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de enteros<br />

[0] 10<br />

[1] 20<br />

[2] 30<br />

Como puede ver, el primer valor de inicialización, 10, se coloca en el índice 0 del<br />

arreglo; el valor 20 se coloca en el índice 1; y el valor 30 se coloca en la última posición del<br />

índice, que es 2. Ahora, ¿qué se supone que sucedería si proporcionara menos valores de<br />

inicialización que las posiciones en el arreglo? Bueno, suponga que define al arreglo como<br />

sigue:<br />

int enteros[3] = {10,20};<br />

Enseguida se presenta lo que encontrará cuando inspeccione al arreglo usando un<br />

depurador:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de enteros<br />

[0] 10<br />

[1] 20<br />

[2] 00<br />

Como puede observar, el compilador inicializó la última posición del arreglo con cero.<br />

Cero es el valor de iniciación predeterminado para arreglos de enteros cuando no se<br />

proporcionan suficientes valores para llenar al arreglo.<br />

La siguiente pregunta obvia es: ¿qué sucede si proporciona demasiados valores de<br />

iniciación? Por ejemplo, suponga que define el arreglo como sigue:<br />

int enteros[3] = {10,20,30,40};<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-61


MIGUEL Á. TOLEDO MARTÍNEZ<br />

En este caso, se obtendrá un error de compilación, demasiados inicializadores (too many<br />

initializers) Una forma de solucionar este problema es incrementar el tamaño del arreglo. Otra<br />

forma preferida, es definir al arreglo sin ningún tamaño específico, como sigue:<br />

int enteros[] = {10,20,30,40};<br />

Con esta definición, el compilador establecerá suficiente lugar de almacenamiento para<br />

contener todos los valores de inicialización. Aquí está lo que verá si inspecciona esta definición<br />

de arreglo usando un depurador:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de enteros<br />

[0] 10<br />

[1] 20<br />

[2] 30<br />

[3] 40<br />

Ahora, vamos a considerar arreglos de caracteres. Suponga que define un arreglo de<br />

caracteres de tamaño cinco, como éste:<br />

char caracteres[5] = {‘H’, ‘E’, ‘L’, ‘L’, ‘O’}<br />

De nuevo se ve que los valores de inicio se encierran en llaves después de un operador de<br />

asignación. Esto mostrará el depurador:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de caracteres<br />

[0] ‘H’<br />

[1] ‘E’<br />

[2] ‘L’<br />

[3] ‘L’<br />

[4] ‘O’<br />

Aquí se ve que los cinco caracteres de inicio se colocan en el arreglo empezando en el<br />

índice cero y finalizando en la última posición del índice, cuatro. ¿Qué pasa si proporciona<br />

unos cuantos caracteres de iniciación menos que los requeridos para llenar el arreglo?<br />

Bueno, suponga que define el arreglo de esta forma:<br />

char caracteres[5] = {'H','E'};<br />

El contenido del arreglo ahora será corno sigue:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de caracteres<br />

[0] ‘H’<br />

[1] ‘E’<br />

[2] ‘\0’<br />

[3] ‘\0’<br />

[4] ‘\0’<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-62


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Esta vez, el compilador ha insertado un carácter terminador nulo como un carácter<br />

predeterminado para llenar el arreglo. De otra manera, si proporciona demasiados caracteres,<br />

el compilador generará un mensaje de error demasiados inicializadores. De nuevo, la forma<br />

segura para manejar este problema es dejar que el compilador determine el tamaño del arreglo<br />

para ajustar el número de valores inicializados.<br />

Por último, vamos a considerar cómo se inicializa el arreglo de caracteres con valores de<br />

cadenas. Recuerde, una cadena no es más que un arreglo de caracteres, terminada con un<br />

terminador nulo. Así es como se puede inicializar un arreglo de caracteres con un valor de<br />

cadena:<br />

char caracteres[6] = "HELLO";<br />

Observe que la sintaxis es diferente. La cadena de iniciación deberá encerrarse entre<br />

comillas más que entre llaves. Otra cosa que se ve es que el tamaño del arreglo es uno más<br />

grande que el número de caracteres en la cadena. La razón para esto parece obvia cuando<br />

inspecciona el arreglo usando un depurador. Aquí esta lo que verá:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de caracteres<br />

[0] ‘H’<br />

[1] ‘E’<br />

[2] ‘L’<br />

[3] ‘L’<br />

[4] ‘O’<br />

[5] ‘\0’<br />

Recuerde que una cadena terminará con un terminador nulo. Al hacer el tamaño del<br />

arreglo uno más grande que el número de caracteres en la cadena, permite espacio para que el<br />

compilador inserte el terminador nulo. Si no se deja espacio para el terminador nulo, éste<br />

quedará truncado (eliminado) del arreglo y no se obtendrá un mensaje de error. De nuevo, la<br />

mejor manera de evitar este problema es permitir que el compilador determine el tamaño del<br />

arreglo, como éste:<br />

char caracteres[] = "HELLO";<br />

Con esta definición, el compilador creará suficientes posiciones en el arreglo para<br />

contener todos los caracteres de cadenas con el terminador nulo insertado como el último<br />

carácter en el arreglo.<br />

INICIACIÓN PRE<strong>DE</strong>TERMINADA <strong>DE</strong> ARREGLOS GLOBALES Y ESTÁTICOS<br />

Se pueden definir e inicializar arreglos en cualquier parte del programa C++. El ámbito<br />

de un arreglo funciona justo como el ámbito de una variable o constante. Un arreglo definido<br />

antes de main() es visible en todo el archivo fuente en el cual se define. Un arreglo definido<br />

dentro de un bloque tiene ámbito de bloque y, por lo tanto, es visible sólo dentro del bloque en<br />

el cual se define.<br />

Si se define un arreglo en forma global o como un arreglo estático y no se proporciona<br />

ningún valor de inicialización, el compilador inicializará el arreglo con el valor predeterminado<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-63


MIGUEL Á. TOLEDO MARTÍNEZ<br />

respectivo (ceros para arreglos de enteros y de punto flotante y terminadores nulos para arreglos<br />

de caracteres) El siguiente es un ejemplo:<br />

int enteros[5];<br />

void main(void)<br />

{<br />

static char caracteres[5];<br />

} // FINAL <strong>DE</strong> main()<br />

Se ha definido en forma global el arreglo enteros y también como un arreglo estático<br />

local al arreglo caracteres dentro de main() La inspección de estos arreglos con un depurador<br />

revelará lo siguiente:<br />

RESULTADOS <strong>DE</strong>L <strong>DE</strong>PURADOR<br />

Inspección de enteros Inspección de caracteres<br />

[0] 0 [0] ‘\0’<br />

[1] 0 [1] ‘\0’<br />

[2] 0 [2] ‘\0’<br />

[3] 0 [3] ‘\0’<br />

[4] 0 [4] ‘\0’<br />

El depurador muestra que el arreglo global de enteros se ha inicializado con ceros,<br />

mientras que el arreglo de caracteres estático se ha inicializado con caracteres de terminador<br />

nulo. Si define un arreglo con ámbito de bloque local que no es estático y no lo inicializa, el<br />

compilador no suministrará ningún valor de inicialización predeterminado. ¡El arreglo<br />

contendrá basura! De esta manera, si elimináramos la palabra clave static de la definición<br />

anterior del arreglo caracteres, el depurador revelará valores arbitrarios de memoria en el<br />

arreglo.<br />

Aquí está un resumen de la explicación anterior:<br />

• Los arreglos de enteros, de punto flotante y de caracteres se inicializan por medio de un<br />

operador de asignación después de la definición del arreglo, seguido por una lista de valores<br />

individuales de inicialización dentro de llaves.<br />

• Menos valores de iniciación darán como resultado valores predeterminados (ceros para<br />

arreglos de enteros y de punto flotante y terminadores nulos para arreglos de caracteres)<br />

insertados en las posiciones adicionales del arreglo.<br />

• Más valores de iniciación provocan un error de compilación.<br />

• Los arreglos de caracteres se pueden inicializar encerrando una cadena con comillas dobles.<br />

• El tamaño de un arreglo de cadena deberá ser uno más grande que el número de caracteres<br />

dentro de la cadena para dejar espacio para el carácter terminador nulo.<br />

• Si no se especifica un tamaño en la definición del arreglo, el compilador creará el suficiente<br />

espacio de almacenaje para los valores de inicialización.<br />

• Los arreglos globales y arreglos estáticos se inicializan siempre con los valores<br />

predeterminados respectivos cuando ningún valor de iniciación se suministra en la definición<br />

del arreglo.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-64


MIGUEL Á. TOLEDO MARTÍNEZ<br />

• Los arreglos locales que no son estáticos no se inicializarán con ningún valor específico, a<br />

menos que se proporcionen en la definición del arreglo.<br />

ARREGLOS QUE REBASAN LOS 64 KBYTES <strong>DE</strong> MEMORIA<br />

Si un arreglo rebasa los 64 kbytes de longitud, el mismo enviará un mensaje de error<br />

(Array size too large) en tiempo de compilación.<br />

Ejemplo <strong>18</strong>.38<br />

Ejemplo <strong>18</strong>.39<br />

EXAMEN BREVE 38<br />

El siguiente programa, <strong>DE</strong>MG<strong>DE</strong>.CPP, ilustra esta situación.<br />

/* El siguiente programa: <strong>DE</strong>MG<strong>DE</strong>.CPP, no se compila correctamente ya que el<br />

arreglo utiliza mas de 64 kbytes de memoria.<br />

*/<br />

void main(void)<br />

{<br />

char cadena[66000L]; // 66,000 bytes<br />

int valores[33000L]; // 33,000 * 2 = 66,000 bytes<br />

float numeros[17000]; // 17,000 * 4 = 68,000 bytes<br />

}//Fin de main()<br />

El siguiente programa ENORME.CPP, ilustra como resolver esta situación.<br />

/* El siguiente programa: ENORME.CPP crea un arreglo de más de 64 kbytes<br />

de datos de punto flotante.<br />

*/<br />

#include //Para cout y cin<br />

#include //Para halloc()<br />

void main (void)<br />

{<br />

int i;<br />

float huge *valores;<br />

if ((valores = (float huge *) halloc (17000, sizeof(float))) == NULL)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

}//Fin de main()<br />

LO QUE NECESITA SABER<br />

for (i = 0; i < 17000; i++)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Es posible utilizar un arreglo de clase char para almacenar una cadena de caracteres.<br />

Los elementos de un arreglo pueden inicializarse por declaración, por asignación o por<br />

entrada.<br />

Si hay menos inicializadores que elementos en el arreglo, los elementos restantes se<br />

inicializan a cero.<br />

C++ no evita que se haga referencia a elementos que estén fuera de los límites de un<br />

arreglo.<br />

Es posible inicializar un arreglo de caracteres por medio de una literal de cadena.<br />

Todas las cadenas terminan con el carácter nulo (‘\0’)<br />

Los arreglos de caracteres se pueden inicializar con constantes de carácter en una lista<br />

de iniciación.<br />

Es posible acceder a los caracteres de una cadena almacenada en un arreglo por medio<br />

de la notación de índices.<br />

Para pasar un arreglo a una función, hay que pasar su nombre. Para pasar un solo elemento<br />

del arreglo a una función, simplemente hay que pasar el nombre del arreglo seguido por el<br />

índice (entre corchetes cuadrados) de dicho elemento.<br />

Los arreglos se pasan a las funciones simulando una llamada por referencia; las<br />

funciones llamadas pueden modificar los valores de los elementos de los arreglos originales.<br />

El nombre del arreglo es la dirección de su primer elemento. Debido a que se pasa la dirección<br />

de inicio del arreglo, la función llamada sabe exactamente dónde está almacenado dicho<br />

arreglo.<br />

Para recibir un arreglo como argumento, la lista de parámetros de la función debe<br />

especificar que se recibirá un arreglo. No es necesario el tamaño del arreglo entre los<br />

corchetes.<br />

Cuando una función recibe un arreglo como parámetro, la función debe especificar la<br />

clase del arreglo y su nombre, pero no el tamaño del arreglo.<br />

C++ tiene el calificador de clase const, que permite a los programas evitar la modificación,<br />

en una función, de los valores de un arreglo. Cuando un parámetro de arreglo está precedido<br />

por el calificador const, los elementos del arreglo se vuelven constantes en el cuerpo de la<br />

función y cualquier intento por modificarlos provoca un error de sintaxis.<br />

La búsqueda y ordenación son operaciones comunes realizadas sobre arreglos.<br />

Los arreglos pueden ordenarse mediante la técnica de ordenamiento de burbuja. Se<br />

realizan varias pasadas al arreglo. Con cada pasada se comparan los pares consecutivos de los<br />

elementos. Si un par está ordenado (o sus valores son idénticos), se deja tal cual. Si está fuera<br />

de orden, se intercambian. El ordenamiento de la burbuja es aceptable en los arreglos<br />

pequeños, pero en los mayores es ineficiente en comparación con otros algoritmos de<br />

ordenamiento más complejos.<br />

La búsqueda secuencial es una búsqueda iterativa que busca un valor dado en un arreglo,<br />

comparando en forma secuencial el valor con los elementos del arreglo, empezando con el<br />

primer elemento del arreglo, hasta que se encuentra el valor en el arreglo o hasta que se<br />

alcanza el final del arreglo.<br />

La búsqueda lineal compara todos los elementos de un arreglo con la clave de búsqueda. Si el<br />

arreglo no está en ningún orden en particular, existe la misma probabilidad de que el valor se<br />

encuentre en el primer elemento como que esté en el último. Por lo tanto, en promedio, el<br />

programa tendrá que comparar la clave de búsqueda con la mitad de los elementos del arreglo.<br />

El método de búsqueda lineal funciona bien con los arreglos pequeños y es aceptable si se<br />

trata de arreglos desordenados.<br />

Una búsqueda binaria puede ser iterativa o recursiva. Una búsqueda binaria divide el arreglo<br />

en mitades, dirigiéndose a sí misma hacia la mitad en donde es muy probable que se encuentre<br />

el valor.<br />

La búsqueda binaria requiere que el arreglo esté ordenado, mientras que la búsqueda<br />

secuencial no tiene este requerimiento.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-67


MIGUEL Á. TOLEDO MARTÍNEZ<br />

Por otra parte, la búsqueda binaria es mucho más rápida que la secuencial, especialmente en<br />

grandes arreglos ordenados.<br />

La búsqueda binaria elimina de su consideración la mitad de los elementos del arreglo tras<br />

cada comparación; esto lo logra localizando el elemento central del arreglo y comparándolo<br />

con la clave de búsqueda. Si son iguales, entonces se encuentra la clave de búsqueda y se<br />

devuelve el índice de dicho elemento. De otra manera, se reduce el problema a la búsqueda en<br />

una mitad del arreglo.<br />

En el peor caso, la búsqueda en un arreglo de 1024 elementos sólo necesitaría 10<br />

comparaciones y se efectúa mediante búsqueda binaria.<br />

Muchas aplicaciones en el mundo real requieren que la información esté ordenada. Hay<br />

algunos algoritmos de clasificación comunes, incluyendo clasificación por inserción,<br />

clasificación por burbuja, clasificación por selección y clasificación rápida.<br />

Todos estos algoritmos operan sobre arreglos. El algoritmo de clasificación por inserción<br />

es un proceso iterativo que inserta un elemento dado en el arreglo en su lugar correcto relativo<br />

a los elementos que lo preceden en el arreglo. Usted se familiarizará con la clasificación de<br />

burbuja y la clasificación de selección en los problemas de esta lección.<br />

PREGUNTAS Y PROBLEMAS<br />

PREGUNTAS<br />

1. Llene los siguientes espacios en blanco:<br />

a. Las listas y tablas de valores se guardan en ________________________.<br />

b. Los elementos de un arreglo se relacionan por el hecho de que tienen el mismo __________ y<br />

_____________.<br />

c. El número con el que se hace referencia a un elemento en particular de un arreglo se llama<br />

_____________.<br />

d. Debe usarse una _______________ para declarar el tamaño de un arreglo, pues hace más escalable el<br />

programa.<br />

e. El proceso de colocar en orden los elementos en un arreglo se llama _______________ del arreglo.<br />

f. El proceso con el que se determina si un arreglo contiene cierto valor clave se llama ____________.<br />

g. C++ almacena las listas de valores en _________________.<br />

h. Al referirse a un elemento de un arreglo, el número de posición contenido entre paréntesis se llama<br />

_____________.<br />

i. Los nombres de los cuatro elementos del arreglo p son __________, _____________, _________ y<br />

___________.<br />

j. La denominación de un arreglo, indicación de su clase y especificación de la cantidad de elementos que<br />

hay en él se llama _____________ del arreglo.<br />

k. El proceso de colocación de los elementos de un arreglo en orden ascendente o descendente se llama<br />

_____________.<br />

2. Indique si las siguientes oraciones son falsas o verdaderas. Si la respuesta es falso explique por qué.<br />

a. Un arreglo puede contener diferentes clases de valores.<br />

b. Los índices de los arreglos normalmente deben de ser de clase float.<br />

c. Si hay menos inicializadores en una lista de iniciación que el número de elementos que hay en el<br />

arreglo, los elementos restantes se inicializan automáticamente al último valor de dicha lista.<br />

d. Es un error que una lista de iniciación contenga más inicializadores que la cantidad de elementos que<br />

hay en el arreglo.<br />

e. Un elemento de un arreglo que se pasa a una función y se modifique ahí contendrá el valor modificado<br />

cuando termine la ejecución de la función llamada.<br />

f. Para hacer referencia a una localidad particular o elemento de un arreglo, se especifica el nombre del<br />

arreglo y el valor del elemento.<br />

g. Una declaración de arreglo reserva espacio para el arreglo.<br />

h. Para indicar que se deben reservar 100 localidades para el arreglo de enteros p, el programador<br />

escribirá la declaración<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-68


MIGUEL Á. TOLEDO MARTÍNEZ<br />

p[100];<br />

i. Un programa C++ que inicialice a 0 los elementos de un arreglo de 15 elementos debe contener cuando<br />

menos una instrucción for.<br />

3. Conteste las siguientes preguntas relacionadas con un arreglo llamado fracciones.<br />

a. Defina una variable constante tamanoArreglo que se inicialice a 10.<br />

b. Declare un arreglo con elementos tamanoArreglo de la clase float e inicialice dichos elementos a 0.<br />

c. Nombre el cuarto elemento a partir del inicio del arreglo.<br />

d. Haga referencia al elemento 4.<br />

e. Asígnele el valor 1.667 al elemento 9.<br />

f. Asígnele el valor 3.333 al séptimo elemento del arreglo.<br />

g. Imprima los elementos 6 y 9 del arreglo con una precisión de dos dígitos a la derecha del punto decimal y<br />

muestre la salida que se desplegará en la pantalla.<br />

h. Imprima todos los elementos del arreglo mediante una estructura de repetición for. Defina la variable<br />

entera x como la variable de control del ciclo. Muestre la salida.<br />

4. Encuentre los errores en los siguientes segmentos de programa y corríjalos.<br />

a. #include ;<br />

b. tamanoArreglo = 10; //tamanoArreglo se declaró como const<br />

c. Suponga que int b[10] = {0};<br />

5.<br />

for(int i = 0; i


MIGUEL Á. TOLEDO MARTÍNEZ<br />

16. Escriba un enunciado para definir un arreglo de punto flotante que se inicializará con ceros y es local para<br />

main()<br />

17. ¿Dónde está el error en la siguiente definición del arreglo?<br />

<strong>18</strong>. Dada la siguiente definición de arreglo,<br />

int números[4] = {0,1,2,3,4};<br />

int valores[10];<br />

a. Escriba un enunciado para colocar el producto del primero y segundo elementos de arreglo en la<br />

posición del último elemento.<br />

Use la siguiente definición de arreglo para contestar las preguntas 19 - 23:<br />

const int MAX = 4;<br />

char cadena[MAX] =“C++”;<br />

19. Escriba el prototipo para una función de nombre longitudCadena() que recibirá el arreglo completo y<br />

regresa la longitud de la cadena.<br />

20. Escriba un prototipo para una función de nombre elementoCadena() que recibirá un elemento sencillo de la<br />

cadena, de manera que cualquier operación sobre ese elemento dentro de la función no afectará el valor del<br />

elemento dentro del arreglo.<br />

21. Escriba un enunciado para llamar la función de la pregunta 19 y pase el primer elemento del arreglo a la<br />

función.<br />

22. Escriba un prototipo para una función de nombre cambiaElemento() que recibirá un solo elemento de la<br />

cadena, de manera que cualquier modificación en este elemento dentro de la función cambie el valor del<br />

elemento en el arreglo.<br />

23. Escriba un enunciado para llamar a la función de la pregunta 22 y pase el último elemento del arreglo a la<br />

función.<br />

24. En general, ¿qué posición del elemento se regresará por medio de las funciones de búsqueda secuencial y<br />

binaria desarrolladas en esta lección, si un elemento se presenta varias veces en el arreglo?<br />

25. ¿Por qué, en promedio, es más rápida la búsqueda binaria que la secuencial?<br />

26. ¿Cuándo es más rápida la búsqueda secuencial que la binaria?<br />

27. Revise el algoritmo clasifPorInser() para ordenar el arreglo de modo descendente.<br />

PROBLEMAS<br />

1. Escriba un programa para llenar un arreglo con todos los enteros impares desde 1 hasta 99. Escriba una<br />

función para llenar el arreglo y otra para mostrar éste, desplegando en la pantalla los enteros impares<br />

separados por comas.<br />

2. Escriba una función para leer el nombre del usuario desde la entrada del teclado y colóquelo en un arreglo<br />

de caracteres. Escriba otra función para mostrar el nombre del usuario almacenado en el arreglo. Verifique<br />

sus funciones por medio de un programa de aplicación.<br />

3. Escriba un programa para leer una lista de 25 elementos de caracteres desde una entrada de teclado y<br />

muéstrelos en orden inverso. Use una función para llenar la lista con los elementos escritos y otra para<br />

mostrarla.<br />

4. Escriba un programa que use seis arreglos de caracteres para almacenar el nombre del usuario, domicilio,<br />

ciudad, estado, código postal y número telefónico. Proporcione una función para llenar los arreglos y<br />

otra para mostrar el contenido del arreglo usando un formato de direccionamiento apropiado.<br />

5. (La coladera de Eratóstenes) Un entero primo es cualquier entero que es divisible sólo entre él mismo y<br />

entre 1. La coladera de Eratóstenes es un método para encontrar números primos. Opera como sigue:<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-70


MIGUEL Á. TOLEDO MARTÍNEZ<br />

a) Cree un arreglo con todos los elementos inicializados a 1 (verdadero) Los elementos del arreglo que<br />

tengan índices primos permanecerán en 1. Los demás elementos del arreglo en algún momento se<br />

establecerán a cero.<br />

b) Comenzando por índice 2 (el índice 1 debe ser primo), cada vez que se encuentre un elemento del<br />

arreglo que sea 1, haga un ciclo por el resto del arreglo y establezca a cero todos los elementos cuyo<br />

índice sea un múltiplo de dicho índice. Para el índice 2, todos los elementos por encima de 2 que sean<br />

múltiplos de 2 se establecerán a cero (los índices 4, 6, 8, 10, etc.); en el caso del índice 3, todos los<br />

elementos por encima de 3 que sean múltiplos de 3 se establecerán a cero (índices 6, 9, 12, 15, etc.); y<br />

así sucesivamente.<br />

Terminado este proceso, los elementos del arreglo que aún estén establecidos a 1 indicarán que el índice<br />

es un número primo, así que podrán imprimirse. Escriba un programa con un arreglo de 1000<br />

elementos que determine e imprima los números primos entre 1 y 999. Ignore el elemento 0 del<br />

arreglo.<br />

6. Por medio de un arreglo de un solo índice resuelva el siguiente problema. Una compañía paga a sus<br />

vendedores con base en una comisión. Los vendedores reciben $200 a la semana más 9% de sus ventas<br />

netas durante la semana. Por ejemplo, un vendedor cuyas ventas brutas son de $5000, a la semana recibe<br />

$200 más 9% de $5000, es decir un total de $650. Escriba un programa (con un arreglo de contadores) que<br />

determine la cantidad de vendedores que ganaron salarios dentro de los siguientes rangos (suponga que el<br />

salario de cada vendedor se cierra a una cifra entera):<br />

a) $200 - $299<br />

b) $300 - $399<br />

c) $400 - $499<br />

d) $500 - $599<br />

e) $600 - $699<br />

f) $700 - $799<br />

g) $800 - $899<br />

h) $900 - $999<br />

i) $1000 o más<br />

7. El ordenamiento por el método de la burbuja elaborado en el ejemplo <strong>18</strong>.26. es ineficiente en el caso de<br />

arreglos grandes. Haga las siguientes modificaciones sencillas que mejorarán el desempeño del<br />

ordenamiento de burbuja.<br />

a) Después de la primera pasada, se garantiza que la cifra mayor es el elemento de mayor índice del<br />

arreglo, tras la segunda pasada, los dos números mayores están en su lugar, etc. En lugar de hacer<br />

nueve comparaciones con cada pasada, modifique el ordenamiento de burbuja para que efectúe ocho<br />

comparaciones en la segunda pasada, siete en la tercera, etc.<br />

b) Los datos en el arreglo tal vez ya estén en el orden adecuado, o casi, así que ¿por qué hacer nueve<br />

pasadas si tal vez baste con menos? Modifique el ordenamiento para comprobar al final de cada pasada<br />

si se han hecho intercambios. Si no ha sucedido ninguno, entonces los datos ya estarán en orden y<br />

deberá terminar el programa. Si han sucedido intercambios, entonces se necesita cuando menos otra<br />

pasada.<br />

8. Escriba instrucciones que lleven a cabo las siguientes operaciones sobre arreglos de un solo índice. Debe ser<br />

una sola instrucción por cada una.<br />

a) Inicialice a cero los 10 elementos del arreglo de enteros contador.<br />

b) Sume 1 a cada uno de los 15 elementos del arreglo de enteros bonos.<br />

c) Lea del teclado 12 valores para el arreglo float temperaturaMensual.<br />

d) Imprima los 5 valores del arreglo de enteros mejoresCalificaciones en formato de columnas<br />

9. Encuentre el error o los errores en las siguientes instrucciones:<br />

a) Suponga que: char cadena[5];<br />

cin >> cadena; //El usuario teclea bello<br />

b) Suponga que: int a[3];<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

c) float f[3] = {1.1, 10.01, 100.001, 1000.0001};<br />

10. Modifique el ejemplo <strong>18</strong>.32 para que la función moda() pueda manejar empates en el valor de la moda.<br />

También modifique la función mediana() de modo que se promedien los dos elementos centrales cuando se<br />

trate de un arreglo con un número par de elementos.<br />

11. Con un arreglo de un solo índice resuelva el siguiente problema. Lea 20 números entre 10 y 100, inclusive. A<br />

medida que se lea cada número, imprímalo sólo si no es un duplicado de algún número ya leído. Tome en<br />

cuenta el peor caso, cuando todos los números son diferentes. Resuelva este problema empleado el arreglo<br />

más pequeño posible.<br />

12. Escriba un programa que simule el lanzamiento de dos dados. El programa deberá valerse de rand() para<br />

lanzar el primer dado y nuevamente rand() para lanzar el segundo. Luego debe calcular la suma de ambos<br />

valores. Nota: debido a que cada dado puede tener un valor entero de 1 a 6, entonces la suma de ambos<br />

valores variará de 2 a 12, siendo 7 la suma más frecuente y 2 y 12 las menos frecuentes. La figura <strong>18</strong>.5<br />

muestra las 36 combinaciones de dados posibles. Su programa deberá lanzar ambos dados 36,000 veces.<br />

Mediante un arreglo de un solo índice, registre la cantidad de veces que aparece cada suma. Imprima el<br />

resultado en formato de tabla. Además determine si los totales son razonables, es decir, hay seis maneras de<br />

lanzar 7, por lo que aproximadamente una sexta parte de los lanzamientos debe ser 7.<br />

1 2 3 4 5 6<br />

1 2 3 4 5 6 7<br />

2 3 4 5 6 7 8<br />

3 4 5 6 7 8 9<br />

4 5 6 7 8 9 10<br />

5 6 7 8 9 10 11<br />

6 7 8 9 10 11 12<br />

Figura <strong>18</strong>.5. Las 36 posibles combinaciones de lanzamiento de dos dados.<br />

13. ¿Qué hace el siguiente problema?<br />

// Nombre del programa: PROBLEMA11.CPP<br />

#include <br />

int queEsEsto(int[], int);<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 10;<br />

int a[TAMANO_ARREGLO] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};<br />

}<br />

int resultado = queEsEsto(a, TAMANO_ARREGLO);<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

d) ¿cuál es la duración promedio de un juego de dados?<br />

e) ¿Mejoran las posibilidades de ganar a medida que aumenta la duración del juego?<br />

15. (Sistema de reservaciones de una aerolínea) Una línea aérea pequeña acaba de comprar una computadora para<br />

su nuevo sistema automatizado de reservaciones. Se le ha pedido a usted que programa este sistema. Deberá<br />

escribir un programa que asigne asientos en cada vuelo del único avión de la compañía (capacidad: 10<br />

asientos)<br />

Su programa deberá presentar el siguiente menú de alternativas:<br />

Por favor teclee 1 para fumar.<br />

Por favor teclee 2 para no fumar.<br />

Si se teclea 1, el programa deberá asignar un asiento en la sección de fumadores (asientos 1 a 5) Si se<br />

teclea 2, se asignará un asiento en la sección de no fumar (asientos 6 a 10). El programa deberá imprimir un<br />

pase de abordar que indique el número de asiento del pasajero y si se trata de la sección de fumar o de no<br />

fumar.<br />

Mediante un arreglo de un solo índice, represente la gráfica de asientos del avión. Inicialice a cero todos<br />

los elementos del arreglo, indicando que todos los asientos están vacíos. A medida que se asigne un asiento,<br />

establezca a 1 el elemento correspondiente, indicando que ya no está disponible.<br />

El programa, claro está, no deberá volver a asignar un asiento ya asignado. Cuando la sección de<br />

fumadores esté llena, el programa deberá preguntar si es aceptable asignar un asiendo en la sección de no<br />

fumar (y viceversa) Si la respuesta es sí, entonces haga la asignación. Si no, imprima el mensaje el próximo<br />

vuelo parte en tres horas.<br />

16. ¿Qué hace el siguiente programa?<br />

// PROGRAMA14.CPP<br />

#include <br />

void ciertaFunción(int[], int);<br />

void main(void)<br />

{<br />

const int TAMANO_ARREGLO = 10;<br />

int a[TAMANO_ARREGLO] = {32, 27, 64, <strong>18</strong>, 95, 14, 90, 70, 60, 37};<br />

}<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

srand(1);<br />

for(int l = 0; 1 < 10; ++1)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

medio de la función clasifPorBur() para intercambiar dos elementos del arreglo como se muestra<br />

en el algoritmo. Escriba sus funciones para clasificar un arreglo de caracteres. Incorpórelas dentro<br />

de un programa para que verifique el procedimiento de clasificación. ¿Por qué la clasificación<br />

por burbuja es menos eficiente que la clasificación por inserción?<br />

21. Otro algoritmo de clasificación iterativa común es clasificación por selección. El algoritmo es como éste:<br />

clasifPorSelec()<br />

Inicio<br />

para indice1 = (primer índice del arreglo) hasta (ultimo índice del arreglo) hacer<br />

posición = indice1.<br />

masPequeno = A[Posicion].<br />

para indice2 = (indice1 + 1) hasta (ultimo índice del arreglo) hacer<br />

si A[indice2] < masPequeno<br />

posicion = indice2.<br />

masPequeno = A[posicion].<br />

A[posicion] = A[indice1].<br />

A[indice1] = masPequeno.<br />

Fin.<br />

Como en la clasificación por burbuja, la clasificación por selección realiza diversos pasos a través<br />

del arreglo. En el primero de ellos examina al arreglo completo y coloca los elementos más<br />

pequeños en la primera posición del arreglo. En el segundo paso se examina el arreglo empezando<br />

en el segundo elemento. Se encuentra el elemento más pequeño en el segmento del arreglo y se<br />

coloca en la segunda posición del arreglo. El tercer paso examina el arreglo empezando en el tercer<br />

elemento, encuentra el elemento más pequeño en el segmento del arreglo y lo coloca en la tercera<br />

posición del elemento. El proceso continúa hasta que no quedan más segmentos del arreglo.<br />

Su trabajo es codificar el algoritmo anterior como una función C++ de nombre clasifPorSelec()<br />

Escriba su función para clasificar un arreglo de caracteres. Después úsela en un programa que<br />

verifique el procedimiento de clasificación.<br />

¿Por qué la clasificación por selección es menos eficiente que la clasificación por inserción?<br />

22. Escriba un programa que tome un arreglo entero sin ordenar y encuentre la localización del valor<br />

máximo en el arreglo. (Sugerencia: copie el arreglo dentro de otro y clasifique este segundo arreglo<br />

para determinar su valor máximo. Después busque el arreglo original para este valor)<br />

Problemas de recursividad<br />

23. (Ordenamiento por selección) El ordenamiento por selección busca en un arreglo el elemento más pequeño, el<br />

cual se intercambia con el primero del arreglo. El proceso se repite con el subarreglo que comienza en el<br />

segundo elemento del arreglo. Cada pasada por el arreglo da como resultado la colocación de un elemento en su<br />

lugar correcto. El desempeño de este ordenamiento es comparable con el ordenamiento de burbuja: para un<br />

arreglo de n elementos, se necesita hacer n-1 pasadas y por cada subarreglo, hay que hacer n-1 comparaciones<br />

para encontrar el valor más pequeño. Cuando el subarreglo que se está procesando sólo contiene un elemento, el<br />

arreglo está ordenado. Escriba la función recursiva clasifOrdenamiento()<br />

24. (Palíndromos) Un palíndromo es una cadena que se pronuncia igual hacia delante que hacia atrás. Algunos<br />

ejemplos son: radar, anilina y dábale arroz a la zorra el abad. Escriba una función recursiva<br />

pruebaPalindrome() que devuelva verdadero si la cadena almacenada en el arreglo es un palíndromo y falso si<br />

no. La función deberá ignorar los espacios y la puntuación en la cadena.<br />

25. (Búsqueda lineal) Modifique el ejemplo <strong>18</strong>.33 para que emplee la función recursiva busquedaBinaria() para<br />

llevar a cabo una búsqueda lineal en el arreglo. La función deberá recibir como argumentos un arreglo de<br />

enteros y su tamaño. Si se encuentra la clave de búsqueda, devuelva el índice del arreglo; de otro modo,<br />

devuelva –1.<br />

26. (Búsqueda binaria) Modifique el programa del ejemplo <strong>18</strong>.34 para que utilice una función recursiva<br />

busquedaBinaria() que lleve a cabo una búsqueda binaria en el arreglo. La función deberá recibir como<br />

argumentos un arreglo de enteros y el índice inicial y el final. Si se encuentra la clave de búsqueda, devuelva el<br />

índice del arreglo; de otro modo, devuelva –1.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-75


MIGUEL Á. TOLEDO MARTÍNEZ<br />

27. (Impresión de un arreglo) Escriba una función recursiva imprimirArreglo() que tome como argumentos un<br />

arreglo y su tamaño y no devuelva nada. La función deberá terminar el proceso y regresar cuando reciba un<br />

arreglo de tamaño cero.<br />

28. (Impresión inversa de una cadena) Escriba una función recursiva cadenaInvertida() que tome un arreglo de<br />

caracteres que contenga como argumento una cadena, la imprima al revés y no devuelva nada. La función<br />

deberá terminar el proceso y regresar cuando se encuentre el carácter nulo de terminación.<br />

29. (Encuentre el valor mínimo dentro de un arreglo) Escriba una función recursiva minimoRecursivo() que tome<br />

como argumentos un arreglo de enteros y su tamaño y devuelva su elemento más pequeño. La función deberá<br />

terminar el proceso y regresar cuando reciba un arreglo de 1 elemento<br />

EXAMEN BREVE 34<br />

1. Los dos componentes principales de un arreglo son: ______________ y ___________.<br />

2. Verdadero o falso: Los elementos dentro de un arreglo determinado pueden ser de cualquier<br />

combinación de clase de datos.<br />

EXAMEN BREVE 35<br />

1. Defina un arreglo de nombre registrosDeExamen que almacene hasta 15 registros de exámenes.<br />

2. ¿Cuál es la dimensión del arreglo en la pregunta 1?<br />

3. ¿Cuál es el índice del primer elemento del arreglo en la pregunta 1?<br />

4. ¿Cuál es el índice del último elemento del arreglo en la pregunta 1?<br />

5. Defina un arreglo de nombre esteSemestre que almacene elementos de una clase enumerada de<br />

nombre cursos, que incluya los cursos que usted está tomando este semestre.<br />

6. Suponga que el índice del último elemento en un arreglo es [25] ¿Cuántos elementos almacenará el<br />

arreglo?<br />

EXAMEN BREVE 36<br />

1. Escriba un ciclo for que llene el siguiente arreglo desde la entrada del usuario: char caracteres[15];<br />

2. Escriba un ciclo for que muestre el contenido del arreglo de la pregunta 1.<br />

EXAMEN BREVE 37<br />

1. Verdadero o falso: el nombre del arreglo es la dirección del índice[1] del arreglo.<br />

2. Escriba un prototipo para una función de nombre muestra() que modifique al siguiente arreglo:<br />

char caracteres[15];<br />

Suponga que la función no regresa ningún valor excepto el arreglo modificado.<br />

3. Escriba un prototipo para una función de nombre prueba() que modifique un solo elemento del<br />

arreglo que se definió en la pregunta 2.<br />

4. Escriba un enunciado que llamará a la función prototipo elaborada en la pregunta 3 para modificar<br />

el elemento almacenado en el índice[5] del arreglo definido en la pregunta 2.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-76


MIGUEL Á. TOLEDO MARTÍNEZ<br />

EXAMEN BREVE 38<br />

1. Defina un arreglo e inicialícelo con los valores enteros de -3 hasta +3.<br />

2. ¿Cuál es la dimensión del arreglo que definió en la pregunta 1?<br />

3. Muestre el contenido del siguiente arreglo:<br />

char lenguaje[51 = {‘C’, ‘+’, ‘+’};<br />

4. Muestre el contenido del siguiente arreglo:<br />

char lenguaje[] = " C++";<br />

5. Suponga que define globalmente un arreglo de caracteres sin valores de iniciación. ¿Qué almacena<br />

el compilador en el arreglo?<br />

RESPUESTA EXAMEN BREVE 34<br />

1. Los dos componentes principales de un arreglo son: indice y elemento.<br />

2. Falso: Todos los elementos dentro de un arreglo deben de ser de la misma clase de datos.<br />

1. float registrosDeExamen[15];<br />

RESPUESTA EXAMEN BREVE 35<br />

2. La dimensión del arreglo de la pregunta 1 es 1 ××××15.<br />

3. El índice del primer elemento del arreglo de la pregunta 1 es [0]<br />

4. El índice del último elemento en el arreglo de la pregunta 1 es [14]<br />

5. enum cursos {Computacion, Matematicas, Física, Ingles, Oratoria};<br />

cursos esteSemestre[5];<br />

6. El arreglo almacenará 26 elementos, dado que el primer índice de elemento es [0]<br />

RESPUESTA EXAMEN BREVE 36<br />

1. El ciclo for que se necesita para llenar el arreglo char caracteres[15]; es:<br />

for(int indice = 0; indice < 15; ++indice)<br />

cin >> caracteres[indice];<br />

2. El ciclo for que mostrará el contenido del arreglo anterior es:<br />

for(int indice = 0; indice < 15; ++indice)<br />

cout


MIGUEL Á. TOLEDO MARTÍNEZ<br />

3. Un prototipo para una función llamada prueba() que modificará sólo un elemento en el arreglo de la<br />

pregunta 2 es:<br />

void prueba(char &elementoDelArreglo);<br />

4. Un enunciado que llamará a la función anterior para modificar el elemento almacenado en el<br />

índice[5] del arreglo en la pregunta 2 es:<br />

prueba(caracteres[5]);<br />

RESPUESTA EXAMEN BREVE 38<br />

1. La definición de un arreglo inicializado con los valores enteros de –3 a +3 es:<br />

int numeros[7] = [-3, -2, -1, 0, 1, 2, 3};<br />

o<br />

int numeros[] = [-3, -2, -1, 0, 1, 2, 3};<br />

2. La dimensión del arreglo antes mencionado es 1 x 7.<br />

3. El contenido del arreglo char lenguaje[51 = {‘C’, ‘+’, ‘+’}; es:<br />

[‘C] [‘+’] [‘+’] [‘\0’] [‘\0’]<br />

4. El contenido del arreglo char lenguaje[] = "C++"; es;<br />

[‘C] [‘+’] [‘+’] [‘\0’]<br />

5. Un carácter terminador nulo (‘\0’) se coloca en cada posición de un arreglo de caracteres definido<br />

globalmente sin ningún valor de inicialización.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-78

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!