Pontificia Universidad Cat´olica de Chile Escuela de Ingenier´ıa
Departamento de Ciencia de la Computaci´on
IIC1103 — Introducci´on a la Programaci´on
Cap´ıtulo 7: Ordenaci´
on y B´
usqueda
Resumen te´
orico
La operaci´on de ordenar consisten seleccionar de un conjunto de datos y ordenarlos bajo alg´un determinado criterio. Por ejemplo, cada elemento del conjunto de datos de una gu´ıa telef´onica tiene un nombre, una direcci´on y un n´umero de tel´efono; la gu´ıa telef´onica est´a dispuesta en orden alfab´etico de nombres; los elementos num´ericos se pueden ordenar en orden creciente o decreciente de acuerdo al valor num´erico del elemento. En terminolog´ıa de ordenaci´on, el elemento por el cual est´a ordenado un conjunto de datos (o se est´a buscando) se denomina clave.
Una colecci´on de datos (estructura) puede ser almacenada por ejemplo en un array (vector o tabla). Una estructura se dice que est´a ordenada por la clave k si la lista est´a en orden ascendente o descendente con respecto a esta clave. La colecci´onde datos se dice que est´a en orden ascendente si:i < jimplicaquek[i]<= k[j]. En cambio, est´a en orden descendente si:i > jimplicaquek[i]<=k[j] para todos los elementos de la colecci´on.
Por ejemplo, para una gu´ıa telef´onica, la lista est´a clasificada en orden ascendente por el campo clave k, donde k[i] es el nombre del abonado (apellidos, nombre). Un ejempo m´as simple de n´umeros es la colecci´on 4514213245 que se encuentra en orden ascendente y la colecci´on 757035161412 en cambio se encuentra en orden descendente.
B´
usqueda
Los computadores se emplean frecuentemente para almacenar grandes vol´umenes de datos. Tener mucha informaci´on implica tener dificultades para darle real utilidad.
Los algortimos de b´usqueda son fundamentales para poder localizar la informaci´on relevante en el menor tiempo posible.
Los algoritmos de ordenaci´on permiten mantener la informaci´on ordenada de tal forma que la b´usqueda se simplifique.
Dado un valor X, debolver el ´ındice del elemento X en el arreglo, en caso de existir. En caso contrario devolver no encontrado (-1). Se supone que en un arreglo no hay entradas duplicadas.
Existen varios procedimientos (algoritmos) de b´usqueda. Nosotros veremos dos: B´usqueda Lineal
B´usqueda Binaria
B´usqueda Lineal
Consiste en recorrer el arreglo hasta encontrar el elemento buscado (elemento por elemento). Si se llega hasta el ´ultimo elemento y a´un no se ha encontrado, entonces no se encuentra en la lista.
Declaraci´on 1 public int busquedaLineal ( String [] lista , String buscado ){ for ( int i = 0; i<lista.length ; i ++){
if( lista [i].equals( buscado )){ return i;} } return -1; } B´usqueda Binaria Restricci´on
• Los elementos de la lista deben estar previamente ordenados.
Algoritmo (asumiento orden ascendente)
1. Si el largo de la lista es 0 el programa termina. 2. Se calcula el ´ındice del elemento central.
3. Se compara el elemento buscado con el elemento central.
a) Si el elemento buscado es mayor al central, se vuelve al paso 1, pero con la sublista [central+ 1, largo]. b) Si el elemento buscado es menor al central, se vuelve al paso 1, pero con la sublista [0, central−1]. c) Si el elemento buscado es igual al central se retorna el ´ındice de este. Encontr´o el elemento.
Declaraci´on 2 public int busquedaBinaria ( String [ ] lista , String buscado ){ int inicial = 0;
int final = lista.length - 1; while ( inicial<final ){
int central = ( inicial + final )/2;
if( buscado.compareTo(lista[central]) >0){ inicial = central + 1; }
else if( buscado.compareTo(lista [central])<0){ final = central - 1;}
else{ return central;}
}
return -1;
}
Ordenaci´on
Dado un arreglo con N elementos, ordenarlo en funci´on de alguna caracter´ıstica com´un entre ellos. Por ejem-plo, escribir los valores en orden creciente (o decreciente).
Existen una gran cantidad de algoritmos que se diferencian en su rapidez y complejidad. Nosotros veremos dos:
Ordenaci´on por selecci´on
Si quisieramos ordenar ascendentemente: 1. Se busca el menor elemento.
2. Este elemento se cambia con el elemento en el primer lugar de la lista.
3. Se vuelve al paso 1, pero ahora la b´usqueda comienza en el siguiente elemento.
Se conoce comoSelection Sort.
Ordenaci´on por selecci´on
Declaraci´on 3 public void ordenacionPorSeleccion ( int [] lista ){ for ( int i = 0; i<lista.length -1; i ++){
// Buscamos el menor int menor = i;
for ( int j = i + 1; j <lista.length ; j + +){ if( lista [j]<lista [menor]){ menor = j;} // Cambiamos el menor
int aux = lista [i]; lista [i] = lista [menor]; lista [menor] = aux ;
} } }
Ordenaci´on por burbuja
Si quisieramos ordenar ascendentemente: 1. Se busca el menor elemento.
2. Este elemento se cambia con el elemento en el primer lugar de la lista.
3. Se vuelve al paso 1, pero ahora la b´usqueda comienza en el siguiente elemento.
Se conoce comoBuble Sort.
Ordenaci´on por burbuja
Declaraci´on 4 public void ordenacionPorBurbuja ( int [] lista ){ for ( int i = 1; i<lista . length ; i ++) {
for ( int j = i - 1; j ≥0; j - -){ if( lista [j +1]<lista [j]) {
// Intercambio int aux = lista [j +1]; lista [j +1] = lista [j]; lista [j] = aux ; } else{break;} } } }
Ordenaci´on por inserci´on
1. Inicialmente se tiene un solo elemento, que obviamente es un conjunto ordenado.
2. Despu´es, cuando hay k elementos ordenados de menor a mayor, se toma el elemento k+1 y se compara con todos los elementos ya ordenados
3. deteni´endose cuando se encuentra un elemento menor (todos los elementos mayores han sido desplaza-dos una posici´on a la derecha).
4. En este punto se inserta el elemento k+1 debiendo desplazarse los dem´as elementos.
Se conoce comoInsertion Sort.
Declaraci´on 5 public void insertSort (int[] v){ for (int i=1; i<v.length; i + +) {
int aux = v[i]; int j;
for (j=i-1; j>=0 && v[j] >aux; j - -){
v[j+1] = v[j];} v[j+1] = aux;
} }
Ejemplos
Problema 1: Patentes
Enunciado
Las antiguas patentes (de autom´oviles), por ejemploPL7812, est´an compuestas por unstringde dos carac-teres, en el ejemplo PL, y por un n´umero entero de cuatro d´ıgitos, en el ejemplo7812. Suponga que exista una clasePatentey otraTablaDePatentesde la siguiente forma:
public class Patente { private String letras ; private int numero ; public Patente() {}
public String o b t L e t r a s () { return letras ; } public int o b t N u m e r o () { return numero ; } }
public class T a b l a D e P a t e n t e s { private String[] tabla ;
public T a b l a D e P a t e n t e s() { tabla = new String[9999]; } public boolean buscar (Patente patente ) {}
otros metodos }
La idea es queTablaDePatentesalmacena en el atributo tabla todas las patentes autorizadas a estacionarse en el campus San Joaqu´ın. En particular, si la patente PL7812 est´a autorizada, entonces tabla[7812] = ‘‘PL’’, y si la patente JK2345 est´a autorizada, entonces tabla[2345] = ‘‘JK’’. Adem´as, si dos o m´as
patentes autorizadas tienen el mismo n´umero, entonces sus pares de letras aparecen consecutivamente en el
string correspondiente de tabla. Por ejemplo, si las patentes PL7812 y MB7812 est´an ambas autorizadas,
entonces tabla[7812] = ‘‘PLMB’’; y si las patentes JK2345, RC2345 y DW2345 est´an todas autorizadas,
entoncestabla[2345] = ‘‘JKRCDW’’.
Escriba el m´etodo buscar de la clase TablaDePatentes, que busca r´apidamente la Patente patente en
el atributotabla, y devuelvetrue (verdadero) si patente est´a entabla, yfalse(falso) en caso contrario.
Criterios de soluci´on
Lo primero que tenemos que hacer es declarar el m´etodo como nos indican en el enunciado. Luego, con los m´etodos de la clase Patente, obtenemos las letras y los n´umeros que la componen. Con el n´umero de la patente obtenemos lo almacenado en el arreglo y luego debemos recorrer este String obteniendo Substring de largo 2 e ir comparando cada substring con las letras de la patente a buscar. Si coincide con alguno retornamos true, de lo contrario retornamos false.
Posible soluci´on
public boolean buscar (Patente patente ) { int num = patente . o b t N u m e r o (); String letras = patente . o b t L e t r a s (); String validas = tabla [ num ];
if( validas !=null){
int largo = validas . length (); int k = 1;
while ( k < largo ) {
if ( letras . equals ( validas . s u b s t r i n g ( k - 1 , k + 1))) return true; k = k + 2; } } return false; }
Problema 2: Distancia entre puntos
Enunciado
Implemente un programa que busque la mayor distancia entre un grupo de puntos e identifique los puntos que est´an a la mayor distancia encontrada.
Para esto pida al usuario el n´umero de puntos a utilizar y luego cree cada uno de los puntos. Para hacerle m´as f´acil la implementaci´on cuenta con la clasePuntomostrada a continuaci´on. import i i c 1 1 0 3 P a c k a g e .*;
public class Punto { private double x ; private double y ;
public Punto (double x , double y ) { this. x = x ; this. y = y ; } public Punto () { double r ; r = A l e a t o r i o . real (0 , 1000); this. x = r ; r = A l e a t o r i o . real (0 , 1000); this. y = r ; }
public double getX () { return x ;
}
public double getY () { return y ;
}
public double d i s t a n c i a ( Punto p ) {
return ( Math . sqrt ((this. x - p . getX ()) * (this. x - p . getX ()) + (this. y - p . getY ()) * (this. y - p . getY ())));
} }
Luego de la ejecuci´on su programa debe mostrar un mensaje como el siguiente:
.\\La mayor distancia en el conjunto de puntos es 1058.91295913645 e involucra al punto 0: (10.920578500052901,15.64305239454644) y al punto 4: (644.0265655345464,864.4501354282548)
Criterios de soluci´on
Antes de buscar la distancia debemos crear los puntos necesarios. Para eso pedimos al usuario la cantidad de puntos a utilizar y luego con un ciclo creamos cada uno de los puntos.
Luego de que tenemos creados los puntos debemos recorrerlos y calcular la distancia entre cada uno de ellos. Para ello podemos utilizar un doble ciclo que recorra cada punto y luego lo compare con todos los puntos
Posible soluci´on
import i i c 1 1 0 3 P a c k a g e .*; public class Main {
public static void main (String[] args ) {
int n_puntos , i , j , p1 = 0 , p2 = 0; double d i s t _ m a x = 0;
Punto [] puntos ;
n _ p u n t o s = Usuario . entero (" Cuantos puntos usara para el e j e r c i c i o ? "); puntos = new Punto [ n _ p u n t o s ];
for ( i = 0; i < n _ p u n t o s ; i ++) { puntos [ i ] = new Punto (); } for ( i = 0; i < ( n _ p u n t o s - 1); i ++) { for ( j = i + 1; j < n _ p u n t o s ; j ++) { if ( puntos [ i ]. d i s t a n c i a ( puntos [ j ]) > d i s t _ m a x ) { d i s t _ m a x = puntos [ i ]. d i s t a n c i a ( puntos [ j ]); p1 = i ; p2 = j ; } } }
Usuario . m e n s a j e C o n s o l a (" La mayor d i s t a n c i a en el c o n j u n t o de puntos es "
+ d i s t _ m a x + " e i n v o l u c r a al punto " + p1 + " : ( "
+ puntos [ p1 ]. getX () + " ," + puntos [ p1 ]. getY () + " ) y al punto "
+ p2 + " : ( " + puntos [ p2 ]. getX () + " ," + puntos [ p2 ]. getY () + " ) ");
}
Problema 3: Diccionario
Enunciado
En el desarrollo de un editor de texto (como Word), se necesita incorporar un diccionario de manera de poder corregir la ortograf´ıa del documento. Para esto, se le pide implementar la clase Diccionario que pueda construirse con un tama˜no entero positivo dado, que ser´ıa la capacidad m´axima del diccionario. Se le pide implementar los m´etodos:
AgregarPalabra(String s)→agregasal diccionario si no existe ya en ´este y si es que queda espacio para agregarla.
String ConsultarPalabra(String s)→buscasen el diccionario. Si la encuentra, le avisa al usuario con un mensaje. Si no la encuentra, retorna la palabra que produjo el menor valor (en valor absoluto) como resultado de la comparaci´on usando el m´etodocompareTo.
Criterios de soluci´on
Para implementar el Diccionario lo m´as l´ogico es utilizar un arreglo de String para representar las palabras que lo componen.
Luego debemos implementar los m´etodos que nos piden.
M´etodoConsultarPalabra: Utilizamos una variable para almacenar la palabra a menor distancia de
la buscada. Recorremos todo el arreglo y revisamos la distancia de la siguiente palabra a la palabra buscada utilizando el m´etodo compareTo. Si la distancia es menor que la menor distancia encontrada
hasta el momento actualizamos la variable. Finalmente revisamos si la palabra encontrada es igual a la buscada, si es as´ı mostramos un mensaje indicando que encontramos la palabra.
M´etodoAgregarPalabra: Revisamos que el arreglo no est´e lleno y que la palabra ya no est´e en el dic-cionario. Para esto ´ultimo llamamos al m´etodoConsultarPalabray revisamos si la palabra retornada por este m´etodo es igual a la palabra que queremos agregar. Si no es as´ı agregamos el string al arreglo en la posici´on que corresponde.
Posible soluci´on import i i c 1 1 0 3 P a c k a g e .*; public class D i c c i o n a r i o { private String[] p a l a b r a s ; private int p r o x i m a P a l a b r a ; public D i c c i o n a r i o (int m a x P a l a b r a s ) { p a l a b r a s = new String[ m a x P a l a b r a s ]; p r o x i m a P a l a b r a = 0; }
public void A g r e g a r P a l a b r a (String s ) {
// R e v i s a m o s que se puedan i n s e r t a r mas p a l a b r a s y que la palabra no se // e n c u e n t r e en el arreglo
if ( p r o x i m a P a l a b r a < p a l a b r a s . length && ! C o n s u l t a r P a l a b r a ( s ). equals ( s )) { p a l a b r a s [ p r o x i m a P a l a b r a ] = s ;
// R e v i s a m o s si la palabra e n c o n t r a d a es la misma que b u s c b a m o s if ( p a l a b r a M e n o r . equals ( s )) {
Usuario . mensaje (" Se e n c o n t r o la palabra . "); }
return p a l a b r a M e n o r ; }
Problema 4: Analizar c´
odigo
Enunciado
Para el siguiente c´odigo
1. Describa, en castellano, que representa laClase A
2. Describa, en forma clara y precisa, qu´e hacen los m´etodosm1ym2 public class ClaseB {
private int x1 , x2 , x3 ; private String s ;
public ClaseB (String s , int x1 , int x2 , int x3 ) { this. s = s ; this. x1 = x1 ; this. x2 = x2 ; this. x3 = x3 ; } String getS () { return s ; } int getX1 () { return x1 ; } int getX2 () { return x2 ; } int getX3 () { return x3 ; } }
public class ClaseA { private ClaseB [] Arr ; private int tam ;
ClaseA (String s , int t ) { Arr = new ClaseB [ t ]; tam = 0;
}
public void m1 ( ClaseB b ) { Arr [ tam ++] = b ;
}
public void m2 () { int i , k ;
for ( k = Arr . length - 1; k > 0; k - -) { for ( i = 0; i < k ; i ++) {
ClaseB aux ;
if ( Arr [ i ]. getS (). c o m p a r e T o ( Arr [ i + 1]. getS ()) > 0) { aux = Arr [ i ];
Arr [ i ] = Arr [ i + 1]; Arr [ i + 1] = aux ; }
sistem´atico para no equivocarse, y cuidar interpretar correctamente los cambios en las variables, arreglos y en los objetos. Entendiendo bien cada paso de los m´etodos se puede interpretar qu´e est´an calculando.
Posible soluci´on
1. ClaseAes una lista/conjunto/colecci´on de elementos deClaseB. 2. m1agrega un elemento a la lista
Problema 5: Ordenando Strings
Enunciado
Usted recibe una matriz con el siguiente contenido: ’c’ ’b’ ’a’
’a’ ’z’ ’i’ ’z’ ’b’ ’a’
Donde cada car´acter es un char. Debe crear un programa que ordene alfab´eticamente esta matriz, pri-mero las filas y despu´es, sin cambiar las filas, las columnas, de tal manera que quede as´ı:
’a’ ’b’ ’c’ ’a’ ’b’ ’z’ ’a’ ’i’ ’z’
Aunque este problema se puede resolver de manera “sucia”, resu´elvalo pensando que este programa de-be ser aplicable a cualquier matriz de 3x3.
Criterios de soluci´on
Lo importante aqu´ı es darse cuenta de que cada fila de una matriz se puede tratar como un arreglo unidi-mensional. Para hacer esto ocupamos matriz[i][j] dejando el i est´atico. Con esto vamos a ir obteniendo los valores de nuestras filas. Luego para ordenarlas, se revisa uno por uno los caracteres y se le compara con todos los otros caracteres de la misma fila. En caso de que sea mayor, se pone a la derecha del car´acter revisado. Luego es cosa de hacer lo mismo pero ahora para las columnas.
Posible soluci´on
public class Ordenar {
public static boolean s o n I g u a l e s (char[] palabra1 , char[] palabra2 , int tamano ) { for (int i = 0; i < tamano ; i ++) {
if ( p a l a b r a 1 [ i ] != p a l a b r a 2 [ i ]) {// vemos letra por letra return false; // r e v i s a n d o que sean iguales
} }
return true; }
public static void main (String[] args ) { int t a m a n o M a t r i z = 3;
char[][] matriz = new char[ t a m a n o M a t r i z ][]; char[] fila1 = { ’c ’ , ’b ’ , ’a ’ };
char[] fila2 = { ’a ’ , ’z ’ , ’i ’ }; char[] fila3 = { ’z ’ , ’b ’ , ’a ’ };
matriz [0] = fila1 ;// i n i c i a l i z a m o s la matriz con las filas matriz [1] = fila2 ;
matriz [2] = fila3 ;
for (int i = 0; i < t a m a n o M a t r i z ; i ++) {
// en este for c o m p a r a m o s cada letra de cada fila for (int j = 0; j < t a m a n o M a t r i z ; j ++) {
for (int k = 0; k < t a m a n o M a t r i z ; k ++) { char a u x i l i a r ;
if ( matriz [ i ][ j ] < matriz [ i ][ k ]) {
// si es que la letra es menor se va para la derecha a u x i l i a r = matriz [ i ][ j ]; matriz [ i ][ j ] = matriz [ i ][ k ]; matriz [ i ][ k ] = a u x i l i a r ; } } } } for (int j = 0; j < t a m a n o M a t r i z ; j ++) {
// en este for c o m p a r a m o s cada fila con cada fila for (int k = 0; k < t a m a n o M a t r i z ; k ++) {
int i = 0;
if (! s o n I g u a l e s ( matriz [ j ] , matriz [ k ] , t a m a n o M a t r i z )) { // si son iguales no hacemos nada
while ( matriz [ j ][ i ] == matriz [ k ][ i ]) { // e s p e r a m o s a e n c o n t r a r una letra d i s t i n t a // ( por ejemplo cuando c o m p a r a m o s " abc " con " abz ") i ++;
}
char[] a u x i l i a r ;
if ( matriz [ j ][ i ] < matriz [ k ][ i ]) {
// si la letra es menor c a m b i a m o s la palabra a u x i l i a r = matriz [ j ]; matriz [ j ] = matriz [ k ]; matriz [ k ] = a u x i l i a r ; } } } } for (int i = 0; i < t a m a n o M a t r i z ; i ++) { // i m p r i m i m o s for (int j = 0; j < t a m a n o M a t r i z ; j ++) { System .out. print ( matriz [ i ][ j ]); }
System .out. println (" "); }
} }
Problema 6: Estad´ıstica de orden
Enunciado
Un n´umeroxes lai-´esima estad´ıstica de orden de un vectorAsi y s´olo sixes eli-´esimo n´umero m´as peque˜no del conjunto. As´ı, siA= (1,2,4,1), la primera (“1-´esima”) estad´ıstica de orden es 1, la segunda (“2-´esima”) estad´ıstica de orden es 1 y la tercera (“3-´esima”) estad´ıstica de orden es 2.
La operaci´on matricial$se define entre una matrizM den×my un vectorvdenelementos, y retorna un vector denelementos. La siguiente igualdad:
a11 a11 . . . a1m a21 a21 . . . a2m ... ... ... ... an1 an2 . . . anm $ v1 v2 ... vn = u1 u2 ... un ,
se cumple si y s´olo si el valorui es lavi-´esima estad´ıstica de orden de (ai1, ai2, . . . , aim).
Por ejemplo, la siguiente igualdad:
1 2 44 5 6 7 8 9 $ 32 1 = 45 7 ,
se cumple porque 4 es la tercera estad´ıstica de orden de (1,2,4), 5 es la segunda estad´ıstica de orden de (4,5,6) y 7 es la primera estad´ıstica de orden de (7,8,9).
Escriba un m´etodo con el encabezado:
public int [] estadistica (int[][] M, int [] V)
que recibe una matrizMy un vector V—representado como un arreglo de enteros—y retorna el resultado de M$Ven un arreglo. Puede suponer queMyVsiempre tendr´an dimensiones adecuadas y que los n´umeros en Vno piden estad´ısticas fuera de rango.
Criterios de soluci´on
Para encontrar la i-´esima estad´ıstica de orden de un vector lo que tenemos que hacer es ordenar el arreglo de menor a mayor. Para esto podemos utilizar cualquier c´odigo de ordenaci´on, como por ejemplo selection sort. Con el arreglo ya ordenado simplemente buscamos en la posici´on i-1 y tenemos la i-´esima estad´ıstica de orden.
Luego para implementar el m´etodo que nos piden tenemos que crear un nuevo arreglo para retornar de tama˜no adecuado y luego, con un ciclo, obtener la i´esima estad´ıstica de orden de la fila de la matriz correspondiente seg´un el valor en el arreglo recibido como par´ametro.
Posible soluci´on
public static int iesima (int[] A , int i ) { // aqui va c u a l q u i e r a l g o r i t m o de o r d e n a c i o n // en este ejemplo , o c u p a m o s s e l e c t i o n sort for (int j = A . length - 1; j >= 2; j - -) {
int max ; max = 0; for (int k = 1; k <= j ; k ++) { if ( A [ k ] > A [ max ]) max = k ; } int aux ; aux = A [ max ]; A [ max ] = A [ j ]; A [ j ] = aux ; } return A [ i - 1]; }
public static int[] e s t a d i s t i c a (int[][] M , int[] V ) { int i ;
int[] U = new int[ M . length ]; for ( i = 0; i < M . length ; i ++) {
U [ i ] = iesima ( M [ i ] , V [ i ]); }
return U ; }
Problema 7: Cadena Creciente
Enunciado
Dados un arreglolistacon nelementos y un par de ´ındicesi, j tal que 0≤i≤j < n, el arreglo formado por los elementoslista[i],lista[i+ 1],lista[i+ 2],. . ., lista[j] se dice una cadena creciente si:
lista[i] < lista[i+ 1] < lista[i+ 2] < · · · < lista[j].
Adem´as, se dice que el largo de esta cadena es el n´umero de elementos en ella, vale decir,j−i+ 1. En esta pregunta, usted debe implementar un m´etodo con encabezado:
public int[] encontrarCadenaCreciente(int[] lista)
que recibe como entrada un arreglo de n´umeros enteros, y retorna un arreglo conteniendo la cadena cre-ciente m´as larga en el arreglo de entrada. Por ejemplo, silista es un arreglo formado por los 12 elementos
{2, 3, 5, 4, 8, 18, 0, 2, 3, 4, 4, 6}, entonces el arreglo de salida deencontrarCadenaCrecientedebe ser el arreglo de 4 elementos{0, 2, 3, 4}, ya que esta es la cadena creciente m´as larga enlista.
Nota:Si existen varias cadenas crecientes enlistaque tienen largo m´aximo, su procedimiento debe retorna alguna de ellas.
Criterios de soluci´on Posible soluci´on
public int[] e n c o n t r a r C a d e n a C r e c i e n t e (int[] lista ) { int i , aux , inicio , largo ;
boolean entrar ;
i = 0; aux = 0; inicio = 0; largo = 0;
while ( i < lista . length ) { entrar = true;
while ( entrar ) {
if ( i == ( lista . length - 1)) { entrar = false;
} else if ( lista [ i ] < lista [ i + 1]) { i ++; } else { entrar = false; } } if (( i - aux ) + 1 > largo ) { largo = ( i - aux ) + 1; inicio = aux ; } i ++; aux = i ; }
Problema 8: OrdDup
Enunciado
Para representar listas de n´umeros enteros con repeticiones se ha decidido utilizar la siguiente estructura. Un arreglo de largo 2n tiene almacenados en la posici´on 2k (0 ¡= k ¡n) un n´umero de la lista y en 2k + 1 el n´umero de veces que este n´umero aparece repetido. Por ejemplo, el arreglo 2, 3, 5, 4 representa a la lista que tiene el n´umero 2 repetido 3 veces y el n´umero 5 repetido 4 veces.
En esta pregunta usted debe implementar el m´etodo:
public boolean OrdDup(int[] arreglo)
el cual recibe como par´ametro una listaarregloen el formato descrito arriba, y ordena esta lista de manera
ascendente. Por ejemplo, siarreglo= 3, 6, 2, 5, -1, 9, 7, 3, entonces despu´es de invocar al m´etodo se debe
tener quearreglo = -1, 9, 2, 5, 3, 6, 7, 3, que corresponde al orden ascendente de los n´umeros 3, 2, -1, 7 que conten´ıa la lista original, junto con los n´umeros correspondientes de repeticiones.
N´otese que OrdDup retorna un valor booleano. Como no todo arreglo representa una lista con
repeticio-nes,OrdDupretornatrue si arreglo corresponde a una lista con repeticiones, yfalseen caso contrario. En el primer caso, el m´etodo ordena arreglo, mientras que en el segundo lo deja intacto.
Importante: Para resolver esta pregunta puede suponer que arreglo no tiene n´umeros repetidos en las
componentes que representan los n´umeros de la lista. Por ejemplo,arreglopuede ser 12, 3, 5, 7 y no puede
ser 12, 3, 5, 4, 12, 1 ya que el 12 aparece dos veces. N´otese que arreglo puede ser 12, 3, 5, 3 ya que en este caso no hay repeticiones entre los n´umeros de la lista (12 y 5).
Dado lo anterior, para verificar si un arreglo almacena una lista con repeticiones hay que chequear dos condiciones: el largo del arreglo es par, y el n´umero de repeticiones de cada n´umero es mayor que 0. As´ı, por ejemplo, para los arreglos 2, 3, 5, 2, -1, 3, 8 y 2, 4, 1, 0, el m´etodoOrdDupdebe retornarfalse.
Criterios de soluci´on Posible soluci´on
public boolean OrdDup (int[] arreglo ) { if ( arreglo . length % 2 != 0) {
return (false); } else {
int i , k , aux , cant ;
for ( i = 0; i < arreglo . length / 2; i ++) { if ( arreglo [2 * i + 1] <= 0) {
return (false); }
}
for ( i = 1; i < arreglo . length / 2; i ++) { aux = arreglo [2 * i ];
cant = arreglo [2 * i + 1]; k = i - 1;
while ( k >= 0 && arreglo [2 * k ] > aux ) { arreglo [2 * k + 2] = arreglo [2 * k ]; arreglo [2 * k + 3] = arreglo [2 * k + 1]; k = k - 1; } arreglo [2 * k + 2] = aux ; arreglo [2 * k + 3] = cant ; } return (true); } }
Problema 9: Lista de Amigos
Enunciado
Se ha creado un programa para ayudarle a manejar una lista de contactos. El programa tiene las clases
DatosAmigoy Contactosque se describen a continuaci´on.
Los m´etodos que aparecen a continuaci´on ya han sido definidos e implementados, no es necesario que conozca la implementaci´on, pero s´ı c´omo utilizarlos.
ClaseDatosAmigo
Almacena la informaci´on sobre un amigo: nombre, apellido, celular y email. M´etodos
• public DatosAmigo(String no, String ap, int ce, String em) : Constructor de la clase;
recibe el nombre, apellido, celular y email de un amigo.
• public String getNombre(): Retorna el nombre del amigo. • public String getApellido(): Retorna el apellido del amigo. • public int getCelular(): Retorna el celular del amigo. • public String getEmail(): Retorna el e-mail del amigo.
ClaseContactos
Almacena la informaci´on de una lista de contactos. Atributos
• private DatosAmigo[] amigos: Lista de contactos, es un arreglo que almacena los datos de los amigos.
M´etodos
• public Contactos(): Constructor de la clase.
• public void AgregarAmigo(DatosAmigo da): Permite agregar la informaci´on de un amigo a la
lista de contactos; autom´aticamente agranda el arreglo para contener al nuevo amigo. Se le pide que implemente los siguientes m´etodos de la claseContactos:
public void MostrarEmailPorNombre(String nombre): Muestra en la consola el nombre, apellido y email de todos los amigos cuyo nombre (independiente de min´usculas o may´usculas) es igual al que se recibe como par´ametro.
public DatosAmigo[] RecordarEmail(String trozoEmail): Retorna un arreglo de objetos del tipo
DatosAmigo con todos los amigos cuyo email comienza con el trozo de email que se recibe como par´ametro. Puede suponer que todos los e-mails se escriben en min´usculas.
Para ayudarle a entender el funcionamiento deseado, se ilustra a continuaci´on el funcionamiento de estos m´etodos:
public static void main (String[] args ) { C o n t a c t o s lista ;
lista = new C o n t a c t o s (); D a t o s A m i g o amigo ;
amigo = new D a t o s A m i g o (" Marcos ", " S e p u l v e d a ", 1234 , " m a r c o s @ i n g . puc . cl "); lista . A g r e g a r A m i g o ( amigo );
amigo = new D a t o s A m i g o (" Karen ", " Palma ", 2345 , " k p a l m a @ i n g . puc . cl "); lista . A g r e g a r A m i g o ( amigo );
amigo = new D a t o s A m i g o (" Marcelo ", " Arenas ", 3456 , " m a r e n a s @ i n g . puc . cl "); lista . A g r e g a r A m i g o ( amigo );
amigo = new D a t o s A m i g o (" Rosa ", " Alarcon ", 4567 , " r a l a r c o n @ i n g . puc . cl "); lista . A g r e g a r A m i g o ( amigo );
amigo = new D a t o s A m i g o (" Matias ", " R e c a b a r r e n ", 5678 , " mat . r e c a @ g m a i l . com "); lista . A g r e g a r A m i g o ( amigo );
lista . M o s t r a r E m a i l P o r N o m b r e (" Marcos ");
D a t o s A m i g o [] listado = lista . R e c o r d a r E m a i l (" mar "); Usuario . m e n s a j e C o n s o l a (" L i s t a d o s de emails "); for (int i = 0; i < listado . length ; i ++) {
Usuario . m e n s a j e C o n s o l a ( listado [ i ]. g e t E m a i l ()); }
}
.
Salida en Consola
Emails por nombre - Marcos
Marcos S e p u l v e d a m a r c o s @ i n g . puc . cl L i s t a d o s de emails m a r c o s @ i n g . puc . cl m a r e n a s @ i n g . puc . cl Criterios de soluci´on Posible soluci´on
public void M o s t r a r E m a i l P o r N o m b r e (String nombre ) {
Usuario . m e n s a j e C o n s o l a (" Emails por nombre - " + nombre ); for (int i = 0; i < this. amigos . length ; i ++) {
D a t o s A m i g o am = this. amigos [ i ]; if ( am . g e t N o m b r e (). e q u a l s I g n o r e C a s e ( nombre )) { Usuario . m e n s a j e C o n s o l a ( am . g e t N o m b r e () + " \ t " + am . g e t A p e l l i d o () + " \ t " + am . g e t E m a i l ()); } } } public D a t o s A m i g o [] R e c o r d a r E m a i l (String t r o z o E m a i l ) { D a t o s A m i g o [] nuevo ; int n C o i n c i d e n c i a s = 0;
for (int i = 0; i < this. amigos . length ; i ++) { D a t o s A m i g o am = this. amigos [ i ];
if ( am . g e t E m a i l (). length () >= t r o z o E m a i l . length ()) {
String trozo = am . g e t E m a i l (). s u b s t r i n g (0 , t r o z o E m a i l . length ()); if ( trozo . e q u a l s I g n o r e C a s e ( t r o z o E m a i l )) { n C o i n c i d e n c i a s ++; } } } nuevo = new D a t o s A m i g o [ n C o i n c i d e n c i a s ]; int j = 0;
for (int i = 0; i < this. amigos . length ; i ++) { D a t o s A m i g o am = this. amigos [ i ];
if ( am . g e t E m a i l (). length () >= t r o z o E m a i l . length ()) {
String trozo = am . g e t E m a i l (). s u b s t r i n g (0 , t r o z o E m a i l . length ()); if ( trozo . e q u a l s I g n o r e C a s e ( t r o z o E m a i l )) {
nuevo [ j ] = am ; j ++;
} }
return nuevo ; }
Problema 10: M´
etodo desconocido
Enunciado
Para el siguiente c´odigo responda las siguientes preguntas: 1. ¿Qu´e muestra el programa en la consola?
2. ¿Qu´e hacemetodo1y c´omo lo hace?
public class P r i n c i p a l {
public static void main (String[] args ) { int[] a = { 10 , 25 , 17 , 7 , 15 , 6 , 9 , 12 }; metodo2 ( a );
metodo1 ( a ); metodo2 ( a ); }
private static void metodo1 (int[] a ) { boolean b = false; int c = 2; int d = a . length ; int e = 0 , f = 0; while ( b || ( d > 1)) { d = d / c ; if ( d == 0) { d = 1; } else if ( d == 9 || d == 10) { d = 11; } b = false;
int top = a . length - d ;
for (int i = 0; i < top ; i ++) { int j = i + d ; f ++; if ( a [ i ] > a [ j ]) { int t = a [ i ]; a [ i ] = a [ j ]; a [ j ] = t ; b = true; e ++; } } } Usuario . m e n s a j e C o n s o l a ( f ); Usuario . m e n s a j e C o n s o l a ( e ); }
private static void metodo2 (int[] a ) { String s = " ";
for (int i = 0; i < a . length ; i ++) { s += a [ i ] + " "; } Usuario . m e n s a j e C o n s o l a ( s ); } } Criterios de soluci´on Posible soluci´on 1. 10 25 17 7 15 6 9 12 31 8 6 7 9 10 12 15 17 25
2. El metodo1 ordena el arreglo recibido, para lo cual define un salto (la variabled), y luego compara
d, cuidando que no sea menor que 1. El algoritmo termina cuando des 1 y se compararon todos los elementos del arreglo con esa distancia sin realizar ninguna permutaci´on.
Problema 11: Tama˜
no ´
optimo
Enunciado
En el proceso productivo de una f´abrica de envases de lata, se requiere alimentar una m´aquina cortadora con la plancha de lata de tama˜no ´optimo, de modo de minimizar las p´erdidas. Una vez definido el tama˜no ´optimo, se ingresa a la m´aquina el tama˜no de la plancha de lata (largo y ancho) y el radio de cada c´ırculo, con lo cual la m´aquina cortar´a la mayor cantidad de c´ırculos tal como se muestra en la figura a continuaci´on.
Considerando que existen N tipos de planchas con medidas distintas (largo y ancho), se solicita crear un programa que determine cu´al es la medida optima de la plancha con que se debe alimentar la cortadora, para minimizar el material perdido. El programa debe calcular para cada tipo de plancha, la cantidad de c´ırculos, el ´area perdida y luego debe obtener un listado ordenado de menor a mayor material perdido, indicando las medidas de cada plancha, la cantidad de c´ırculos y la superficie perdida.
Datos entrada:
N: cantidad de tipos de planchas
Largo y ancho de cada uno de los N tipos de plancha en mil´ımetros. Radio de corte del c´ırculo requerido en mil´ımetros
Datos salida: Listado de todas las planchas ingresada ordenado de menor a mayor superficie perdida indicando para cada una:
Largo y Ancho de la plancha Cantidad de c´ırculos obtenidos.
Superficie perdida en mil´ımetros cuadrados
La cantidad de c´ırculos en la superficie es la siguiente:
Circulos= (Ancho/((2∗radio) + 0,5))∗(Largo/((2∗radio) + 0,5))
Obs.Se debe considerar que la m´aquina de corte necesita 5 mil´ımetros como m´ınimo entre cada c´ırculo para efectuar el corte.
Nota: Los datos de entrada deben ser pedidos al usuario y la informaci´on de salida debe aparecer en la consola.
Criterios de soluci´on Posible soluci´on
import i i c 1 1 0 3 P a c k a g e .*;
public class P r i n c i p a l {
public static void main (String[] args ) { // D e c l a r a c i o n e s i n i c i a l e s y datos int n , radio ;
n = Usuario . entero (" Ingrese tipos de p l a n c h a s : "); int[][] m = new int[ n ][4];
radio = Usuario . entero (" Ingrese radio : "); // llenar matriz de medidas
for (int i = 0; i < n ; i ++) {
m [ i ][0] = Usuario . entero (" Ingrese largo plancha : "); m [ i ][1] = Usuario . entero (" Ingrese ancho plancha : "); }
// calculo c a n t i d a d c i r c u l o s / plancha y s u p e r f i c i e perdida for (int i = 0; i < n ; i ++) {
m [ i ][2] = m [ i ][0] / (2 * radio + 10) * m [ i ][1] / (2 * radio + 10); m [ i ][3] = (int) ( m [ i ][0] * m [ i ][1] - Math . PI * Math . pow ( radio , 2)
* m [ i ][2]); }
// o r d e r n a r el arreglo de menor a mayor m a t e r i a l perdido int aux ; for (int i = 0; i < n - 1; i ++) { for (int j = i + 1; j < n ; j ++) { if ( m [ i ][3] > m [ j ][3]) { aux = m [ i ][3]; m [ i ][3] = m [ j ][3]; m [ j ][3] = aux ; aux = m [ i ][2]; m [ i ][2] = m [ j ][2]; m [ j ][2] = aux ; aux = m [ i ][1]; m [ i ][1] = m [ j ][1]; m [ j ][1] = aux ; aux = m [ i ][0]; m [ i ][0] = m [ j ][0]; m [ j ][0] = aux ; } } } // I m p r i m i r los datos o r d e n a d o s
Usuario . mensaje (" Largo Ancho c i r c u l o s Superf "); for (int i = 0; i < n ; i ++) { for (int j = 0; j < 4; j ++) { Usuario . mensaje ( m [ i ][ j ]); } } } }
Problema 12: B´
usqueda Matriz Irregular
Enunciado
Una matriz se dice irregular si algunas de sus filas no tienen el mismo n´umero de columnas. Por ejemplo, la siguiente es una matriz irregular:
Las matrices irregulares de n´umeros no negativos pueden ser almacenadas en arreglos de la siguiente forma. Dada una matriz M, cada fila de M es almacenada en posiciones contiguas del arreglo. Estas filas son almacenadas de manera ordenada, es decir, la fila i-´esima de M es almacenada en el arreglo antes que la fila j-´esima de M si i ¡j. Adem´as, el n´umero -1 es usado para indicar el fin de una fila. Por ejemplo, la matriz mostrada arriba es almacenada en el siguiente arreglo:
En esta pregunta usted deber´a implementar un m´etodo con encabezado
public int valor(int[] M, int i, int j)
que recibe como par´ametros una matriz irregular de n´umeros no negativos almacenados en el arreglo M (como se indica arriba), y las posiciones i, j, y retorna el n´umero que est´a en la fila i y columna j de M (recuerde que la primera fila de una matriz es la n´umero 0, al igual que para las columnas). Por ejemplo, si M es el arreglo mostrado arriba, entonces la llamada:
valor(M, 2, 2)
debe entregar como resultado 10, ya que el elemento en la fila 2 y columna 2 de M es 10.
Importante:El m´etodovalordebe retornar -1 si el par´ametro i o el par´ametro j est´an fuera de los rangos de la matriz M. Por ejemplo, si M es la matriz mostrada arriba, las invocaciones valor(M, 3, 0), valor(M, -1, 0), valor(M, 2, 4) deben retornar -1. Adem´as, su implementaci´on debe manejar correctamente el caso en que una fila no tiene elementos (lo cual aparece en el arreglo como dos n´umeros -1 contiguos).
Criterios de soluci´on Posible soluci´on
public int n u m e r o _ f i l a s (int[] M ) { int i , num ; num = 0; for ( i = 0; i < M . length ; i ++) if ( M [ i ] == -1) num ++; return num ; }
public int valor (int[] M , int i , int j ) { if ( i < 0 || i >= n u m e r o _ f i l a s ( M ) || j < 0)
return -1; else {
int fila , columna , pos ; fila = 0;
pos = 0;
while ( fila < i ) { if ( M [ pos ] == -1)
fila ++; pos ++; }
columna = 0;
while ( columna < j && M [ pos ] != -1) { columna ++; pos ++; } if ( M [ pos ] == -1) return -1; else return M [ pos ]; } }
Problema 13: Combate Naval
Enunciado
Usted deber´a implementar una versi´on simplificada del conocido juego “Combate Naval”. El juego consta de un tablero bidimensional sobre el cual se disponen estrat´egicamente barcos de combate, y el objetivo es que su rival no logre adivinar las posiciones de sus barcos, o bien, que no lo haga antes de que usted adivine las posiciones de los barcos de ´el.
Por tratarse de una versi´on simplificada, la implementaci´on que Usted haga resultar´a en un prototipo que no es completamente funcional. Sin embargo, su programa deber´a permitir agregar barcos a su tablero, quitar-los del mismo, mostrar informaci´on relevante que d´e cuenta del estado de una contienda, recibir y procesar correctamente un ataque, entre otras cosas.
Para la realizaci´on del laboratorio usted cuenta con la clase Principal, con su respectivo m´etodo main, y la claseOponente, que representa al rival de esta versi´on simplificada del juego, ambas ya implementadas. Observe que esta clase tiene como ´unica finalidad proporcionarle la posibilidad de probar algunos de los m´etodos que Usted deber´a implementar, mediante la generaci´on de ataques de naturaleza aleatoria.
import i i c 1 1 0 3 P a c k a g e .*;
public class O p o n e n t e {
public O p o n e n t e () { }
public int[] atacar (int largoMar , int a n c h o M a r ) { int[] c o o r d e n a d a s A t a q u e = new int[2];
c o o r d e n a d a s A t a q u e [0] = A l e a t o r i o . entero (0 , l a r g o M a r ); c o o r d e n a d a s A t a q u e [1] = A l e a t o r i o . entero (0 , a n c h o M a r ); return c o o r d e n a d a s A t a q u e ; } } import i i c 1 1 0 3 P a c k a g e .*; public class P r i n c i p a l {
public static void main (String[] args ) {
Usuario . mensaje (" B i e n v e n i d o a \" Combate Naval \" version 0 . 0 . 0 . 1 ! ");
int l a r g o T a b l e r o = Usuario . entero (" Ingrese el largo del Tablero de Juego : "); int a n c h o T a b l e r o = Usuario . entero (" Ingrese el ancho del Tablero de Juego : "); int m a x B a r c o s = Usuario . entero (" Ingrese la c a n t i d a d maxima de barcos " +
" que se puede agregar al Tablero : ");
while ( m a x B a r c o s *2 > l a r g o T a b l e r o || m a x B a r c o s *2 > a n c h o T a b l e r o ) { Usuario . mensaje (" La c a n t i d a d de barcos no puede ser s u p e r i o r a la " +
" \ nmitad de la d i m e n s i o n mas chica del Tablero de Juego ");
m a x B a r c o s = Usuario . entero (" Ingrese n u e v a m e n t e la c a n t i d a d maxima de barcos " +
" que se puede agregar al Tablero : "); }
Tablero tablero = new Tablero ( largoTablero , anchoTablero , m a x B a r c o s ); O p o n e n t e rival = new O p o n e n t e ();
int opcion = -1; while( opcion != 0) {
// Pedimos al usuario que elija una de las o p c i o n e s
opcion = Usuario . entero (" Que desea hacer ?\ n (1) Agregar un barco a la flota \ n " +
" (2) Poblar Tablero a l e a t o r i a m e n t e \ n " +
" (3) Quitar barco de la flota \ n " +
" (4) Mostrar el estado actual de la flota \ n " +
" (5) Mostrar el tablero \ n " +
" (6) Simular ataque \ n " +
" (0) Salir ");
if( opcion == 1) {
// Pedimos la i n f o r m a c i o n al usuario
int tipo = Usuario . entero (" Ingrese el tipo de barco que desea agregar : "); int o r i e n t a c i o n = Usuario . entero (" Ingrese su o r i e n t a c i o n :\ n (1) " +
char orienta ; if ( o r i e n t a c i o n == 1) orienta = ’V ’; else orienta = ’H ’; int fila = Usuario . entero (" Ingrese la fila en que desea que este : "); int columna = Usuario . entero (" Ingrese la columna en que desea que este : ");
// Creamos el barco y lo a g r e g a m o s Barco barco = new Barco ( tipo , orienta );
if( tablero . a g r e g a r B a r c o ( barco , fila , columna )) {
Usuario . mensaje (" El barco fue a g r e g a d o a la flota s a t i s f a c t o r i a m e n t e ! "); } else {
Usuario . mensaje (" No fue posible agregar el barco a la flota . " +
" \ n I n t e n t e con p a r a m e t r o s d i s t i n t o s . "); }
}
else if( opcion == 2) {
tablero = new Tablero ( largoTablero , anchoTablero , m a x B a r c o s ); tablero . p o b l a r T a b l e r o ();
}
else if( opcion == 3) {
// Pedimos el tipo del barca para i d e n t i f i c a r l o
int tipo = Usuario . entero (" Ingrese el tipo del barco que desea quitar : "); if( tablero . h u n d i r B a r c o ( tipo )) {
Usuario . mensaje (" El barco fue quitado de la flota . "); } else {
Usuario . mensaje (" No fue posible quitar el barco de la flota . "); }
}
else if( opcion == 4) {
tablero . m o s t r a r E s t a d o F l o t a (); }
else if( opcion == 5) { tablero . m o s t r a r T a b l e r o (); }
else if( opcion == 6) {
int[] ataque = rival . atacar ( l a r g o T a b l e r o - 1 , a n c h o T a b l e r o - 1); tablero . r e c i b i r A t a q u e ( ataque ); } } } } .
El programa lo dividiremos en 3 subconjuntos incrementales, de acuerdo a las necesidades se˜naladas. Se le recomienda no comenzar con el siguiente subconjunto sino hasta terminar y probar el funcionamiento correcto del subconjunto actual, a fin de que su desarrollo sea consistente.
Incremento 1
Para completar el primer incremento, deber´a implementar completamente la claseBarco. A trav´es de ´esta representaremos los barcos que participan del juego. Un barco queda caracterizado por sutipo y su orien-taci´on dentro del tablero de juego. Adem´as, resultar´a trascendente asociar a un barco tanto la cantidad de veces que ha sido impactado por un ataque rival, como su estado en un determinado instante: si a´un permanece a flote o se ya se ha hundido.
A continuaci´on se detallan los m´etodos que deber´a tener esta clase:
1. Barco(int tipo, char orientacion) →Constructor de la clase. Recibe la inicializaci´on de sus ca-racter´ısticas esenciales. Un barco se modela como una hilera de segmentos. Luego, su ancho es unitario
impactados todos los segmentos de un barco. Por ejemplo, si un barco tipo 4 es alcanzado 3 veces en un mismo segmento y una vez en cualquier otro, su estado debe cambiar (el barco se hunde).
3. M´etodos para poder obtener estas 4 caracter´ısticas (getters).
Por otro lado, para este incremento deber´a implementar parcialmente la claseTablero, que representar´a la superficie de juego. Esta clase queda caracterizada por sus dimensiones (largo y ancho) y por la lista de barcos que han sido creados y agregados al tablero (suflota).
Dado que el juego impide que dos barcos est´en ocupando un mismo espacio, deber´a modelar el tablero de manera tal que almacene informaci´on acerca de cu´ales posiciones se encuentran ocupadas y cu´ales no. Entonces, deber´a crear un arreglo bidimensional inicializado con el valor−1 en todas sus celdas para repre-sentar el vac´ıo inicial del tablero.
Al agregar un barco al tablero, deber´a poner en las posiciones correspondientes el ´ındice del barco den-tro de la flota. Por ejemplo, el primer barco agregado al tablero de juego utilizar´a el ´ındice 0 denden-tro de la lista, por lo que todas las posiciones que cubra este barco en el tablero de juego, deber´an contener el valor 0 en vez del valor−1.
El siguiente ejemplo le permitir´a entender mejor la situaci´on. Suponga que las dimensiones del tablero son 8de largopor 10 de ancho. Luego, se agrega un barco detipo 3 conorientaci´on ‘H’ en la posici´on(3,2), y otro detipo 5 con orientaci´on ‘V’ en la posici´on (0,6). En tal caso, el arreglo bidimensional quedar´ıa de la siguiente forma: −1 −1 −1 −1 −1 −1 1 −1 −1 −1 −1 −1 −1 −1 −1 −1 1 −1 −1 −1 −1 −1 −1 −1 −1 −1 1 −1 −1 −1 −1 −1 0 0 0 −1 1 −1 −1 −1 −1 −1 −1 −1 −1 −1 1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1 −1
La claseTablerodeber´a tener los siguientes m´etodos:
1. Tablero(int filas, int columnas, int barcos) →Constructor de la clase. Recibe las
dimensio-nes de la superficie de juego, y la cantidad m´axima de barcos que pueden ser agregados al tablero. En la implementaci´on dada del m´etodo main observar´a que este ´ultimo n´umero debe cumplir con cierta
restricci´on.
2. agregarBarco(Barco barco, int fila, int columna)→Permite agregarbarcoal tablero de juego a partir de la posici´on determinada por (fila, columna). Estas coordenadas corresponden directa-mente a los ´ındices del arreglo bidimensional, y seg´un la orientaci´on del barco representan el extremo superior (‘V’) o izquierdo (‘H’) de ´este. Verifica, de acuerdo a la cantidad m´axima de barcos que admite el tablero, si es posible agregar un nuevo barco al tablero y si el tipo de barco que se desea agregar es v´alido y no hay uno igual ya en la flota. Adem´as, revisa si las coordenadas son v´alidas, si no so-brepasar´a los l´ımites del tablero seg´un su orientaci´on, y si los espacios requeridos para la operaci´on est´an desocupados. Si no cumple con alguna de estas condiciones, retornar´afalse. En caso contrario,
inserta el barco al final de la lista (o flota) y actualiza las posiciones del arreglo bidimensional con el n´umero del ´ındice que ocup´o en la lista, y luego retornatrue.
3. void mostrarTablero() → Muestra en la consola una visualizaci´on gr´afica del estado actual del tablero, similar a la mostrada m´as arriba, pero reemplazando al imprimir los ‘−1’ por el caracter ‘˜’. Luego, para cada barco de la flota, muestra la cantidad de impactos recibidos por ataques del rival y, si corresponde, si ya fue hundido.
El barco 0 ha recibido 2 impactos El barco 1 ha recibido 0 impactos
El barco 2 ha recibido 4 impactos (ya hundido)
Incremento 2
Para completar el segundo incremento, su programa debe complementar la claseTablerocon los siguientes m´etodos:
1. boolean hundirBarco(int tipo)→ Permite quitar un barco del tablero, como tambi´en de su lista asociada, solamente seg´un el tipo del barco a eliminar dada la caracter´ıstica de que en la flota no puede haber m´as de un barco por cada tipo posible. Si el barco no existe en la flota retornafalse. Observe que al remover un barco de la lista, debe actualizarla de manera que todos los barcos agregados con posterioridad al que se quiere eliminar sean desplazados dentro de la lista, a fin de que no quede un espacio vac´ıo en la lista ni se desperdicie un ´ındice. En relaci´on a esto ´ultimo, no olvide hacer lo propio con la representaci´on de la flota en el arreglo bidimensional, disminuyendo los ´ındices de los barcos que correspondan en una unidad. Finalmente, retornatrue.
2. void mostrarEstadoFlota()→Muestra en la consola el estado de la flota. Para ello, crea un arreglo auxiliar con los barcos activos de la flota (aquellos que a´unsobreviven), y lo ordena crecientemente seg´un la cantidad de impactos que a´un pueden recibir. Finalmente, muestra un resumen como el siguiente:
Los barcos de la Flota a´un activos son: Barco Tipo 4 ha recibido 1 impactos Barco Tipo 5 ha recibido 3 impactos Barco Tipo 3 ha recibido 2 impactos
Incremento 3
Para completar el tercer incremento, su programa debe agregar los siguientes m´etodos a la claseTablero: 1. void poblarTablero() → Permite poblar un Tablero de acuerdo a sus par´ametro de inicializaci´on.
Ocupando el m´etodo Aleatorio.enterodel paquete del curso y el m´etodo agregarBarco ya
imple-mentado por Usted, genera la informaci´on necesaria para crear los barcos que corresponda y agregarlos exitosamente a la flota.
2. void recibirAtaque(int[] coordenadas) →Permite conocer los resultados de un ataque del
opo-nente. Revisa si en el arreglo bidimensional la posici´on representada por(coordenadas[0], coordenadas[1])
est´a vac´ıa u ocupada por alg´un segmento de un barco. Si el ataque fue certero, invoca al m´etodo
recibirImpacto()del barco afectado. Finalmente, seg´un sea el caso, muestra en la consola una de las
siguientes alternativas de mensaje:
Ataque a (6, 0): AGUA! Ataque a (7, 1): FUEGO!
El barco atacado a´un sobrevive! Ataque a (2, 4): FUEGO!
private char o r i e n t a c i o n ; private boolean d e r r i b a d o ; private int n u m I m p a c t o s ;
public Barco (int tipo , char o r i e n t a c i o n ) { this. tipo = tipo ;
this. o r i e n t a c i o n = o r i e n t a c i o n ; this. d e r r i b a d o = false; this. n u m I m p a c t o s = 0; } public void r e c i b i r I m p a c t o () { n u m I m p a c t o s ++; if ( n u m I m p a c t o s == tipo ) d e r r i b a d o = true; }
public int getTipo () { return tipo ; }
public int g e t O r i e n t a c i o n () { return o r i e n t a c i o n ; }
public boolean i s D e r r i b a d o () { return d e r r i b a d o ; }
public int g e t N u m I m p a c t o s () { return n u m I m p a c t o s ; } }
import i i c 1 1 0 3 P a c k a g e .*;
public class Tablero {
private int[][] s u p e r f i c i e ; private Barco [] flota ; private int c a n t i d a d B a r c o s ;
public Tablero (int filas , int columnas , int barcos ) {
// I n i c i a l i z a m o s los a t r i b u t o s de acuerdo a las c a r a c t e r i s t i c a s i n d i c a d a s en el e n u n c i a d o flota = new Barco [ barcos ];
c a n t i d a d B a r c o s = 0;
s u p e r f i c i e = new int[ filas ][ c o l u m n a s ];
for(int i = 0; i < s u p e r f i c i e . length ; i ++) for(int j = 0; j < s u p e r f i c i e [0]. length ; j ++)
s u p e r f i c i e [ i ][ j ] = -1; }
public boolean a g r e g a r B a r c o ( Barco barco , int fila , int columna ) { // R e v i s a m o s si aun no se han a g r e g a d o todos los barcos p o s i b l e s if ( c a n t i d a d B a r c o s == flota . length )
return false;
// R e v i s a m o s si ya existe un barco del mismo tipo en la flota , // o si el tipo no esta p e r m i t i d o para el tamano de la flota for (int i = 0; i < c a n t i d a d B a r c o s ; i ++)
if ( barco . getTipo () == flota [ i ]. getTipo () ||
barco . getTipo () < 2 || barco . getTipo () > flota . length + 1) return false;
// R e v i s a m o s que la p o s i c i o n en que se quiere agregar un barco sea p e r m i t i d a
if ( fila < 0 || fila >= s u p e r f i c i e . length || columna < 0 || columna >= s u p e r f i c i e [0]. length ) return false;
// D e p e n d i e n d o de la o r i e n t a c i o n y el tipo del barco que se quiere agregar , r e v i s a m o s que " alcance " // a ser i n c l u i d o en la p o s i c i o n deseada
if ( barco . g e t O r i e n t a c i o n () == ’V ’) {
if( fila + barco . getTipo () > s u p e r f i c i e . length ) return false;
}
else { // barco . g e t O r i e n t a c i o n () == ’H ’
if ( columna + barco . getTipo () > s u p e r f i c i e [0]. length ) return false;
}
// R e v i s a m o s si el espacio n e c e s a r i o para agregar el barco se e n c u e n t r a d e s o c u p a d o if ( barco . g e t O r i e n t a c i o n () == ’V ’) {
for (int i = 0; i < barco . getTipo (); i ++) { if ( s u p e r f i c i e [ fila + i ][ columna ] != -1)
} }
else { // barco . g e t O r i e n t a c i o n () == ’H ’ for (int i = 0; i < barco . getTipo (); i ++) {
if ( s u p e r f i c i e [ fila ][ columna + i ] != -1) return false;
} }
// Como a esta altura ya se han s u p e r a d o con exito las r e s t r i c c i o n e s de factibilidad , // a g r e g a m o s el barco al tablero ...
if ( barco . g e t O r i e n t a c i o n () == ’V ’) { for (int i = 0; i < barco . getTipo (); i ++)
s u p e r f i c i e [ fila + i ][ columna ] = c a n t i d a d B a r c o s ; }
else { // barco . g e t O r i e n t a c i o n () == ’H ’ for (int i = 0; i < barco . getTipo (); i ++)
s u p e r f i c i e [ fila ][ columna + i ] = c a n t i d a d B a r c o s ; } // ... y a la flota flota [ c a n t i d a d B a r c o s ] = barco ; c a n t i d a d B a r c o s ++; return true; }
public boolean h u n d i r B a r c o (int tipo ) {
// B u s c a m o s el barco a hundir de acuerdo a su tipo int indice = -1;
for (int i = 0; i < c a n t i d a d B a r c o s ; i ++) { if ( flota [ i ]. getTipo () == tipo ) {
indice = i ; break; } }
// Si indice c o n t i n u a en -1 , e n t o n c e s el barco que se desea e l i m i n a r no esta en la flota if ( indice == -1)
return false;
// Lo q u i t a m o s de la flota ( c o r r e m o s un espacio " a la i z q u i e r d a " a todos los barcos a g r e g a d o s // con p o s t e r i o r i d a d al barco i m p a c t a d o por el enemigo )...
for (int i = indice ; i < cantidadBarcos -1; i ++) flota [ i ] = flota [ i +1];
cantidadBarcos - -;
// ... y lo q u i t a m o s del tablero
for (int i = 0; i < s u p e r f i c i e . length ; i ++) { for (int j = 0; j < s u p e r f i c i e [ i ]. length ; j ++) {
// Si e n c o n t r a m o s una seccion del barco i m p a c t a d o por el enemigo , la " h u n d i m o s " if ( s u p e r f i c i e [ i ][ j ] == indice )
s u p e r f i c i e [ i ][ j ] = -1;
// Si e n c o n t r a m o s una seccion de un barco que fue a g r e g a d o p o s t e r i o r m e n t e a la flota , // a c t u a l i z a m o s su indice en el tablero else if ( s u p e r f i c i e [ i ][ j ] > indice ) s u p e r f i c i e [ i ][ j ] = s u p e r f i c i e [ i ][ j ] - 1; } } return true; } public void m o s t r a r E s t a d o F l o t a () { Usuario . m e n s a j e C o n s o l a (" ");
int v = 0; for (int i = 0; i < c a n t i d a d B a r c o s ; i ++) { if (! flota [ i ]. i s D e r r i b a d o ()) { b a r c o s A c t i v o s [ v ] = flota [ i ]; v ++; } }
// U t i l i z a n d o BubbleSort , o r d e n a m o s el arreglo de acuerdo al e n u n c i a d o Barco aux ;
for (int i = 0; i < b a r c o s A c t i v o s . length - 1; i ++) { for (int j = 0; j < b a r c o s A c t i v o s . length - 1 - i ; j ++) {
// O r d e n a m o s c r e c i e n t e m e n t e segun la c a n t i d a d de i m p a c t o s que aun pueden recibir if( b a r c o s A c t i v o s [ j ]. getTipo () - b a r c o s A c t i v o s [ j ]. g e t N u m I m p a c t o s () > b a r c o s A c t i v o s [ j + 1]. getTipo () - b a r c o s A c t i v o s [ j + 1]. g e t N u m I m p a c t o s ()) { aux = b a r c o s A c t i v o s [ j ]; b a r c o s A c t i v o s [ j ] = b a r c o s A c t i v o s [ j + 1]; b a r c o s A c t i v o s [ j + 1] = aux ; } } }
// M o s t r a m o s el estado de la flota en consola
Usuario . m e n s a j e C o n s o l a (" Los barcos de la Flota que aun s o b r e v i v e n son : "); for(int i = 0; i < b a r c o s A c t i v o s . length ; i ++)
Usuario . m e n s a j e C o n s o l a (" Barco Tipo " + b a r c o s A c t i v o s [ i ]. getTipo () + " , ha r e c i b i d o "
+ b a r c o s A c t i v o s [ i ]. g e t N u m I m p a c t o s () + " i m p a c t o s "); }
public void m o s t r a r T a b l e r o () { Usuario . m e n s a j e C o n s o l a (" ");
// M o s t r a m o s cada c a s i l l e r o del tablero , r e e m p l a z a n d o los c a r a c t e r e s segun c o r r e s p o n d a for (int i = 0; i < s u p e r f i c i e . length ; i ++) {
String linea = " ";
for (int j = 0; j < s u p e r f i c i e [ i ]. length ; j ++) { if ( s u p e r f i c i e [ i ][ j ] == -1) linea += " ~ "; else linea += s u p e r f i c i e [ i ][ j ] + " "; } Usuario . m e n s a j e C o n s o l a ( linea ); }
// De manera similar , m o s t r a m o s el estado de cada barco for (int i = 0; i < c a n t i d a d B a r c o s ; i ++) {
String linea = " El barco " + i + " ha r e c i b i d o " + flota [ i ]. g e t N u m I m p a c t o s () + " i m p a c t o s "; if ( flota [ i ]. i s D e r r i b a d o ()) linea += " ( hundido ) "; Usuario . m e n s a j e C o n s o l a ( linea ); } } public void p o b l a r T a b l e r o () { Barco b a r c o A u x ; char o r i e n t a c i o n ; int fila , columna ;
// A g r e g a m o s todos los barcos a la flota for (int i = 0; i < flota . length ; i ++) {
boolean a g r e g a r O K = false; while (! a g r e g a r O K ) { // D e f i n i m o s la o r i e n t a c i o n del barco if ( A l e a t o r i o . entero (0 , 1) == 0) o r i e n t a c i o n = ’V ’; else o r i e n t a c i o n = ’H ’; // Creamos el barco b a r c o A u x = new Barco ( i + 2 , o r i e n t a c i o n ); // D e f i n i m o s las c o o r d e n a d a s
fila = A l e a t o r i o . entero (0 , s u p e r f i c i e . length ); columna = A l e a t o r i o . entero (0 , s u p e r f i c i e [0]. length );
a g r e g a r O K = a g r e g a r B a r c o ( barcoAux , fila , columna ); }
} }
Usuario . m e n s a j e C o n s o l a (" ");
// Si la celda esta vacia , el ataque no produjo danos if ( s u p e r f i c i e [ c o o r d e n a d a s [0]][ c o o r d e n a d a s [1]] == -1) {
Usuario . m e n s a j e C o n s o l a (" Ataque a ( " + c o o r d e n a d a s [0] + " , " + c o o r d e n a d a s [1] + " ): AGUA ! "); return;
}
// El ataque cayo sobre uno de los barcos de la flota
flota [ s u p e r f i c i e [ c o o r d e n a d a s [0]][ c o o r d e n a d a s [1]]]. r e c i b i r I m p a c t o ();
Usuario . m e n s a j e C o n s o l a (" Ataque a ( " + c o o r d e n a d a s [0] + " , " + c o o r d e n a d a s [1] + " ): FUEGO ! "); if ( flota [ s u p e r f i c i e [ c o o r d e n a d a s [0]][ c o o r d e n a d a s [1]]]. i s D e r r i b a d o ())
Usuario . m e n s a j e C o n s o l a (" El barco atacado se ha hundido ! "); else
Usuario . m e n s a j e C o n s o l a (" El barco atacado aun s o b r e v i v e ! "); }
Problema 14: Grupos de Novatos
Enunciado
Como bien Ud. sabe, los novatos de Ingenier´ıa son acogidos durante el primer a˜no por el Cuerpo de Tutores. En particular, durante el primer semestre, est´an en un grupo con otros novatos desarrollando un proyecto para el curso Desaf´ıos de la Ingenier´ıa. Para formar los grupos, el Cuerpo de Tutores considera una serie de variables, tales como paquete al que pertenecen los novatos, el sexo, si son de regiones, etc. Todos los grupos tienen novatos del mismo paquete. Usted deber´a implementar un programa que permita agrupar a los novatos seg´un ciertas variables, adem´as de permitir realizar operaciones sobre sus datos. El proceso suele ser m´as complicado que el que Ud. implementar´a.
Para la realizaci´on del ejercicio usted cuenta con 3 clases ya implementadas que se detallan a continua-ci´on.
public class D B N o v a t o s {
// Esta clase r e p r e s e n t a los datos de los novatos private Novato [] novatos ;
public D B N o v a t o s () { // C o n s t r u c t o r de la clase }
public void c a r g a r D a t o s () { ... // Carga los datos de los novatos }
public Novato [] g e t L i s t a N o v a t o s () { ... // Retorna la lista de los novatos } }
public class Novato {
private int id ; private String nombre ; private int puntaje ;
public Novato (int id , String nombre , int puntaje ) { ... } public int getId () { return id ; }
public void setId (int id ) { this. id = id ; } public String g e t N o m b r e () { return nombre ; }
public void s e t N o m b r e (String nombre ) { this. nombre = nombre ; } public int g e t P u n t a j e () { return puntaje ; }
public void s e t P u n t a j e (int puntaje ) { this. puntaje = puntaje ; }
// Retorna en un string los datos del novato public String g e t D a t o s N o v a t o () {
return " id : " + id + " \ tnombre : " + nombre + " \ t p u n t a j e : " + puntaje ; }
}
import i i c 1 1 0 3 P a c k a g e .*; public class P r i n c i p a l {
public static void main (String[] args ) {
// I n i c i a l i z a c i o n de la base de datos y o r d e n a m i e n t o de la lista . D B N o v a t o s db = new D B N o v a t o s ();
// El numero de p a q u e t e s es 5 , y el de grupos por paquete es 4 A r m a P a q u e t e s G r u p o s apg = new A r m a P a q u e t e s G r u p o s (4 , 5);
apg . o r d e n a r L i s t a ( db . g e t L i s t a N o v a t o s ()); apg . a r m a r G r u p o s ( apg . g e t L i s t a O r d e n a d a ());
Usuario . mensaje (" Base de datos de novatos cargada y o r d e n a d a segun p u n t a j e s ");
int opcion = 0;
// Menu de o p c i o n e s while ( opcion != 4) {
opcion = Usuario
. entero (" Ingrese opcion :\ n1 : Listar segun p u n t a j e s \ n2 : I n t e r c a m b i a r novatos \ n3 : "+
" Listar todos los novatos \ n4 : Salir "); while ( opcion < 1 || opcion > 4)
opcion = Usuario
. entero (" OPCION I N V A L I D A \ n I n g r e s e opcion :\ n1 : Listar segun p u n t a j e s \ n2 : "+
" I n t e r c a m b i a r novatos \ n3 : Listar todos los novatos \ n4 : Salir ");
case 1:
int nMenor = Usuario . entero (" Ingrese cota menor de puntaje "); int nMayor = Usuario . entero (" Ingrese cota mayor de puntaje "); apg . l i s t a S e g u n R a n g o s ( nMenor , nMayor );
break;
case 2:
int n1Id = Usuario
. entero (" Ingrese primer novato a i n t e r c a m b i a r "); int n2Id = Usuario
. entero (" Ingrese segundo novato a i n t e r c a m b i a r "); apg . i n t e r c a m b i a r N o v a t o s ( apg . g e t N o v a t o ( n1Id ) ,
apg . g e t N o v a t o ( n2Id )); break; case 3: apg . i m p r i m i r L i s t a C o m p l e t a (); default: break; } } } } .
El programa lo dividiremos en 3 subconjuntos incrementales, de acuerdo a las necesidades se˜naladas. Se le recomienda no comenzar con el siguiente subconjunto sino hasta terminar y probar el funcionamiento correcto del subconjunto actual, a fin de que su desarrollo sea consistente.
Incremento 1
Para completar el primer incremento, deber´a implementar parte de la clase ArmaPaquetesGrupos, la cual permitir´a realizar las tareas previamente descritas. Utiliza intensivamente la clase Novato, que ya viene implementada y cuyos m´etodos podr´a apreciar en el respectivo archivo .java; NO LA MODIFIQUE. A continuaci´on se detallan los m´etodos que deber´a tenerArmaPaquetesGrupospara este primer incremento:
1. public ArmaPaquetesGrupos(int gruposPorPqte, int nroPaquetes) → Constructor de la clase. gruposPorPqteespecifica el n´umero m´aximo de grupos que tendr´a cada paquete, nroPaquetes
espe-cifica el m´aximo de paquetes en los que se dividir´a a los novatos.
2. public Novato[] ordenarLista(Novato[] listaNovatos)→Ordena la lista de novatos seg´un
pun-taje de forma decreciente1. Retorna un arreglo unidimensional de tipoNovato.
3. public void armarGrupos(Novato[] listaNovatos)→Dado un arreglo de objetos de tipoNovato2,
define a qu´e paquete y grupo pertenece cada novato. Para cumplir esta tarea, Ud. deber´a tener como
atributo de esta clase un arreglo bidimensional de tipo int denominado relNovatoGrupo, donde el
primer ´ındice represente el Id del novato3, y el segundo corresponda al n´umero de paquete, ambos
numerados desde el cero. El valor almacenado en cada celda de relNovatoGrupo[id][paquete]
co-rresponde al n´umero de grupo asignado. Para poder llenar la matriz anterior, debemos determinar primero a qu´e paquete pertenece cada alumno, y luego asignarle un n´umero de grupo v´alido para ese paquete.
Para armar un paquete, la idea es que todos tengan personas de todos los rangos de puntajes (altos, medios y bajos). Para efectos de este ejercicio, el n´umero de paquete para cada novato se
• indexOrdencorresponde al ´ındice del arreglolistaNovatos[], pasado como par´ametro. • nroPaquetesel m´aximo de paquetes, especificado al momento de la construcci´on de la clase. El% corresponde al operador de m´odulo de Java.
El n´umero de grupo para cada novato se calcula de la siguiente forma:
#grupo= ((#novatosP aquete) %(gruposP orP qte) + 1) + (#paquete)∗(gruposP orP qte)
donde:
• #novatosPaqueteespecifica la cantidad de novatos del paquete correspondiente, a los cuales
ya se les ha asignado grupo4.
• gruposPorPqtecorresponde al atributo especificado en el constructor de la clase. • #paquetees el n´umero de paquete calculado previamente para el novato en cuesti´on.
Asuma para este c´alculo que habr´a suficientes alumnos para que exista el n´umero de grupos por paquetes se˜nalado al momento de la creaci´on de la clase.
A continuaci´on veremos una representaci´on ficticia de relNovatoGrupo[][], para 10 alumnos, 5
pa-quetes y 2 grupo de alumnos por paquete5:
1 0 0 0 0 0 3 0 0 0 0 0 0 0 9 0 0 0 0 10 2 0 0 0 0 0 0 5 0 0 0 0 0 7 0 0 4 0 0 0 0 0 0 8 0 0 0 6 0 0
Las filas representan a los novatos (indexados por su Id), y las columnas representan a los paque-tes (indexados por su n´umero). Por ejemplo, podemos ver que la segunda fila corresponde al alumno con Id = 1. Si nos desplazamos hacia la derecha por esta misma fila, vemos que todos los n´umeros son 0, salvo uno (en este caso, el 3, que corresponde a su n´umero de grupo). Podemos tambi´en revisar que la columna asociada a esta celda es la que corresponde al n´umero de paquete (en este caso, como es la segunda columna, corresponde al paquete 1). Note que un novato puede pertenecer a un s´olo grupo y a un s´olo paquete.
4. public void imprimirListaCompleta()→ Imprime en consola la lista completa de alumnos, orde-nada decrecientemente por puntaje. Un ejemplo de output para un alumno es el siguiente:
id: 8 nombre: VICENCIO ALBERTO puntaje: 818
Al final de la lista, se debe imprimir el n´umero de alumnos mostrados en consola (por ejemplo:** Se encontraron 20 registros)
5. Debe agregar m´etodos para poder obtener los atributos que debe tener la clase (getters).
Si´entase libre de agregar otros m´etodos seg´un estime necesario para realizar de mejor forma su tarea, pero debe cumplir como m´ınimo con los espec´ıficados (que deben ce˜nirse fielmente a las definiciones). Esto es v´alido tambi´en para los otros 2 incrementos.
4Este valor no incluye al novato sobre el que se est´a calculando su n´umero de grupo.