Arreglos Avanzados H. Tejeda Marzo 2016
´Indice 1. Ordenamiento de elementos de un arreglo
1
2. Arreglos multidimensionales
7
3. Clase Arrays
12
4. Clase ArrayList
15
5. Enumeraciones
19
Se presentan a continuaci´on algunas otras operaciones que son realizadas con los arreglos. Una en particular, el ordenamiento de los elementos, es requerida por otros algoritmos. Tambi´en se indica como declarar y crear arreglos con m´as de una dimensi´on. Se revisa la clase Arrays que tiene m´etodos para algunas de las operaciones requeridas en un arreglo, como el ordenamiento. Por su parte la clase ArrayList es una clase que permite realizar algunas operaciones adicionales que no est´an presentes cuando se maneja un arreglo directamente. Por u ´ltimo se comentan las enumeraciones que son empleadas para crear un tipo de dato propio con un conjunto fijo de valores v´alidos.
1.
Ordenamiento de elementos de un arreglo
El ordenamiento es el proceso de arreglar una serie de objetos con alg´ un orden l´ogico. Cuando se ponen los objetos en orden, iniciando con el objeto que tiene el menor valor, se est´a haciendo en orden ascendente, y si se inicia con el objeto con el valor m´as grande, se hace en orden descendente.
1
El ordenamiento posible m´as simple es el de dos valores que no est´en ordenados. Se deben intercambiar los dos valores para ponerlos en orden. Suponiendo que se tienen dos variables, valA y valB, con los valores 16 y 2, respectivamente. Para intercambiar los valores se requiere usar una variable temp para que no se pierdan los valores al intercambiar, as´ı las sentencias quedar´ıan como: temp = valA; // 16 se asigna a temp valA = valB; // 2 se asigna a valA valB = temp; // 16 se asigna a valB Si se quiere ordenar dos valores cualesquiera, valA y valB, en orden ascendente, se usa la siguiente sentencia if para decidir si se hace el intercambio. El intercambio se hace cuando valA es mayor que valB, de otra forma no se hace nada. if (valA temp valA valB }
> = = =
valB) { valA; valB; temp;
Ordenar m´as de dos valores puestos en variables es m´as complicado, pero esta tarea es manejable cuando se usa un arreglo. Varios algoritmos de ordenamiento han sido desarrollados; un algoritmo es un proceso o conjunto de pasos que resuelven un problema.
1.1.
Algoritmo de ordenamiento burbuja
En el algoritmo de ordenamiento burbuja se comparan parejas de elementos contiguos, intercambi´andolos si no est´an ordenados. As´ı los elementos m´as peque˜ nos “burbujean” a la cima de la lista, eventualmente creando una lista ordenada. El ordenamiento burbuja ni es el m´as r´apido, ni es la t´ecnica m´as eficiente de ordenamiento, pero es f´acil de entender y da mayor conocimiento de la manipulaci´on de elementos del arreglo. Suponiendo que se tienen valores no ordenados en un arreglo, como en la siguiente sentencia: int [] numeros = {88, 33, 99, 22, 54}; Se compara el primer n´ umero con el segundo, si no est´an ordenados ascendentemente se intercambian. Luego se repite lo anterior para el segundo con el tercero, y as´ı sucesivamente, hasta terminar con el cuarto y el quinto. En general se compara si numeros[x] es mayor 2
que numeros[x + 1] para intercambiarlos. En la siguiente tabla se muestran en la primera columna los n´ umeros que son comparados, la segunda columna informa si la pareja de valores son intercambiados y la u ´ltima muestra los valores del arreglo como van acomodando. Valores comparados 88 > 33 88 > 99 99 > 22 99 > 54
¿Intercambio? S´ı No S´ı S´ı
88, 33, 33, 33, 33,
Arreglo numeros 33, 99, 22, 88, 99, 22, 88, 99, 22, 88, 22, 99, 88, 22, 54,
54 54 54 54 99
Cuando se alcanza el fondo de la lista, los n´ umeros no est´an en orden ascendente, pero el n´ umero m´as grande, 99, se ha movido al fondo de la lista. Esta caracter´ıstica da al ordenamiento burbuja su nombre, el valor “m´as pesado” se ha hundido en el fondo de la lista y los valores “m´as ligeros” han burbujeado a la cima. Suponiendo que b y temp han sido declaradas como variables enteras, el c´odigo para lo realizado previamente es: for (b = 0; b < numeros.length - 1; ++b) if (numeros[b] > numeros[b+1]) { temp = numeros[b]; numeros[b] = numeros[b+1]; numeros[b+1] = temp; } Nota. En vez de comparar b con numeros.length - 1 en cada iteraci´on del ciclo, es m´as eficiente declarar una variable a la cual se le asigne numeros.length - 1 y usarla en la comparaci´ on. De esta forma, la resta es hecha una sola vez.
Para continuar el ordenamiento de la lista se debe hacer nuevamente el procedimiento de comparaci´on-intercambio, en la siguiente tabla se describe el procedimiento. Valores comparados 33 > 88 88 > 22 88 > 54 88 > 99
¿Intercambio? No S´ı S´ı No
3
33, 33, 33, 33, 33,
Arreglo numeros 88, 22, 54, 88, 22, 54, 22, 88, 54, 22, 54, 88, 22, 54, 88,
99 99 99 99 99
Se puede observar que con una pasada m´as en la lista, los valores 22 y 33 se intercambiar´an, y la lista quedar´a en orden. Para ordenar completamente la lista en el pero caso, una en la cual los n´ umeros originales est´en en orden descendente, se requiere ir en la lista cuatro veces con el procedimiento comparaci´on-intercambio. A lo m´as, siempre se necesitar´a pasar por la lista tantas veces como su tama˜ no menos uno. Las siguientes sentencias muestran el procedimiento completo. for (a = 0; a < numeros.length - 1; ++a) for (b = 0; b < numeros.length - 1; ++b) if (numeros[b] > numeros[b+1]) { temp = numeros[b]; numeros[b] = numeros[b+1]; numeros[b+1] = temp; } Al usar el ordenamiento burbuja para ordenar cualquier arreglo en orden ascendente, el valor m´as grande “cae” en el fondo del arreglo despu´es de comparar cada par de valores consecutivos en el arreglo una vez. La segunda vez que se recorre el arreglo haciendo comparaciones, no hay necesidad de revisar el u ´ltimo par. Se garantiza que el valor m´as grande ya est´a en el fondo del arreglo. Se puede hacer el proceso de ordenamiento m´as eficiente usando una variable nueva para el ciclo for interno y reduciendo el valor en uno en cada ciclo a trav´es del arreglo. Las siguientes sentencias muestran como se realiza. int comparaciones = numeros.length - 1; for (a = 0; a < numeros.length - 1; ++a) { for (b = 0; b < comparaciones; ++b) if (numeros[b] > numeros[b+1]) { temp = numeros[b]; numeros[a] = numeros[b]; numeros[b] = temp; } --comparaciones; } 1.1.1.
Ordenamiento de arreglos de objetos
Se pueden ordenar arreglos de objetos de la misma forma como se ordenan arreglos de tipos primitivos. La diferencia principal se da cuando se hace la comparaci´on que determina si se hace el intercambio de dos elementos del arreglo. Con un arreglo de elementos primitivos, se comparan los dos elementos del arreglo para saber si est´an desordenados. Cuando los elementos del arreglo son objetos, se ordena usando un campo particular del objeto. Suponer que se ha creado una clase simple EmpleadoCompleto, c´odigo 1. La clase tiene cuatro campos de datos y los m´etodos set y get para los campos. 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
public c l a s s EmpleadoCompleto { private int numero ; private S t r i n g a p e l l i d o s ; private S t r i n g nombres ; private double s a l a r i o ; public int getNumero ( ) { return numero ; } public S t r i n g g e t A p e l l i d o s ( ) { return a p e l l i d o s ; } public S t r i n g getNombres ( ) { return nombres ; } public double g e t S a l a r i o ( ) { return s a l a r i o ; } public void setNumero ( int num ) { numero = num ; } public void s e t A p e l l i d o s ( S t r i n g aps ) { a p e l l i d o s = aps ; } public void setNombres ( S t r i n g nom ) { nombres = nom ; } public void s e t S a l a r i o ( double s a l ) { salario = sal ; } }
C´odigo 1: Clase EmpleadoCompleto. Se puede escribir un programa que contenga un arreglo de cinco objetos EmpleadoCompleto usando la siguiente sentencia: EmpleadoCompleto[] empleados = new EmpleadoCompleto[5]; Despu´es de asignar los n´ umeros de empleado, nombres y salarios a los objetos EmpleadoCompleto, se quiere ordenar los empleados por el salario. Se puede pasar el arreglo a un m´etodo ordenaBurbuja que est´a preparado para recibir el arreglo de EmpleadoCompleto, enseguida se muestra el m´etodo. public static void ordenaBurbuja(EmpleadoCompleto[] arreglo) { int a, b; EmpleadoCompleto temp; 5
int comparaciones = arreglo.length - 1; for (a = 0; a < arreglo.length - 1; ++a) { for (b = 0; b < comparaciones; ++b) if (arreglo[b].getSalario() > arreglo[b+1].getSalario()) { temp = arreglo[b]; arreglo[b] = arreglo[b+1]; arreglo[b+1] = temp; } --comparaciones; } } El m´etodo ordenaBurbuja es similar al m´etodo usado para un arreglo de tipos primitivos, pero hay tres diferencias. La cabecera del m´etodo ordenaBurbuja muestra que recibe un arreglo de tipo EmpleadoCompleto. La variable temp creada para intercambiar es del tipo EmpleadoCompleto. Observar que a pesar de solo los salarios de los empleados completos son comparados, no se intercambian u ´nicamente los salarios, se intercambian cada objeto EmpleadoCompleto. La comparaci´on para determinar si un intercambio se hace usa llamadas al m´etodo getSalario() para comparar el salario de cada objeto en el arreglo con el salario del objeto adyacente.
1.2.
Algoritmo de ordenamiento por inserci´ on
El ordenamiento burbuja es f´acil de entender y manipular, pero existen otros algoritmos de ordenamiento. El algoritmo ordenamiento por inserci´ on revisa cada elemento de la lista uno a la vez. Si un elemento est´a desordenado respecto a cualquiera de los elementos previos, se mueve cada elemento previo hacia abajo una posici´on y se inserta el elemento revisado. Este ordenamiento es similar a la t´ecnica que ser´ıa m´as probable de usar para ordenar un grupo de objetos manualmente. Por ejemplo, si una lista contiene los valores 2, 3, 1, y 4, y se quiere poner en orden ascendente se prueban los valores 2 y 3, pero no se mueven porque est´an en orden. Cuando se prueba el tercer valor, 1, se mueven 2 y 3 a posiciones posteriores y se inserta 1 a la primera posici´on. Las siguientes sentencias muestran la l´ogica que realiza un ordenamiento por inserci´on ascendente usando un arreglo de enteros de 5 elementos llamado numeros. Se supone que a, b, y temp han sido declarados como enteros. int [] numeros = {90, 85, 65, 95, 75}; 6
a = 1; while (a < numeros.length) { temp = numeros[a]; b = a - 1; while (b >= 0 && numeros[b] > temp) { numeros[b + 1] = numeros[b]; --b; } numeros[b + 1] = temp; ++a; } El ciclo externo del c´odigo anterior modifica una variable de control de ciclo a desde 1 hasta uno menos que el tama˜ no del arreglo. En el ciclo interno se van recorriendo los elementos de la lista parcialmente ordenada, empezando por el mayor, si estos son mayores que el elemento que se revisa. Este movimiento de los elementos es para generar un espacio dentro de la lista parcialmente ordenada d´onde ser´a puesto el elemento revisado. Si el elemento revisado es mayor que el elemento m´as grande de la lista parcialmente ordenada, entonces no se hace ning´ un cambio a la lista. En la siguiente tabla se muestra como funciona el algoritmo de ordenamiento por inserci´on, en la primera columna se muestra la lista parcial ordenada, en la segunda el elemento que se est´a revisando, en la tercera se indica si el elemento est´a ordenado y en la cuarta columna se muestra como se queda el “hueco” en la lista parcialmente ordenada para poner el elemento que se revisa. Lista parcial ordenada 90 85, 90 65, 85, 90 65, 85, 90, 95 65, 75, 85, 90, 95
2.
Elemento a insertar a 85 65 95 75
Lugar de Lista parcial inserci´ on modificada 0 , 90 , 85, 90 0 3 65, 85, 90, 1 65, , 85, 90, 95
Arreglos multidimensionales
Un arreglo declarado y creado por una sentencia como la siguiente: int [] numeros = new int [3]; se puede considerar como una columna de valores 7
numeros[0] numeros[1] numeros[2] y cuyos elementos son accedidos usando un s´olo sub´ındice, es un arreglo unidimensional o de una dimensi´ on. Se puede pensar en el tama˜ no del arreglo como su altura. Java tambi´en soporta arreglos de dos o m´as dimensiones. Los arreglo bidimensionales tienen dos o m´as columnas de valores como se muestra en el cuadro 1. Las dos dimensiones representan la altura y el ancho del arreglo. Otra forma de ver un arreglo bidimensional es como un arreglo de arreglos. Se deben usar dos sub´ındices cuando se accede un elemento en un arreglo bidimensional. Los matem´aticos llaman a un arreglo bidimensional una matriz o una tabla. Un arreglo bidimensional se usa en las hojas de c´alculo electr´onicas, como Excel. numeros[0][0] numeros[0][1] numeros[0][2] numeros[0][3] numeros[1][0] numeros[1][1] numeros[1][2] numeros[1][3] numeros[2][0] numeros[2][1] numeros[2][2] numeros[2][3] Cuadro 1: representaci´on de un arreglo bidimensional. Para declarar un arreglo bidimensional se ponen dos juegos de corchetes despu´es del tipo de arreglo. Por ejemplo, para el arreglo del cuadro 1 puede ser declarado como sigue, creando el arreglo llamado numeros que tiene tres renglones y cuatro columnas: int [][] numeros = new int [3][4]; Si no se proporcionan valores para los elementos en el arreglo bidimensional num´erico, los valores por defecto son cero. Se puede asignar otros valores a los elementos despu´es. Por ejemplo para poner el valor catorce al elemento del arreglo numeros que est´a en la primera columna del primer rengl´on se pone como numeros[0][0] = 14;. Alternativamente, se puede inicializar un arreglo bidimensional con valores cuando es creado. El siguiente c´odigo asigna valores a numeros al declarar el arreglo: int [][] numeros = { { 0, 2, 4, 6}, { 8, 10, 12, 14}, {16, 18, 20, 22} }; El arreglo numeros contiene tres renglones y cuatro columnas. Se contiene el conjunto entero de valores dentro de un juego de corchetes internos.El primer rengl´on del arreglo tiene los cuatro enteros 0, 2, 4, y 6. Observar que estos cuatro valores est´an puestos dentro de su propio juego de llaves interno para indicar que forman el primer rengl´on o el rengl´on cero. De igual forma se indican el resto de los renglones usando sus propios juegos de llaves. El valor de numeros[0][0] es 0, de numeros[0][1] es 2 y el de numeros[2][3] es 22. El valor 8
dentro del primer juego de corchetes que siguen el nombre del arreglo se refiere al rengl´on; el valor dentro de los segundos corchetes se refiere a la columna. Un ejemplo de como puede emplearse un arreglo bidimensional es el siguiente. Suponer que se tiene un edificio de departamentos con cuatro niveles, la planta baja ser´a referida como el piso cero, y los otros tres pisos como el uno, dos, y tres. Adem´as cada uno de los pisos tiene estudio (sin rec´amara) y departamentos con una y dos rec´amaras. La renta mensual para cada tipo de departamento var´ıa, entre m´as alto es el piso, mayor es la renta, y la renta es mayor para departamentos con m´as rec´amaras. La siguiente tabla muestra los montos de las rentas.
Piso 0 1 2 3
Sin Una rec´ amara rec´ amara 4000 4500 5000 5600 6250 6760 10000 12500
Dos rec´ amaras 5100 6300 7400 16000
Para determinar la renta de alg´ un inquilino, se necesita saber dos cosas: el piso en el cual el inquilino renta el departamento y la cantidad de rec´amaras en el departamento. Dentro de un programa Java, se puede declarar un arreglo de rentas usando el siguiente c´odigo: int [][] rentas = { {4000, 4500, 5100}, {5000, 5600, 6300}, {6250, 6760, 7400}, {10000,12500,16000} }; Si se declaran dos enteros llamados piso y recamaras, entonces cualquier renta de un inquilino puede ser referida como rentas[piso][recamaras]. El c´odigo 2 muestra una aplicaci´on que pide al usuario el n´ umero del piso y la cantidad de rec´amaras.
9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import j a v a x . swing . JOptionPane ; public c l a s s EncontrarRenta { public s t a t i c void main ( S t r i n g [ ] a r g s ) { int [ ] [ ] r e n t a s = { { 4 0 0 0 , 4 5 0 0 , 5 1 0 0 } , {5000 , 5600 , 6300} , {6250 , 6760 , 7400} , {10000 ,12500 ,16000} } ; String entrada ; int p i s o , r e c a m a r a s ; e n t r a d a = JOptionPane . sh ow In put Di al og ( null , ” I n g r e s e e l n´ u mero d e l p i s o ” ) ; piso = In tege r . parseInt ( entrada ) ; e n t r a d a = JOptionPane . sh ow In put Di al og ( null , ” I n g r e s e e l n´ u mero de r e c ´a maras ” ) ; rec a m a r a s = I n t e g e r . p a r s e I n t ( e n t r a d a ) ; JOptionPane . showMessageDialog ( null , ”La r e n t a d e l departamento con ” + r e c a m a r a s + ” rec´ a mara ( s ) en e l p i s o ” + p i s o + ” e s $ ” + r e n t a s [ p i s o ] [ recamaras ] ) ; } }
C´odigo 2: Aplicaci´on EncontrarRenta.
2.1.
Pasar un arreglo bidimensional a un m´ etodo
Para pasar un arreglo bidimensional a un m´etodo, s´olo se pasa el nombre del arreglo al igual como se hace con un arreglo unidimensional. Un m´etodo que recibe un arreglo bidimensional usa dos pares de corchetes siguiendo al tipo de dato en la lista de par´ametros de la cabecera del m´etodo. Por ejemplo, las siguientes cabeceras de m´etodos aceptan arreglos bidimensionales de int, double, y Empleado, respectivamente: public static void mostrarPuntuaciones(int [][] puntuaciones) public static boolean sonTodosPreciosAltos(double [][] precios) public static double calcularTotalNomina(Empleado[][] plantilla) Observar que los corchetes indicando el arreglo en la cabecera del m´etodo est´an vac´ıos. No hay necesidad de poner n´ umeros en los corchetes porque cada nombre de arreglo pasado es una direcci´on de memoria inicial. La forma como se manipulan los sub´ındices dentro del m´etodo determina como los renglones y columnas son accedidas.
10
2.2.
Campo length con un arreglo bidimensional
En un arreglo unidimensional tiene un campo length que guarda la cantidad de elementos en el arreglo. Con un arreglo bidimensional, el campo length guarda la cantidad de renglones en el arreglo. A su vez cada rengl´on tiene un campo length que guarda la cantidad de columnas en el rengl´on. Suponiendo que se declara un arreglo rentas como sigue: int [][] rentas = { {4000, 4500, 5100}, {5000, 5600, 6300}, {6250, 6760, 7400}, {10000,12500,16000} }; El valor de rentas.length es cuatro porque hay cuatro renglones en el arreglo. El valor de rentas[0].length es tres porque hay tres columnas en el primer rengl´on del arreglo rentas. Este valor es igual para el resto de los renglones. La aplicaci´on MostrarRentas, c´odigo 3, muestra una aplicaci´on que usa los campos length asociados con el arreglo rentas para mostrar todas las rentas. La variable piso var´ıa desde 0 hasta tres en el ciclo externo, y la variable recamaras va desde 0 hasta 2 en el ciclo interno. 1 2 3 4 5 6 7 8 9 10 11 12 13
public c l a s s MostrarRentas { public s t a t i c void main ( S t r i n g [ ] a r g s ) { int [ ] [ ] r e n t a s = { { 4 0 0 0 , 4 5 0 0 , 5 1 0 0 } , {5000 , 5600 , 6300} , {6250 , 6760 , 7400} , {10000 ,12500 ,16000} } ; int p i s o , r e c a m a r a s ; for ( p i s o = 0 ; p i s o < r e n t a s . l e n g t h ; ++p i s o ) f o r ( r e c a m a r a s = 0 ; r e c a m a r a s < r e n t a s [ p i s o ] . l e n g t h ;++r e c a m ar a s ) System . out . p r i n t l n ( ” P i s o ” + p i s o + ” Rec´a maras ” + r e c a m a r a s + ” Renta e s $ ” + r e n t a s [ p i s o ] [ r e c a m a r a s ] ) ; } }
C´odigo 3: Aplicaci´on MostrarRentas. En un arreglo bidimensional, cada rengl´on tambi´en es un arreglo. Se puede declarar en Java cada rengl´on para que tenga diferente longitud. Cuando un arreglo bidimensional tiene renglones de longitudes diferentes, este es un arreglo imperfecto porque al dibujar las terminaciones de cada rengl´on quedan desiguales. Se crea un arreglo imperfecto definiendo la cantidad de renglones para un arreglo bidimensional, pero no definiendo la cantidad de columnas en los renglones. Por ejemplo, suponer que se quieren guardar los primeros cinco renglones del Tri´ angulo de Pascal. Se podr´ıa definir el arreglo como sigue: int [][] triangulo = new int [5][]; 11
La sentencia declara un arreglo con cinco renglones, pero los renglones no han sido creados todav´ıa. Enseguida, se puede declarar los renglones individuales, dependiendo de cuantos valores tiene cada rengl´on en el tri´angulo de Pascal, se usa un ciclo for para escribir un c´odigo compacto. for (int i = 0; i < triangulo.length; ++i) triangulo[i] = new int [i + 1];
2.3.
Arreglos multidimensionales
Java tambi´en soporta arreglos con tres, cuatro y m´as dimensiones. El t´ermino general para arreglos con m´as de una dimensi´on es arreglos multidimensionales. Un arreglo de m´as de dos dimensiones se requiere cuando se quiere guardar las rentas de departamentos de varios edificios. Una expresi´on como rentas[edificio][piso][recamaras] se refiere a una renta espec´ıfica para un edificio cuyo n´ umero de edificio es guardada en la variable edificio y cuyos n´ umeros piso y rec´amaras est´an guardadas en las variables piso y recamaras. Java permite crear arreglos de cualquier tama˜ no siempre y cuando se tenga control de las variables que se ocupan como sub´ındices, y no se agote la memoria de la computadora.
3.
Clase Arrays
En muchas ocasiones se quiere realizar tareas similares con arreglos diferentes, por ejemplo, llenarlos con valores u ordenar sus elementos. Java proporciona la clase Arrays, la cual contiene varios m´etodos u ´tiles para manipular arreglos. El cuadro 2 muestra algunos de los m´etodos m´as u ´tiles de la clase Arrays. Para cada m´etodo de la columna izquierda de la tabla, tipo es para un tipo de dato; una versi´on sobrecargada que existe de cada m´etodo para cada tipo de dato apropiado. Por ejemplo, hay una versi´on del m´etodo sort() para ordenar arreglos de int, double, char, byte, float, long, short y Object. Los m´etodos en la clase Arrays son m´etodos static, por lo que se usan con el nombre de la clase sin instanciar un objeto Arrays. La clase Arrays est´a localizada en el paquete java.util, as´ı que se puede usar la sentencia import java.util.* para accederla. La aplicaci´on DemoArrays, c´odigo 4, muestra como se pueden usar algunos m´etodos de la clase Arrays. En la clase DemoArrays, el arreglo puntuaciones es creado para guardar cinco enteros. Luego, un mensaje y la referencia arreglo son pasados al m´etodo mostrar(). Al ejecutar la aplicaci´on se debe mostrar el arreglo original creado llenado con ceros. Despu´es se llama al m´etodo Arrays.fill() con el nombre del arreglo y el n´ umero 7, para luego mostrar el arreglo por segunda vez mostrando siete. Luego dos elementos, el segundo y el u ´ltimo, son cambiados a 3 y 8 respectivamente, y el arreglo se muestra nuevamente. Despues se llama al m´etodo Arrays.sort() para ordenar en forma ascendente el arreglo y se vuelve a mostrar el arreglo por cuarta ocasi´on. 12
M´ etodo static int binarySearch( tipo[] a, tipo llave) static boolean equals( tipo[] a, tipo[] b) static void fill( tipo[] a, tipo val) static void sort(tipo[] a) static void sort(tipo[] a, int inicial, int final)
Prop´ osito Busca en el arreglo indicado el valor dado por la llave usando b´ usqueda binaria. Se requiere que el arreglo est´e ordenado en forma creciente. Devuelve true si los dos arreglos especificados del mismo tipo son iguales en cantidad de elementos y elemento a elemento en la misma posici´on. Asigna el valor indicado a cada elemento del arreglo indicado. Ordena el arreglo indicado en orden ascendente. Ordena el rango, definido por los sub´ındices inicial a final, del arreglo indicado en orden ascendente.
Cuadro 2: m´etodos u ´tiles de la clase Arrays. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import j a v a . u t i l . Arrays ; public c l a s s DemoArrays { public s t a t i c void main ( S t r i n g [ ] a r g s ) { int [ ] p u n t u a c i o n e s = new int [ 5 ] ; mo s t r a r ( ” Arreglo o r i g i n a l : ” , puntuaciones ) ; Arrays . f i l l ( p u n t u a c i o n e s , 7 ) ; mo s t r a r ( ” Luego de l l e n a r con 7 : ” , p u n t u a c i o n e s ) ; puntuaciones [ 1 ] = 3; puntuaciones [ 4 ] = 8; mo s t r a r ( ” Luego de cambiar dos v a l o r e s : ” , p u n t u a c i o n e s ) ; Arrays . s o r t ( p u n t u a c i o n e s ) ; mo s t r a r ( ” Luego de o r d e n a r : ” , p u n t u a c i o n e s ) ; } public s t a t i c void m o s t r a r ( S t r i n g mensaje , int [ ] a r r e g l o ) { int tam = a r r e g l o . l e n g t h ; System . out . p r i n t ( mensaje ) ; for ( int v a l o r : a r r e g l o ) System . out . p r i n t ( v a l o r + ” ” ) ; System . out . p r i n t l n ( ) ; } }
C´odigo 4: Aplicaci´on DemoArrays. Los m´etodos binarySearch() de la clase Arrays son una manera conveniente para buscar en listas ordenadas de valores de diferentes tipos de datos. La lista deber´a estar en orden ascendente para usar el m´etodo binarySearch(). La forma como trabaja la b´ usqueda binaria usada por el m´etodo binarySearch() es como sigue. Se encuentra la posici´on central usando el tama˜ no del arreglo. Si un arreglo tiene una cantidad par de elementos, esta puede ser cualquiera de las dos posiciones centrales. 13
Se compara el dato que se est´a buscando con el elemento en la posici´on central del arreglo y se revisa si el valor del dato es menor que el valor de la posici´on central. Si el dato est´a por encima de la posici´on central, se encuentra la posici´on central de la mitad superior del arreglo; otro caso se encuentra la posici´on central de la mitad inferior. En cualquier caso, se compara el dato con la nueva posici´on central y se divide el ´area de b´ usqueda en la mitad nuevamente. Finalmente, se encuentra el valor o se determina que no est´a en el arreglo. Nota. Los programadores frecuentemente se refieren a la b´ usqueda binaria como un procedimiento “divide y vencer´as”. Si se ha jugado en alguna ocasi´on el juego en cual se trata de adivinar que n´ umero alguien pens´o, se podr´ıa haber usado una t´ecnica similar.
Suponer ahora una organizaci´on que usa seis c´odigos de una letra para productos. El c´odigo 5 contiene la aplicaci´on VerificarCodigo que revisa un c´odigo de producto dado por el usuario. El arreglo codigos guarda seis valores en orden ascendente. El usuario ingresa un c´odigo que es obtenido de la primera posici´on del String usando el m´etodo charAt(). Luego, el arr´eglo de caracteres v´alidos y el caracter ingresado por el usuario son pasados al m´etodo Arrays.binarySearch(). Si el caracter es encontrado en el arreglo, su posici´on es regresada, si el car´acter no es encontrado en el arreglo, un entero negativo es devuelto y la aplicaci´on muestra un mensaje de error. Nota. El entero negativo devuelto por el m´etodo binarySearch() cuando el valor no es encontrado es el equivalente negativo del tama˜ no del arreglo. En muchas aplicaciones, no se emplea el valor devuelto cuando no hay apareamiento, s´olo se considera si es negativo.
14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import j a v a . u t i l . Arrays ; import j a v a x . swing . JOptionPane ; public c l a s s V e r i f i c a r C o d i g o { public s t a t i c void main ( S t r i n g [ ] a r g s ) { char [ ] c o d i g o s = { ’B ’ , ’E ’ , ’K ’ , ’M’ , ’P ’ , ’T ’ } ; S t r i n g entrada , mensaje ; char c o d i g o U s u a r i o ; int p o s i c i o n ; e n t r a d a = JOptionPane . sh ow In put Di al og ( null , ” I n g r e s a r un c´ o d i g o de p r o d u c t o ” ) ; c o d i g o U s u a r i o = e n t r a d a . charAt ( 0 ) ; p o s i c i o n = Arrays . b i n a r y S e a r c h ( c o d i g o s , c o d i g o U s u a r i o ) ; i f ( p o s i c i o n >= 0 ) mensaje = ”La p o s i c i ´on de ” + c o d i g o U s u a r i o + ” e s ” + posicion ; else mensaje = c o d i g o U s u a r i o + ” e s un c´o d i g o i n v ´a l i d o ” ; JOptionPane . showMessageDialog ( null , mensaje ) ; } }
C´odigo 5: La aplicaci´on VerificarCodigo.
Nota. Los m´etodos sort() y binarySearch() en la clase Arrays son u ´tiles y permiten lograr resultados escribiendo menos instrucciones en vez de tener que escribir los m´etodos propios. Esto no significa una p´erdida de tiempo de lectura acerca de los m´etodos de ordenar y buscar vistos previamente. Entre m´as completo sea el entedimiento de como los arreglos son manipulados, las futuras aplicaciones ser´an m´as u ´tiles, eficientes y creativas.
4.
Clase ArrayList
La clase ArrayList puede ser usada para crear contenedores que guarden listas de objetos. Esta clase proporciona algunas ventajas sobre los arreglos, una de ellas es que es redimensionable din´ amicamente, es decir, que su tama˜ no puede cambiar durante la ejecuci´on del programa, esto significa que: Se puede agregar un elemento en cualquier punto de un contenedor ArrayList, y el tama˜ no del arreglo se expande autom´aticamente para acomodar el nuevo elemento. Se puede quitar un elemento en cualquier punto de un contenedor ArrayList, y el tama˜ no del arreglo se contrae autom´aticamente. Para usar la clase ArrayList se debe usar alguna de las dos sentencias de importaci´on: 15
import java.util.ArrayList; import java.util.*; Luego, para declarar un ArrayList, se puede usar el constructor por defecto, como se muestra en el siguiente ejemplo: ArrayList nombres = new ArrayList(); El constructor por defecto crea un ArrayList con una capacidad de 10 elementos. La capacidad del ArrayList es la cantidad de elementos que puede guardar sin tener que incrementar su tama˜ no. Por definici´on, la capacidad del ArrayList es mayor que o igual a su tama˜ no. Se puede tambi´en indicar una capacidad, como en la siguiente sentencia que declara un ArrayList que puede guarda 20 nombres: ArrayList nombres = new ArrayList(20); Si se sabe que se necesitar´an m´as de 10 elementos desde el principio, es m´as eficiente crear un ArrayList con una capacidad mayor que la asignada por el constructor. El cuadro 3 resume algunos de los m´etodos m´as u ´tiles del ArrayList, el tipo E indica que puede emplearse cualquier tipo, siempre y cuando al crear la colecci´on se indique el tipo particular que la colecci´on manejar´a, ver la secci´on 4.1 Limitaciones de la clase ArrayList M´ etodo Prop´ osito public void add(E e) Agrega el elemento indicado al final de la lista. public void add(int i, E e) Inserta el elemento e en la posici´on especificada. public E remove(int i) Quita y devuelve el elemento en la posici´on indicada. public void set(int i, E e) Reemplaza el elemento en posici´on indicada con el elemento e. public E get(int i) Devuelve el elemento de la posici´on indicada. public int size() Regresa la cantidad de elementos. Cuadro 3: M´etodos u ´tiles de la clase ArrayList.
Nota. La clase Object es la clase de Java m´as gen´erica, esta clase es la ra´ız de todas las clases.
Para agregar un elemento al final de un ArrayList se usa el m´etodo add. Suponer que se quiere agregar el nombre “Javier” al ArrayList llamado nombres, entonces usar la siguiente sentencia: 16
nombres.add("Javier"); Se puede insertar un elemento en una posici´on espec´ıfica en un ArrayList usando una versi´on sobrecargada del m´etodo add() que incluye la posici´on. Para insertar el nombre “Juana” en la primera posici´on del ArrayList nombres, usar la siguiente sentencia: nombres.add(0, "Juana"); Con algunos de los m´etodos descritos en la tabla 3, se recibe un mensaje de error si la posici´on es inv´alida para el ArrayList. Tambi´en est´an disponibles m´etodos para modificar y quitar elementos de un ArrayList. Con el m´etodo size() se puede saber la cantidad de elementos que tiene un ArrayList, no confundir con la capacidad del ArrayList. En la aplicaci´on DemoArrayList, codigo 6, se muestran algunos de los metodos mencionados. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import j a v a . u t i l . A r r a y L i s t ; public c l a s s DemoArrayList { public s t a t i c void main ( S t r i n g [ ] a r g s ) { A r r a y L i s t nombres = new A r r a y L i s t ( ) ; nombres . add ( ” Aixa ” ) ; // a g r e g a r a l f i n a l mo s t r a r ( nombres ) ; nombres . add ( ” A l e j a n d r o ” ) ; // a g r e g a r a l f i n a l d r a w b a c k mo s t r a r ( nombres ) ; nombres . add ( ”Ana Karen ” ) ; // a g r e g a r a l f i n a l mo s t r a r ( nombres ) ; nombres . add ( 2 , ” Benjamin ” ) ; // a g r e g a r en l a 3a p o s i c i ´on mo s t r a r ( nombres ) ; nombres . remove ( 1 ) ; // q u i t a r e l segundo nombre mo s t r a r ( nombres ) ; nombres . s e t ( 0 , ” C a r l o s ” ) ; // m o d i f i c a r l a primera p o s i c i ´on mo s t r a r ( nombres ) ; } public s t a t i c void m o s t r a r ( A r r a y L i s t nombres ) { System . out . p r i n t l n ( ”\ nEl tama˜ n o de l a l i s t a e s ” + nombres . s i z e ( ) ) ; for ( int i =0; i ” ) ; e n t r a d a = t e c l a d o . n e x t L i n e ( ) . toUpperCase ( ) ; mesNacimiento = Mes . v a l u e O f ( e n t r a d a ) ; System . out . p r i n t l n ( ”Ha i n g r e s a d o ” + mesNacimiento ) ; p o s i c i o n = mesNacimiento . o r d i n a l ( ) ; System . out . p r i n t l n ( mesNacimiento+” e s t ´a en l a p o s i c i ´on ”+p o s i c i o n ) ; System . out . p r i n t l n ( ”As´ı e l n´ u mero de mes e s ” + ( p o s i c i o n + 1 ) ) ; comparacion = mesNacimiento . compareTo ( Mes . JUN ) ; i f ( comparacion < 0 ) System . out . p r i n t l n ( mesNacimiento + ” est´ a a n t e s en e l a˜ n o que ” + Mes . JUN ) ; else i f ( comparacion > 0 ) System . out . p r i n t l n ( mesNacimiento + ” est´ a despu´e s en e l a˜ n o que ” + Mes . JUN ) ; else System . out . p r i n t l n ( mesNacimiento + ” e s ” + Mes . JUN ) ; }
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
}
C´odigo 8: La aplicaci´on DemoEnum. En la aplicaci´on, c´odigo 8, una enumeraci´on Mes es declarada en el m´etodo main(), una variable Mes es declarada en la l´ınea 7. En la l´ınea 13 la sentencia usa el ciclo for avanzado, el cual declara una variable local Mes llamada mes que toma el valor de cada elemento del arreglo devuelto por Mes.values() para mostrarlo. Luego en la aplicaci´on se pide que se ingresen las primeras tres letras de un mes, que son convertidas a may´ usculas. En la l´ınea 18 se usa el m´etodo valueOf() para convertir la cadena del usuario a un valor enumerado. En la l´ınea 20 se obtiene la posici´on del mes en la lista de enumeraci´on. En la l´ınea 23 se compara el mes ingresado con la constante JUN. Despu´es se tiene una sentencia if que muestra si el mes ingresado est´a antes o despu´es de JUN en la lista, o si es igual. Comenzando con Java 7, se pueden usar operadores de comparaci´on con constantes enume22
radas en vez de usar el m´etodo compareTo() para devolver un n´ umero. El siguiente ejemplo muestra lo comentado: if (mesNacimiento < Mes.JUN) System.out.println(mesNacimiento + " est´ a antes en el a~ no que " + Mes.JUN); Se pueden usar enumeraciones para controlar una estructura switch. La aplicaci´on DemoEnum2, c´odigo 9, declara una enumeraci´on Propiedad para una empresa de bienes ra´ıces. La aplicaci´on asigna uno de los valores a una variable Propiedad y luego usa una estructura switch para mostrar un mensaje. Ejecutar esta aplicaci´on para revisar lo se˜ nalado. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import j a v a . u t i l . Scanner ; public c l a s s DemoEnum2 { enum Propiedad {FAMILIA SOLA , FAMILIA MULTIPLE , CONDOMINIO, TERRENO, NEGOCIO} ; public s t a t i c void main ( S t r i n g [ ] a r g s ) { Propiedad propiedadEnVenta = Propiedad . FAMILIA MULTIPLE ; switch ( propiedadEnVenta ) { case FAMILIA SOLA : case FAMILIA MULTIPLE : System . out . p r i n t l n ( ” H o n o r a r i o s 5 %” ) ; break ; case CONDOMINIO: System . out . p r i n t l n ( ” H o n o r a r i o s 6 %” ) ; break ; case TERRENO: case NEGOCIO: System . out . p r i n t l n ( ”No manejamos e s t e t i p o de p r o p i e d a d ” ) ; } } }
C´odigo 9: Aplicacion DemoEnum2. Se tienen varias ventajas creando un tipo enumeraci´on. Para el caso de la enumeraci´on Mes mejora los programas en las siguientes formas: 1. Si no se crea un tipo enumerado para los valores del mes, se podr´ıa crear otro tipo, como int o String. El problema es que cualquier valor podr´ıa ser asignado a una variable int o String, pero a Mes s´olo se pueden asignar los doce valores permitidos. 2. Se podr´ıa tener un comportamiento sin sentido con los valores si no se crea un tipo enumerado para los valores del mes. Por ejemplo, si se usaron enteros para representar meses, se podr´ıa agregar, sustraer, multiplicar o dividir dos meses, lo cual no es l´ogico. 23
Los programadores dicen que usando enum hace los valores tipo seguro. Tipo seguro describe un tipo de dato para el cual solo comportamientos apropiados son permitidos. 3. Las constantes enum proporcionan una forma de autodocumentaci´on. Alguien leyendo el programa podr´ıa malinterpretar el significado de 6 como valor de mes, pero hay menos confusi´on cuando se usa el identificador JUN. 4. Al igual que con otras clases, se puede tambi´en agregar m´etodos y otros campos a un tipo enum.
24