Arreglos H. Tejeda Marzo 2016
´ Indice 1. Declaraci´ Declaraci´ on on de arreglos
2
2. Inicializa Inicializaci´ ci´ on on de arreglos
4
3. Uso de sub´ sub´ındices variables en un arreglo
5
4. Declaraci´ Declaraci´ on y uso de arreglos de objetos on
8
5. B´ usqueda y uso de arreglos paralelos usqueda
10
6. Paso Paso y devoluci´ devoluci´ on on de arreglos en m´ etodos etodos
14
Para guardar un valor y usarlo se han usado variables. Se han usado ciclos que permiten “reciclar” variables para ser usadas varias veces; ya que despu´es es de haber creado una variable, asignarle un valor, usar el valor, y luego, en iteraciones sucesivas en el ciclo, se reusa la variable con valores diferentes. En ocasiones se tienen situaciones en las cuales guardar un solo valor a la vez en memoria no es suficiente. Por ejemplo, un supervisor sup ervisor de ventas ventas que vigila 20 empleados podr´ podr´ıa querer determinar si cada empleado ha hecho ventas por encima o por debajo del promedio. Con el valor de las ventas del primer empleado ingresado en una aplicaci´on, on, no se puede determinar si est´a por encima o por debajo porque todav´ todav´ıa no se sabe el promedio promedio hasta que se tengan los 20 valores. alores. Desafortun Desafortunadaadamente, s´ s´ı se intente asignar 20 valores de venta a la misma variable, cuando se asigne el valor para el segundo empleado, este reemplaza el valor del primer empleado. Una soluci´ on posible es crear 20 variables de ventas de empleados separadas, cada una con un on nombre unico, u ´ nico, para poder guardar todas las ventas hasta que se pueda calcular el promedio. Una desventaja es que se ocupan 20 nombres de variables diferentes para asignar los valores y 20 sentencias de asignaci´ on diferentes. Para los nombres de las 20 variables diferentes la sentencia que on calcula el total de la venta ser´a compleja, quedando como: total total = prime primeraC raCan ant t + segun segundaC daCan ant t + terce terceraC raCan ant t + ... ...
1
La sentencia anterior traba jar´ıa para 20 vendedores, pero ¿qu´e suceder´ıa si se tienen 5,000 vendedores?
1.
Declaraci´ on de arreglos
La mejor soluci´ on al problema de los 5,000 vendedores es creando un arreglo. Un arreglo es una lista de datos con nombre teniendo todos ellos el mismo tipo. Cada dato es un elemento del arreglo. Se declara una variable arreglo de la misma forma como se declara una variable simple, pero se inserta un par de corchetes despu´es del tipo. Por ejemplo, para declarar un arreglo de valores double para guardar las ventas, se puede escribir lo siguiente: double [] ventas;
Nota .
Se puede declarar una variable arreglo en Java p oniendo los corchetes despu´ es del nombre del arreglo, como en double ventas[];. Este formato es empleado en C y C++, pero el formato preferido entre los programadores de Java es poniendo los corchetes despu´ es del tipo de la variable y antes del nombre de la variable.
Se puede dar cualquier identificador legal que se quiera para un arreglo, pero los programadores de Java nombran los arreglos siguiendo las mismas reglas usadas para variables, el nombre inicia con min´ uscula y letras may´ usculas iniciando palabras subsecuentes. Adicionalmente, varios programadores observan una de las siguientes convenciones para hacer m´as ´enfasis que el nombre representa un grupo de datos: Los arreglos son nombrados frecuentemente usando un sujeto plural como ventas. Los arreglos son nombrados frecuentemente agregando una palabra final que implique un grupo, como listaVentas, tablaVentas, o arregloVentas. Despu´es de crear una variable arreglo, se necesita reservar espacio de memoria. Se usa el mismo procedimiento para crear un arreglo que el empleado para crear un objeto. Para declarar un arreglo y reservar memoria para este se hace en dos procesos distintos. Para reservar localidades de memoria para 20 valores de ventas, se declara la variable arreglo y luego se crea el arreglo mediante dos sentencias como sigue: double [] ventas; ventas = new double [20];
Al igual que con los objetos, se puede declarar y crear un arreglo en una sola sentencia con lo siguiente: double [] ventas = new double [20];
2
Con la sentencia anterior se reservan 20 localidades de memoria para 20 valores double. Se puede distinguir cada dato ventas de los otros con un sub´ındice. Un sub´ ındice es un entero contenido dentro de corchetes que especifica uno de los elementos del arreglo. Cualquier arreglo de elementos en Java est´a numerado iniciando con cero, as´ı que se pueden usar correctamente sub´ındices de 0 hasta 19 al trabajar con un arreglo de 20 elementos. Es decir, el primer elemento del arreglo ventas es ventas[0] y el u ´ ltimo elemento es ventas[19]. En otros lenguajes de programaci´ on el primer elemento del arreglo es el elemento uno, lo cual es un error com´ un al olvidar que en Java el primer elemento en un arreglo es el elemento cero. Tambi´en lo anterior hace que se olvide que el sub´ındice del u´ltimo elemento es uno menos que el tama˜ no del arreglo y no el tama˜ no de este. Para no olvidar el uso correcto se puede pensar que el sub´ındice de un elemento indica la cantidad de elementos que le preceden. Si se emplea un sub´ındice que es negativo, o igual a, o mayor que el tama˜ no del arreglo, el sub´ındice est´ a fuera de l´ımites y un mensaje de error es generado. Cuando se trabaja con alg´ un elemento del arreglo, se emplea de igual forma como se hace con una variable. Por ejemplo, para asignar un valor al primer elemento de ventas en un arreglo, se usa una sentencia de asignaci´ on simple, tal como la siguiente: ventas[0] = 12345.0;
Para mostrar el u ´ltimo elemento del arreglo ventas de tama˜ no 20, se escribe: System.out.println(ventas[19]);
Cuando se declara o accesa un arreglo, se puede usar cualquier expresi´on para indicar el tama˜ no, siempre y cuando esta d´ e un entero. Para declarar un arreglo double llamado valoresMoneda, se podr´ıa usar cualquiera de las siguientes: Una constante literal entera double [] valoresMoneda = new double [10];
Una constante con nombre entera double [] valoresMoneda = new double [CANT ELEMS];
Una variable entera double [] valoresMoneda = new double [cantElems];
Un c´alculo que involucre variables con enteros, o d´ e un entero double [] valoresMoneda = new double [ x + y * z ] ;
Un valor entero devuelto por un m´etodo double [] valoresMoneda = new double [getElementos()];
on que declare y cree un arreglo para guardar al menos cinco Actividad 1. Escribir una aplicaci´ valores double. Que asigne a cada uno de los elementos del arreglo un valor arbitrario y que muestre en pantalla las asignaciones hechas. 3
2.
Inicializaci´ on de arreglos
Una variable que tiene un tipo primitivo, como un int, guarda un valor. Una variable con un tipo referencia, como un arreglo, guarda una direcci´ on de memoria donde un valor est´ a guardado. Los nombres de arreglos contienen referencias, al igual como todos los objetos Java. No se asigna direcci´ on de memoria cuando se declara un arreglo usando s´ o lo un tipo de dato, corchetes, y un nombre. El nombre de la variable arreglo tiene el valor especial null, que significa que el identificador no est´a asociado con alguna direcci´ on, como sucede con el valor de numeros que es null en la siguiente declaraci´ on: int [] numeros;
Al emplear la palabra reservada new para definir un arreglo, el nombre arreglo recibe el valor de una direcci´on de memoria, como se hace en la siguiente sentencia al definir numeros int [] numeros = new int [10];
En esta declaraci´ on numeros tiene una direcci´on, pero cada elemento de numeros tiene el valor de cero porque es un arreglo de enteros. Los elementos en un arreglo float o double tienen asignado 0.0. Por defecto, los elementos de un arreglo char tienen asignado ’\u0000’, el cual es el valor Unicode para el car´ acter null, y los elementos de un arreglo boolean tienen asignado false. En arreglos de objetos, incluyendo String, cada elemento tiene asignado null por defecto. Adem´ as de asignar un valor a un elemento de un arreglo, como en: numeros[0] = 45;
Se pueden tambi´ en asignar valores diferentes al valor por defecto a los elementos de un arreglo en la creaci´ on. Para inicializar un arreglo, se usa una lista de inicializaci´ on de valores separados por comas y encerrados entre llaves. Dando valores para todos los elementos en un arreglo tambi´ en es llamado poblar un arreglo. Por ejemplo, si se quiere crear un arreglo llamado multiplosDiez y guardar los primeros seis m´ ultiplos de diez en el arreglo, se puede declarar como sigue: int[] multiplosDiez = {10, 20, 30, 40, 50, 60};
Observar el punto y coma al final de la sentencia. Cuando se pueble un arreglo en la creaci´ on dando una lista de inicializaci´ on, no se da el tama˜ no del arreglo, el tama˜ no es asignado de acuerdo a la cantidad de valores que se pongan en la lista de inicializaci´ on. Por ejemplo, el arreglo multiplosDiez definido previamente tiene tama˜ no seis. Tambi´en, cuando se inicializa un arreglo, no se requiere usar la palabra reservada new, la nueva memoria es asignada de acuerdo al tama˜ no de la lista dada. 4
No se puede directamente inicializar una parte de un arreglo en Java. En caso de que se requiera se deber´a hacer individualmente, una vez que se haya creado el arreglo usando la palabra reservada new. Actividad 2. Modificar la actividad 1 para declarar, crear, e inicializar el arreglo usando una lista
de inicializaci´ on.
3.
Uso de sub´ındices variables en un arreglo
Si se trata cada elemento de un arreglo como una entidad individual, no hay ventaja en declarar un arreglo respecto a variables individuales de tipos primitivos. El poder de los arreglos se da cuando se usan sub´ındices que son variables, en vez de sub´ındices que sean valores constantes. Suponer que se declara un arreglo de cinco enteros para manejar igual cantidad de puntuaciones, como se muestra enseguida: int [] arregloPunt =
{13, 23, 54, 79, 95};
Luego se quiere realizar la misma operaci´on con cada elemento del arreglo, tal como incrementar cada puntuaci´ on por una cantidad constante. Para incrementar cada elemento de arregloPunt por tres puntos, por ejemplo, se puede escribir lo siguiente: final int INCREMENTO = 3;
arregloPunt[0] arregloPunt[1] arregloPunt[2] arregloPunt[3] arregloPunt[4]
+= += += += +=
INCREMENTO; INCREMENTO; INCREMENTO; INCREMENTO; INCREMENTO;
Con un arreglo peque˜ no, la tarea es manejable, requiriendo solo cinco sentencias. Sin embargo, se puede reducir la cantidad de c´odigo necesario usando una variable como sub´ındice. Entonces, se puede usar un ciclo para realizar la aritm´etica con cada elemento, como en el siguiente ejemplo: final int INCREMENTO = 3; for (int sub = 0; sub < 5; ++sub)
arregloPunt[sub] += INCREMENTO;
La variable sub es puesta a cero, y entonces es comparado a cinco. Como el valor de sub es menor que cinco, el ciclo se ejecuta y tres es agregado a arregloPunt[0]. Luego, la variable sub es incrementada y se hace uno, que sigue siendo menor que cinco, as´ı que el ciclo se ejecuta nuevamente, arregloPunt[1] es incrementado por tres, y as´ı sucesivamente. Un proceso que toma cinco sentencias ahora toma solamente una. Considerar lo que suceder´ıa si el arreglo hubiese tenido 100 elementos, habr´ıa requerido 95 sentencias adicionales, pero el unico ´ cambio requerido, usando el segundo m´etodo, es el cambio del tama˜ no del arreglo a 100 en la segunda parte del ciclo for. 5
Cuando una aplicaci´ on contiene un arreglo y se quiere usar cada elemento del arreglo en alguna tarea, se sugiere usar ciclos que var´ıen la variable de control del ciclo desde cero hasta uno menos que el tama˜ no del arreglo. Estas tareas pueden ser el alterar cada valor en el arreglo, sumar todos los valores en el arreglo, o mostrar cada elemento en el arreglo. En una aplicaci´on que incluya un arreglo es conveniente declarar una constante simb´ olica igual al tama˜ no del arreglo y usar la constante simb´ olica como un valor limitante en cada ciclo que procese el arreglo. De esta forma, si el tama˜ no del arreglo cambia m´ as adelante, s´ olo se necesita modificar el valor guardado en la constante simb´ olica, para no tener que buscar y modificar el valor limitante en cada ciclo que procesa el arreglo. Un ejemplo ser´ıa como el siguiente: int [] arregloPunt = {13, 23, 54, 79, 95}; final int INCREMENTO = 5; final int CANT DE PUNT = 5; for (int sub = 0; sub < CANT DE PUNT; ++sub)
arregloPunt[sub] += INCREMENTO;
Este formato tiene dos ventajas, primero, el uso de la constante simb´ olica, CANT DE PUNT, el lector entiende que se est´a procesando cada elemento del arreglo por el tama˜ no del arreglo entero. Segundo, si el tama˜ no del arreglo cambia porque se agregaron o quitaron puntuaciones, s´olo se ocupa cambiar el valor de la constante simb´ olica una sola vez. Una segunda opci´ on, es usar un campo, variable de instancia, al que es asignado autom´ aticamente un valor para cada arreglo que es creado; el campo length contiene la cantidad de elementos en el arreglo. El siguiente ejemplo repite el c´ odigo previo mostrando como se usa este campo como valor limitante en la parte central del ciclo for. int [] arregloPunt = {13, 23, 54, 79, 95}; final int INCREMENTO = 3; for (int sub = 0; sub < arregloPunt.length; ++sub)
arregloPunt[sub] += INCREMENTO;
Un error frecuente del programador es intentar usar length como un m´etodo del arreglo, escribiendo arregloPunt.length(), en vez de usarlo como un campo. Una variable de instancia o campo objeto como length es tambi´en llamado una propiedad del objeto. Java tambi´en soporta un ciclo for mejorado. Este ciclo permite recorrer un arreglo sin indicar los puntos de inicio y terminaci´ on para la variable de control del ciclo. Para mostrar cada elemento del arreglo llamado arregloPunt con el ciclo avanzado se hace as´ı: for (int val : arregloPunt)
System.out.println(val);
a despu´es de los dos puntos. Dentro val es definido del mismo tipo que el arreglo nombrado que est´ del ciclo, val adquiere, uno a la vez, cada valor del arreglo. Se puede leer como, “Para cada val en arregloPunt, mostrar val”. El ciclo for avanzado es conocido tambi´en como ciclo foreach. 6
Uso de una parte del arreglo
En ocasiones no se quiere usar cada valor en un arreglo. Por ejemplo, suponer que se escribe un programa que permite a un estudiante meter hasta 10 puntuaciones y luego calcular y mostrar el promedio. Para permitir 10 puntuaciones, se crea un arreglo que puede guardar 10 valores, pero como el estudiante podr´ıa meter menos de 10 valores, se podr´ıa usar una parte del arreglo, como se muestra en el c´odigo 1. 1 2 3 4 5 6 7 8 9 10
import j a v a . u t i l . ∗ ; p ub li c c l a s s P r o m e d i o F l e x i b l e { p ub li c s t a t i c v oi d ma in ( S t r i n g [ ] a r g s ) { i n t [ ] p u nt u ac i o ne s = new int [ 1 0 ] ; int puntuacion = 0; int c u e n t a = 0 ; i n t t o t al = 0 ; f i n a l i nt SALIR = 99 9; f i n a l i nt MAX = 1 0 ; S c an n er e n t ra d a = new Scanner (System . in );
11 12
13 14 15 16 17 18 19 20
21 22 23 24 25 26
}
27 28
System . out . pr in t (” Entrar puntuaci´on : ” ) ; p u n t u a ci o n = e n t r a d a . n e x t I n t ( ) ; while ( cuent a < MAX && pu nt ua ci on != SALIR) { i f ( puntu acion != SALIR) { p u n t u a c i o n e s [ c u e n t a ] = p u n t u a ci o n ; t o t a l += p u n t u a c i o n e s [ c u e n t a ] ; S ys te m . o ut . p r i n t ( ” I n g r e s a r s i g u i e n t e p u n t ua c i o´n o ” + SALIR + ” p ar a s a l i r : ” ) ; p u n t u a ci o n = e n t r a d a . n e x t I n t ( ) ; } cuenta++; } System . out . pr in tl n (” Las puntua cione s dadas son : ” ) ; f o r ( i n t x = 0; x < c uen ta ; ++x ) System . out . pr in t ( puntua cione s [ x ] + ” ” ); System . out . pr i nt l n (” \ n E l p ro me di o e s ” + ( t o t a l ∗ 1 . 0 / c ue nt a ) ) ;
}
C´ odigo 1: Aplicaci´ on PromedioFlexible. La aplicaci´ on PromedioFlexible declara un arreglo que puede guardar diez puntuaciones. Al usuario se pide la primera puntuaci´on; luego, en ciclo while la puntuaci´ o n es puesta en el arreglo on es agregada a un total, y al usuario se le pide ingresar otra puntuaciones. Luego la puntuaci´ puntuaci´ on o un valor SALIR de 999 para parar la petici´ on de n´ umeros. En el ciclo while se revisa para que no m´ as de diez puntuaciones sean ingresadas y que el usuario no d´ e 999 para salir. Despu´es de cada puntuaci´on entrada, la variable contar es incrementada, y sirve para dos prop´ositos: para indicar el elemento donde la siguiente puntuaci´ on deber´a ser guardada, y para cuando el ciclo termina saber la cantidad de puntuaciones dadas. La variable count luego es usada para controlar la salida del ciclo for y para el c´alculo del promedio. on descrita en la actividad 2 para que se use un ciclo for para Actividad 3. Modificar la aplicaci´ mostrar cada uno de los elementos del arreglo.
7
4.
Declaraci´ o n y uso de arreglos de objetos
Se pueden declarar arreglos que guarden elementos de cualquier tipo, incluyendo objetos. Por ejemplo, suponer que se ha creado la clase Asalariado, c´ odigo 2, la cual incluye dos campos de datos, numero y salario, un constructor, y m´etodos accesores para cada campo. 1 2 3 4
p ub li c c l a s s A s a l a r i a d o { p r iv a te i n t numero ; private double s a l a r i o ; A s a l a r i a d o ( i n t n , double s ) {
numero = n ; salario = s ;
5 6
}
7
p u bl i c i n t getNumero () { return numero ;
8 9
}
10
p u bl i c i n t g e t S a l a r i o ( ) { return s a l a r i o ;
11 12
}
13 14
}
C´ odigo 2: La clase Asalariado. Se pueden crear objetos individuales Asalariado con nombres u ´ nicos, como los siguientes: Asalariado pintor, electricista, plomero; Asalariado trabajador1, trabajador2, trabajador3;
En varios programas puede ser m´as conveniente crear un arreglo de objetos Asalariado. Un arreglo llamado plantilla que guarde siete objetos Asalariado se define como: Asalariado[] plantilla = new Asalariado[7];
La sentencia reserva suficiente memoria para siete objetos Asalariado llamados plantilla[0] hasta plantilla[6]. La sentencia no construye los objetos Asalariado, por lo tanto se requerir´ a llamar al constructor siete veces. Se quiere n´umerar a los trabajadores empezando en 500 y con un salario de $1,200, y como el constructor de la clase Asalariado requiere dos argumentos, n´umero del asalariado y salario, el siguiente ciclo construye los siete objetos: final int NUM INICIAL = 500; final double SALARIO = 1200.0; for (int x = 0; x < plantilla.length; ++x) plantilla[x] = new Asalariado(NUM INICIAL + x, SALARIO);
Como x var´ıa desde 0 hasta 6, cada uno de los siete objetos plantilla es construido con un n´umero de empleado que es 500 m´as que x, y con el mismo salario de $1,200.00, como se asigna por la constante SALARIO. 8
Otras clases contienen solo el constructor por defecto, el cual es dado autom´ aticamente cuando no hay ning´ un constructor escrito en la clase. Para construir un arreglo de objetos usando un constructor por defecto, tambi´ en se debe llamar al constructor usando la palabra reservada new para cada elemento declarado del arreglo. Por ejemplo, suponer que se ha creado una clase llamado ArticuloInventario sin haber escrito un constructor. Para crear un arreglo de 1,000 objetos ArticuloInventario, se podr´ıa hacer as´ı: final int CANT ARTS = 1000;
ArticuloInventario[] articulos = new ArticuloInventario[CANT ARTS]; for (int x = 0; x < CANT ARTS; ++x) articulos[x] = new ArticuloInventario();
Para usar un m´ etodo que pertenece a un objeto que es parte de un arreglo, se inserta la notaci´ on sub´ındice apropiada despu´es del nombre arreglo y antes del punto que precede al nombre del m´etodo. Por ejemplo, para mostrar los datos de los siete asalariados guardados en el arreglo plantilla, se puede escribir lo siguiente: for (int x = 0; x < plantilla.length; ++x)
System.out.println(plantilla[x].getNumero() + " " + plantilla[x].getSalario());
La colocaci´ on del sub´ındice entre corchetes es despu´es de plantilla para indicar que el m´etodo “pertenece” a un elemento particular de la plantilla. Uso de ciclos for avanzados con objetos
Se puede emplear el ciclo for avanzado para recorrer un arreglo de objetos. Para mostrar los datos de los siete asalariados guardados en el arreglo plantilla, se puede hacer de esta forma: for (Asalariado trabajador : plantilla)
System.out.println(trabajador.getNumero() + " " + trabajador.getSalario());
En este ciclo, trabajador es una variable local que representa cada elemento de plantilla en turno. Usando el ciclo for avanzado se evita usar un valor limitante para el ciclo y de usar un sub´ındice siguiendo a cada elemento. Manipulaci´ on de arreglos de String
Como con cualquier otro objeto, se puede crear un arreglo de objetos String. Por ejemplo, se puede guardar los nombres de los departamentos de una empresa como sigue: String[] departNombres = {"Contabilidad", "Recursos Humanos", "Ventas"};
9
Se acceden los nombres de los departamentos como otros arreglos objeto. Por ejemplo, se puede usar el siguiente c´odigo para mostrar la lista de String guardadas en el arreglo departNombres: for (int a = 0; a < departNombres.length; ++a)
System.out.println(departNombres[a]);
a un arreglo String para guardar Actividad 4. Crear la clase EquipoBaloncesto, la cual contendr´ los nombres, de exactamente cinco jugadores, de un equipo de baloncesto. Cuando se declare el arreglo en la clase, este deber´ a ser creado. Agregar un m´etodo que ponga el nombre de un miembro del equipo. Este m´etodo requiere una posici´ on y un nombre, y usa la posici´on como sub´ındice al arreglo String para asignar el nombre. Agregar un m´etodo accesor que devuelve el nombre de un miembro del equipo; este m´etodo requiere un valor usado como sub´ındice para determinar cual nombre se devuelve del arreglo. Agregar tambi´en a la clase EquipoBaloncesto un campo String, para guardar el nombre del equipo; agregar m´etodo accesor y mutador para este campo. Crear una aplicaci´ on que muestre de manera completa el uso de la clase EquipoBaloncesto, es decir, deber´a declarar y crear un objeto del tipo EquipoBaloncesto, pedir al usuario los nombres del equipo y mostrar los miembros del equipo.
5.
B´ usqueda y uso de arreglos paralelos
Suponer que una empresa manufactura diez art´ıculos. Cuando un cliente pone una orden se necesita determinar si la clave del art´ıculo es v´ alida. Cuando se desea determinar si una variable tiene uno de varios valores v´alidos y estos son secuenciales, por ejemplo entre 201 y 220, la siguiente sentencia ogico Y, puede hacer la revisi´ on para poner la bandera a true si el art´ıculo if, que usa el operador l´ es v´alido. final int INF = 201; final int SUP = 220; boolean articuloValido = false; if (articuloOrdenado >= INF && articuloOrdenado <= SUP)
articuloValido = true;
Cuando los valores v´ alidos no son secuenciales, por ejemplo, 101, 108, 201, 213, 266, 304, etc., se puede codificar la siguiente sentencia if anidada profundamente o una comparaci´ on larga O para determinar la validez. if (articuloOrdenado == 101)
articuloValido = true; else if (articuloOrdenado == 108) articuloValido = true; else if (articuloOrdenado == 201) articuloValido = true; // y as´ ı sucesivamente
10
Otra soluci´ on elegante y compacta es comparando la variable articuloOrdenado con una lista de valores en un arreglo, un proceso llamado b´ usqueda en un arreglo . Se inicializa el arreglo con los valores v´alidos y luego se emplea la sentencia for para recorrer el arreglo, poniendo una variable booleana a true cuando un apareamiento es encontrado. int [] valoresValidos =
{101, 108, 201, 213, 266,
304, 311, 409, 411, 412}; for (int x = 0; x < valoresValidos.length; ++x) if (articuloOrdenado == valoresValidos[x]) articuloValido = true;
El uso del ciclo for en esta soluci´ on permite revisar cualquier cantidad de valores v´alidos sin tener que modificar ninguna parte, ya que valoresValidos.length tiene el tama˜ no actual del arreglo. Uso de arreglos paralelos
Cuando se tienen dos arreglos con la misma cantidad de elementos y sus elementos se relacionan entre ellos por la posici´ on, entonces se puede usar simult´aneamente el mismo sub´ındice en ambos arreglos. Un arreglo paralelo es uno con la misma cantidad de elementos como otro y para el cual los valores en los elementos correspondientes est´an relacionados. Suponiendo que para el c´ odigo mostrado previamente se configura un arreglo que tenga los precios de los art´ıculos, entonces estos precios deber´an aparecer en el mismo orden que sus correspondientes n´umeros de art´ıculo en el arreglo valoresValidos. El ciclo for que encuentra el n´ umero v´alido de art´ıculo tambi´ en encuentra el precio, como se muestra en la aplicaci´ on EncontrarPrecio, c´ odigo 3.
11
1 2 3 4
import jav ax . swi ng . JOptionPane ; p ub li c c l a s s E n c o n t r a r P r e c i o { p ub li c s t a t i c v oi d main ( S t r i n g [ ] a r g s ) { i n t [ ] v a l o r e sV a l i d o s = { 1 0 1 , 1 0 8 , 2 0 1 , 2 1 3 , 2 6 6 ,
304 , 311, 409, 411 , 412}; p r e ci o s = { 2 2 . 5 , 1 3 . 6 0 , 1 8 . 7 0 , 5 4 . 2 0 , 2 3 . 3 0 , 5 4 . 80 , 5 6 . 20 , 7 8 . 9 0 , 5 . 5 0 , 9 . 9 0 } ; S t r i ng a r t i c u l o S t r ; int articuloOrden ado ; double p r e ci o A r ti c u l o = 0 . 0 ; boolean a r t i c u l o V a l i d o = f a l s e ; a r t i c u l o S t r = J O pt io nP an e . s h o w I n pu t D i a l o g ( null , ” I n g re s ar e l n´ u me ro d e a r t ´ıc u l o q ue q u i e r e o r d e n a r ” ) ; a r t i c u l o O rd e n a d o = I n t e g e r . p a r s e I n t ( a r t i c u l o S t r ) ; f o r ( i n t i = 0; i
5
double [ ]
6 7 8 9
10 11 12 13 14 15 16 17 18 19 20 21 22
23
else
JOptionPane . showMessageDial og ( null , ”¡Lo s i e n t o ! , a r t´ıc u l o i n g r e s a d o no v´a l i d o ” ) ;
24 25
}
26 27
}
C´ odigo 3: La aplicaci´ on EncontrarPrecio que accede informaci´ on en arreglos paralelos. Nota .
En lugar de arreglos paralelos conteniendo n´ umeros de art´ıculos y precios, se puede crear una clase llamada Articulo conteniendo dos campos, articuloOrdenado y precioArticulo. Luego se crea un arreglo simple de objetos que encapsulan los n´umeros y los precios.
En el c´ odigo 3 se compara articuloOrdenado con cada uno de los diez valoresValidos. No importa, que por ejemplo, articuloOrdenado sea igual al primer valor, se terminan haciendo nueve comparaciones extras, y estas ser´an siempre falsas. Tan pronto como un apareamiento para as eficiente forzar la salida temprana del ciclo for. Una articuloOrdenado es encontrado, es m´ forma f´ acil de lograrlo es poner x a un valor alto dentro del bloque de sentencias ejecutadas cuando hay un apareamiento. Enseguida se muestra la forma como se puede hacer. Tambi´en considerar para una mayor eficiencia poner los art´ıculos m´ as comunes al inicio. for (int x = 0; x < CANTIDAD DE ARTICULOS; ++x) if (articuloOrdenado == valoresValidos[x]) { articuloValido = true ;
precioArticulo = precios[x]; x = CANTIDAD DE ARTICULOS;
} Algunos programadores consideran inapropiado modificar la variable de control de ciclo dentro del 12
Cantidad ordenada
Descuento
1 a 12 13 a 49 50 a 99 100 a 199 200 o m´ as
Ninguno 10 % 14 % 18 % 20 %
Cuadro 1: Tabla de descuentos cuerpo del ciclo for; porque consideran que s´olo se debe hacer en la tercera secci´on del ciclo for. Por lo que la salida forzada del ciclo la realizan con otra expresi´on booleana en la secci´ on central del ciclo for, de esta forma, como se muestra enseguida, x deber´a estar entre el rango antes de cada iteraci´ on y articuloValido no deber´a estar puesta a true. for (int x = 0; x < CANTIDAD DE ARTICULOS && !articuloValido; ++x) if (articuloOrdenado == valoresValidos[x]) { articuloValido = true ;
precioArticulo = precios[x];
} B´ usqueda en un arreglo por un rango de apareamiento
Suponga ahora que una empresa da descuentos a sus clientes de acuerdo a la cantidad de art´ıculos ordenados. El cuadro 1 muestra el descuento ofrecido dependiendo de la cantidad ordenada. Una opci´ on de programaci´ on ineficiente es crear un arreglo simple para guardar los descuentos. Se podr´ıa usar una variable llamada cantArts como sub´ındice en el arreglo, pero el arreglo podr´ıa requerir cientos de entradas, como se muestra enseguida: double [] descuentos =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.10, 0.10, 0.10, ...};
En el arreglo descuentos se requieren trece ceros, porque el primer elemento del arreglo tiene un sub´ındice cero y representa un descuento de cero para cero art´ıculos y los siguientes 12 descuentos tambi´en son cero para manejar desde un art´ıculo hasta 12. Despu´es el arreglo guardar´ a 37 copias de 0.10 para 13 art´ıculos y hasta 49. El arreglo ser´ a necesariamente grande para guardar un valor exacto para cada posible cantidad ordenada. Una mejor opci´on es crear dos arreglos correspondientes y realizar un apareamiento de rango, en el cual se compara un valor con los extremos de los rangos num´ ericos para encontrar la categor´ıa a la cual el valor pertenece. Por ejemplo, un arreglo puede tener los cinco descuentos, y el otro arreglo puede tener los cinco l´ımites inferiores de los rangos de descuento, como se muestra enseguida: int [] limitesInferiores = {1, 13, 50, 100, 200}; double [] descuentos = {0, 0.1, 0.14, 0.18, 0.2};
13
Empezando con el u ´ ltimo elemento del arreglo limitesInferiores, para cualquier cantOrdenada mayor que, o igual a limitesInferiores[4], el descuento es descuentos[4]. Si cantOrdenada es menor que limitesInferiores[4], se deber´a decrementar el sub´ındice y buscar en un rango inferior. En la aplicaci´ on EncontrarDescuento, c´ odigo 4, se muestra el uso de los arreglos paralelos anteriores. 1 2 3 4 5 6 7
import jav ax . swi ng . JOptionPane ; p ub li c c l a s s EncontrarDescuento { p ub li c s t a t i c v oi d main ( S t r i n g [ ] a r g s ) { f i n a l i nt CANT RANGOS = 5 ; int [ ] l i m i t e sI n f e ri o r e s = { 1, 13 , 5 0 , 1 00 , double [ ] d e s cu e n to s = { 0 , 0 . 1 , 0 . 14 , 0 . 18 , 0 . 2 } ; double d e s c u e n t o C l i e n t e ;
8
S t r i n g s t rC a n tO r de n ad a ;
9
i n t cantOrden ada ; i n t su b = CANT RANGOS − 1 ;
10 11
12 13
14 15 16 17 18
strCantOrdenada = JOptionPane . showI nputDi alog ( null , ”¿Cu´a n t o s a r t ´ıc u l o s h a o r d en a d o ? ” ) ; cantOrdenada = In te ge r . pa rse Int ( strCantOrdenada ); while ( s u b >= 0 && cantOrdenada < l i m i t e s I n f e r i o r e s [ s ub ] ) −−sub ; descu entoC lien te = descuentos [ sub ] ; JOptionPane . showMessageDial og ( null , ” El d es cu en to p ar a ” + c an tO rd en ad a + ” a r t´ıc u l o s e s ” + d e s c u e n t o C l i e n t e ) ;
}
19 20
200};
}
C´ odigo 4: La aplicaci´ on EncontrarDescuento.
Nota .
En la aplicaci´on EncontrarDescuento, c´ odigo 4, se require que sub sea mayor que, o igual a cero antes de evaluar la expresi´on booleana cantOrdenada
Actividad 5. Modificar la actividad 4 para permitir que se capturen varios equipos de baloncesto,
y despu´es se le pida al usuario el nombre de alg´ un equipo del que quiera ver sus jugadores.
6.
Paso y devoluci´ on de arreglos en m´ etodos
Se puede usar cualquier elemento de un arreglo de la misma forma como se usa cualquier variable del mismo tipo. De igual forma, se puede pasar un elemento de un arreglo a un m´etodo de la misma forma como se pasa una variable. La aplicaci´ on PasarElementoArreglo, c´ odigo 5, crea un arreglo de cuatro enteros y los muestra. La aplicaci´ on llama el m´etodo obtenerUnEntero() cuatro veces, pasando un elemento a la vez. El m´etodo muestra el n´ umero, cambia el n´ u mero a 999, y luego muestra el n´ umero otra vez. Finalmente, de regreso en el m´etodo main(), los cuatro n´ umeros son mostrados otra vez.
14
1 2 3
p ub li c c l a s s PasarElementoArreglo { p ub li c s t a t i c v oi d main ( S t r i n g [ ] a r g s ) { i n t [ ] numeros = { 1 0 , 2 0 , 3 0 , 4 0 } ;
S ys te m . o u t . p r i n t ( ” A l i n i c i o d e m ai n : ” ) ; f o r ( i n t n : n um er os ) System . out . pr in t (” ” + n ); System . out . pr in tl n ( ) ; f o r ( i n t i = 0; i
4 5 6 7 8 9 10 11 12 13 14
}
15
p ub li c s t a t i c v oi d obtenerUnEntero( i n t uno) {
System . out . pr in t (”Al i n i c i o del m´e todo uno e s : ” + un o ) ; uno = 9 9 9 ; S ys te m . o u t . p r i n t l n ( ” y a l f i n a l d e l m´e t o do uno e s : ” + u no ) ;
16
17 18
}
19 20
}
C´ odigo 5: La aplicaci´ on PasarElementoArreglo. Al ejecutar la aplicaci´ on PasarElementoArreglo, se puede ver que los cuatro n´ umeros pasados fueron cambiados en el m´etodo obtenerUnEntero() permanecen sin cambio de regreso en main() despu´es de la ejecuci´on del m´etodo. La variable llamada uno es local al m´etodo obtenerUnEntero, y cualquier cambio a variables pasadas en el m´ etodo no son permanentes y no son reflejados en el arreglo en el m´etodo main(). Cada variable llamada uno en el m´etodo obtenerUnEntero guarda una sola copia del elemento del arreglo pasado al m´ etodo. Los elementos individuales del arreglo son pasados por valor ; es decir, una copia del valor es hecha y usada dentro del m´etodo receptor. Cuando cualquier tipo primitivo, boolean, char, byte, short, int, long, float, o double, es pasado a un m´etodo, el valor es pasado. Los arreglos, como todos los objetos no primitivos, son tipos de referencia, esto es, el objeto guarda una direcci´ on de memoria donde los valores est´an guardados. Como un arreglo es una referencia, no se puede asignar otro arreglo a este usando el operador =, ni se pueden comparar dos arreglos usando el operador ==. Cuando se pasa un arreglo, se pasa su nombre, a un m´etodo, el m´etodo receptor obtiene una copia de la direcci´ on de memoria actual del arreglo. Por lo tanto el m´etodo receptor tiene acceso a los valores originales del arreglo de elementos del m´etodo llamador. La aplicaci´ on PasarArreglo, c´odigo 6, crea un arreglo de cuatro enteros. Despu´es que los enteros son mostrados, el nombre del arreglo, su direcci´on, es pasado a un m´etodo llamado obtieneArreglo(). Dentro del m´etodo, los n´ umeros son mostrados, para observar que estos retienen sus valores desde main(), luego el valor 888 est´ a asignado a cada n´ umero. A pesar de que obtieneArreglo() es un m´etodo void, no devuelve nada al m´etodo main(), cuando el m´etodo main() muestra el arreglo por segunda ocasi´on, todos los valores han sido cambiados a 888. Ejecutar la aplicaci´ on etodo recibe una referencia del arreglo, el PasarArreglo para comprobar lo comentado. Como el m´ m´etodo obtieneArreglo() “sabe” la direcci´on del arreglo declarado en main() y hace sus cambios directamente al arreglo original.
15
1 2 3
p ub li c c l a s s P a s a r A r r e g l o { p ub li c s t a t i c v oi d main ( S t r i n g [ ] a r g s ) { i n t [ ] numeros = { 1 0 , 2 0 , 3 0 , 4 0 } ;
S ys te m . o u t . p r i n t ( ” A l i n i c i o d e m ai n : ” ) ; f o r ( i n t n : n um er os ) System . out . pr in t (” ” + n ); System . out . pr in tl n ( ) ; o b t i e n e A r r e g l o ( n um er os ) ; S ys te m . o u t . p r i n t ( ” A l f i n a l d e m ai n : ” ) ; f o r ( i n t n : n um er os ) System . out . pr in t (” ” + n ); System . out . pr in tl n ( ) ;
4 5 6 7 8 9 10 11 12 13
}
14
p ub li c s t a t i c v oi d o b t i e n e A r r e g l o ( i n t [ ]
arr ) { S ys te m . o u t . p r i n t ( ” A l i n i c i o d e l m´e t o do a r r t i e n e : ” ) ; for ( int n : arr ) System . out . pr in t (” ” + n ); System . out . pr in tl n ( ) ; f o r ( i n t i = 0; i
15 16 17 18 19 20 21 22 23 24
}
25 26
}
C´ odigo 6: La aplicaci´ on PasarArreglo.
Nota .
En otros lenguajes, como C, C++, y C#, se puede escoger pasar variables a m´ etodos por valor o referencia. No se puede escoger en Java. Las variables tipo primitivo son siempre pasadas por valor. Cuando se pasa un objeto, una copia de la referencia al objeto es siempre pasada.
Regresar un arreglo desde un m´ etodo
Un m´etodo puede regresar una referencia arreglo. Cuando un m´etodo regresa una referencia arreglo, se deben incluir corchetes con el tipo regresado en la cabecera del m´etodo. En el siguiente c´ odigo se muestra el m´etodo getArreglo() que regresa un arreglo de int declarado localmente. Los corchetes son usados como parte del tipo regresado; la sentencia return devuelve el nombre del arreglo sin ning´ un corchetes. public static int [] getArreglo() { int [] puntuaciones = {98, 74, 69, 89}; return puntuaciones;
} Cuando se llama al m´etodo getArreglo() que se muestra previamente, se puede guardar su valor devuelto en cualquier referencia arreglo entero. Por ejemplo, se podr´ıa declarar un arreglo y hacer la llamada del m´etodo en la siguiente sentencia: 16
int [] puntuacionesRecibidas = getArreglo();
etodo que devuelva un arreglo de 5 equipos de baActividad 6. Agregar a la actividad 5 un m´ loncesto. En el m´etodo se pedir´ a el nombre del equipo y los nombres de los jugadores para cada uno de los equipos. Agregar en el m´etodo main() la llamada a este m´etodo que crea los equipos de baloncesto.
17