El siguiente programa fue el resultado de un proceso de análisis (comprensión del problema), diseño (de un algoritmo en pseudocódigo), implementación (traducción del algoritmo a Java) y pruebas (de cada uno de los anteriores). El rastro del diseño se puede ver en los comentarios en el código.
1000 o masa <= 0 o altura <= 0 o altura > 300cm if ( mass > 1000.0 || mass <= 0.0 || heightCm <= 0.0 || heightCm > 300.0 ) { // Informar datos invalidos System.out.println("invalid data"); } else { // Los datos son validos // Convertir la altura a metros double heightMeters = heightCm / 100.0; // Calcular el indice de masa corporal (bmi) double bodyMassIndex = mass / (heightMeters * heightMeters); // Informar la masa, la altura en centrimetros, y el bmi System.out.printf("%5.2f ", bodyMassIndex); // Imprimir el estado nutricional de acuerdo a los rangos de la OMC if ( bodyMassIndex < 18.5 ) { // Informar infrapeso System.out.println("underweight"); } if ( bodyMassIndex >= 18.5 && bodyMassIndex < 25.0 ) { // Informar normal System.out.println("normal"); } if ( bodyMassIndex >= 25.0 && bodyMassIndex < 30.0 ) { // Informar sobrepeso System.out.println("overweight"); } if ( bodyMassIndex >= 30.0 ) { // Informar obesidad System.out.println("obese"); } } } // Close the standard input input.close(); } } ]]>
Produce números aleatorios enteros en un rango dado, por ejemplo, si el rango es 00 a 75 (inclusive), producirá números válidos para un bingo.
Los operadores ariméticos (+, -, *, /, %) funcionan únicamente con tipos de datos primitivos (enteros y flotantes). Sólo existe una única excepción: el operador + puede concatenar textos (String). Los demás operadores de Java sólo trabajan con tipos de datos primitivos: operadores relacionales (==, >, >=, <, <=), operadores lógicos (!, &&, ||). Sin embargo hay que tener algunos cuidados. Por ejemplo, el operador de igualdad == sólo funciona con enteros, y en caso de flotantes sólo funciona cuando se compara contra 0.0.
1000.0 ? 1000.0 : mass; /* mass > 1000.0 ? System.out.println("invalid data") : System.out.println("valid data"); // bmi = mass / h*h* */ int a = 5; int x = ++a - a--; System.out.printf("a=%d x=%d\n", a, x); // Close the standard input input.close(); } } ]]>
Los operadores de asignación (=) tienen variantes cortas para cada operador aritmético (+=, -=, *=, /=, %=), y operadores de pre/post-incremento (++) y pre/post-decremento (--). Estos últimos deben evitarse combinar en una misma expresión.
Se mostró cómo crear un ejercicio desde cero. Las instrucciones se encuentran en la sección Ejercicios inventados del curso. El ejercicio completo puede obtenerse en:
Se crearon 11 casos de prueba, varios con datos inválidos. El siguiente programa usa excepciones de Java para reaccionar a esas condiciones anormales.
try { // Read the width of the rectangle, stop if it is negative int width = input.nextInt(); if ( width < 0 ) throw new RuntimeException("invalid data"); // If there is another number int height = width; if ( input.hasNextInt() ) { // Read the height, stop if it is negative height = input.nextInt(); if ( height < 0 ) throw new RuntimeException("invalid data"); } // Read the fill character char fillChar = input.next().charAt(0); // Read the boolean that indicates if the rectangle is filled // We read the boolean as 0 or 1, and stop if something else is given int filled = input.nextInt(); if ( filled != 0 && filled != 1 ) throw new RuntimeException("invalid data"); boolean isFilled = filled == 1; // Print each of the height rows for ( int row = 1; row <= height; ++row ) { // Print each of the width columns in the row for ( int column = 1; column <= width; ++column ) { // If rectangle is filled, or row is first or last one, or column is first or last one if ( isFilled || row == 1 || row == height || column == 1 || column == width ) { // Print the fill character System.out.print(fillChar); } else { // Print a space System.out.print(' '); } } // Print a new line System.out.println(); } } catch ( java.util.InputMismatchException exception ) { System.out.println("invalid data"); } catch ( java.util.NoSuchElementException exception ) { System.out.println("missing data"); } catch ( RuntimeException exception ) { System.out.println( exception.getMessage() ); } //
// Close the standard input
input.close();
}
}
]]>
El siguiente ejemplo muestra el resultado de cómo un problema se dividió en varios subproblemas recursivamente. Un subproblema que requiere su propio proceso de análisis, diseño e implementación, es buen canditato para implementarse como una subrutina. Cada subrutina debe tener su propia documentación. Aquí se usa notación JavaDoc.
/** * Run the solution. This method is called from main() */ public void run() { // Create object to read data from standard input input = new Scanner(System.in); // Read the n, r long n = input.nextLong(); long r = input.nextLong(); // Print the table header System.out.printf("%33s%21s%n", "No repetitions", "With repetitions"); // Print permutations printPermutations(n, r); // Print combinations printCombinations(n, r); // Close the standard input input.close(); } /** * Print the table row for the permutations with and without repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ public void printPermutations(long n, long r) { System.out.print("Permutations"); // Calculate and print permutations without repetition printPermutationsNoRepetition(n, r); // Calculate and print permutations with repetition printPermutationsWithRepetition(n, r); } /** * Calculate and print permutations without repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ public void printPermutationsNoRepetition(long n, long r) { long permutations = factorialDivision(n, n - r); System.out.printf("%21d", permutations); } /** * Calculate and print permutations with repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ public void printPermutationsWithRepetition(long n, long r) { long permutations = calculatePermutationsWithRepetition(n, r); System.out.printf("%21d%n", permutations); } /** * Calculate the number of permutations with repetition of r in n as n^r * * @see printPermutations() for details about the parameters * * @return The amount of permutations */ public long calculatePermutationsWithRepetition(long n, long r) { long power = 1; for ( long counter = 1; counter <= r; ++counter ) power = power * n; return power; } /** * Returns the factorial of an integer number. The factorial of n is * the multiplication of all integers less or equals to n * * @param n The number to get the factorial from. n must be positive, * otherwise an RuntimeException is thrown. If n is greater than 20 * it will overflow and an invalid result is produced * * @return The factorial of n */ public long factorial(long n) { long factorial = 1; for ( long counter = 1; counter <= n; ++counter ) { factorial *= counter; } return factorial; } /** * Optimizes the calculus of the division of two factorial parts in the form: * (numerator)! / (denominator)! * * @see factorialDivision(long, long, long) */ public long factorialDivision(long numerator, long denominator) { /* long factorial = 1; if ( numerator >= denominator && denominator > 0 ) { for ( long counter = numerator; counter > 1 && counter > denominator; --counter ) { factorial *= counter; } } else { factorial = 0; } return factorial; */ return factorialDivision(numerator, denominator, 1); } /** * Optimizes the calculus of the division with three factorial parts in the form: * (numerator)! / ( (denominator1)! (denominator2)! ) * * This function cancels the common numerators and denominators before multiply * them for getting the resulting factorial. Therefore it avoids overfloating * long values. * * @param numerator The numerator before calculating its factorial * @param denominator1 The first denominator part before calculating its factorial * @param denominator2 The second denominator part before calculating its factorial * @return The result of the division n! / (d1! d2!) */ public long factorialDivision(long numerator, long denominator1, long denominator2) { long factorial = 1; long minimum = Math.min(denominator1, denominator2); long maximum = Math.max(denominator1, denominator2); if ( numerator >= maximum && maximum > 0 ) { for ( long counter = numerator; counter > maximum; --counter ) { factorial *= counter; } factorial /= factorial(minimum); } else { factorial = 0; } return factorial; } /** * Print the table row for the combinations with and without repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ public void printCombinations(long n, long r) { System.out.print("Combinations"); // Calculate and print combinations without repetition printCombinationsNoRepetition(n, r); // Calculate and print combinations with repetition printCombinationsWithRepetition(n, r); } /** * Calculate and print combinations without repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ void printCombinationsNoRepetition(long n, long r) { long combinations = factorialDivision(n, r, n - r); System.out.printf("%21d", combinations); } /** * Calculate and print combinations with repetition * * @param n The number of elements to choose from. n must be positive * otherwise, it will print invalid data. * * @param r The number of chosen elements from n. r must be positive */ void printCombinationsWithRepetition(long n, long r) { long combinations = factorialDivision(n + r - 1, r, n - 1); System.out.printf("%21d", combinations); } // } ]]>
/** * Run the solution. This method is called from main() */ public void run() { // Create object to read data from standard input this.input = new Scanner(System.in); // This code replicates the input to the standard output // Modify this code to solve the problem while ( this.input.hasNextLong() ) { long number = this.input.nextLong(); testIterativeFactorial(number); testTailRecursiveFactorial(number); testRecursiveFactorial(number); } // Close the standard input this.input.close(); } public void testIterativeFactorial(long number) { long start = System.currentTimeMillis(); BigInteger factorial = iterativeFactorial( number ); double duration = (System.currentTimeMillis() - start) / 1000.0; System.out.printf( "Iterative factorial:%n%,d: %.3fs%n%n", factorial, duration ); } public void testTailRecursiveFactorial(long number) { long start = System.currentTimeMillis(); BigInteger factorial = tailRecursiveFactorial( number ); double duration = (System.currentTimeMillis() - start) / 1000.0; System.out.printf( "%n%nTail Recursive factorial:%n%,d: %.3fs%n%n", factorial, duration ); } public void testRecursiveFactorial(long number) { long start = System.currentTimeMillis(); BigInteger factorial = recursiveFactorial( number ); double duration = (System.currentTimeMillis() - start) / 1000.0; System.out.printf( "%n%nRecursive factorial:%n%,d: %.3fs%n%n", factorial, duration ); } public static BigInteger iterativeFactorial(long number) { BigInteger result = BigInteger.valueOf(1); for ( long current = 1; current <= number; ++current ) result = result.multiply( BigInteger.valueOf(current) ); return result; } public static BigInteger recursiveFactorial(long number) { if ( number <= 0 ) return BigInteger.valueOf(1); else return BigInteger.valueOf(number).multiply( recursiveFactorial(number - 1) ); } public static BigInteger tailRecursiveFactorial(long number) { return tailRecursiveFactorial(number, BigInteger.valueOf(1)); } public static BigInteger tailRecursiveFactorial(long number, BigInteger accumulator) { if ( number <= 0 ) return accumulator; else return tailRecursiveFactorial( number - 1, accumulator.multiply( BigInteger.valueOf(number) ) ); } // } ]]>
Nota: El compilador de Java no soporta recursión de cola al momento de escribir (nov-2017).
/** * Run the solution. This method is called from main() */ public void run() { // Create object to read data from standard input this.input = new Scanner(System.in); // This code replicates the input to the standard output // Modify this code to solve the problem while ( this.input.hasNextLong() ) { long number = this.input.nextLong(); System.out.printf("%,d: %,d%n", number, recursiveFibonacci(number)); System.out.printf("%,d: %,d%n%n", number, tailRecursiveFibonacci(number)); } // Close the standard input this.input.close(); } public static BigInteger iterativeFactorial(long number) { BigInteger result = BigInteger.valueOf(1); for ( long current = 1; current <= number; ++current ) result = result.multiply( BigInteger.valueOf(current) ); return result; } public static BigInteger recursiveFibonacci(long number) { if ( number <= 1 ) return BigInteger.valueOf(number); else return recursiveFibonacci(number - 1).add( recursiveFibonacci(number - 2) ); } public static BigInteger tailRecursiveFibonacci(long number) { return tailRecursiveFibonacci(number, BigInteger.valueOf(0), BigInteger.valueOf(1)); } public static BigInteger tailRecursiveFibonacci(long number, BigInteger previous, BigInteger result) { if ( number <= 0 ) return previous; else if ( number == 1 ) return result; else return tailRecursiveFibonacci(number - 1, result, previous.add(result) ); } // } ]]>
/** * Run the solution. This method is called from main() */ public void run() { // Create object to read data from standard input this.input = new Scanner(System.in); // This code replicates the input to the standard output // Modify this code to solve the problem while ( this.input.hasNextLong() ) { BigInteger base = this.input.nextBigInteger(); long exponent = this.input.nextLong(); System.out.printf("%,d^%,d: %,d%n", base, exponent, recursivePower(base, exponent)); System.out.printf("%,d^%,d: %,d%n", base, exponent, efficientTailRecursivePower(base, exponent)); } // Close the standard input this.input.close(); } public static BigInteger iterativeFactorial(long number) { BigInteger result = BigInteger.valueOf(1); for ( long current = 1; current <= number; ++current ) result = result.multiply( BigInteger.valueOf(current) ); return result; } public static BigInteger recursivePower(BigInteger base, long exponent) { if ( exponent <= 0 ) return BigInteger.valueOf(1); else return base.multiply( recursivePower(base, exponent - 1) ); } public static BigInteger efficientRecursivePower(BigInteger base, long exponent) { if ( exponent <= 0 ) return BigInteger.valueOf(1); else if ( exponent == 1 ) return base; else if ( exponent % 2 == 0 ) return efficientRecursivePower(base.multiply(base), exponent / 2); else return base.multiply( efficientRecursivePower(base, exponent - 1) ); } public static BigInteger efficientTailRecursivePower(BigInteger base, long exponent) { return efficientTailRecursivePower(base, exponent, BigInteger.valueOf(1)); } public static BigInteger efficientTailRecursivePower(BigInteger base, long exponent, BigInteger result) { if ( exponent <= 0 ) return result; else if ( exponent % 2 == 0 ) return efficientTailRecursivePower(base.multiply(base), exponent / 2, result); else return efficientTailRecursivePower(base, exponent - 1, base.multiply(result) ); } // } ]]>
1000 o masa <= 0 o altura <= 0 o altura > 300cm if ( this.person.isValid() ) { // Los datos son validos this.person.calculateBodyMassIndex(); this.person.calculateNutritionalState(); // Informar la masa, la altura en centrimetros, y el bmi System.out.printf("%5.2f %s%n", this.person.getBodyMassIndex(), this.person.getNutritionalState() ); } else { // Informar datos invalidos System.out.println("invalid data"); } } // Close the standard input input.close(); } /** * Read data from standard input and create a Person * * @return true if a Person was read from standard input, false if there are no * more persons in standard input */ public boolean readPerson() { if ( this.input.hasNextDouble() ) { // Obtener la masa en kilogramos double mass = input.nextDouble(); // Obtener la altura en centimetros double heightCm = input.nextDouble(); // Toma el plano/clase Persona y crea un objeto/instancia this.person = new Person(mass, heightCm); // Done return true; } else { // No more data to create a person in standard input return false; } } } ]]>
0.0 && height > 0.0 && height <= 300.0; } /** * Updates the body mass index data member for this person */ public void calculateBodyMassIndex() { // Convertir la altura a metros double heightMeters = this.height / 100.0; // Calcular el indice de masa corporal (bmi) bodyMassIndex = this.mass / (heightMeters * heightMeters); } /** * Updates the nutritional state data member for this person */ public void calculateNutritionalState() { // Actualizar el estado nutricional de acuerdo a los rangos de la OMC if ( bodyMassIndex < 18.5 ) { // Informar infrapeso this.nutritionalState = "underweight"; } if ( bodyMassIndex >= 18.5 && bodyMassIndex < 25.0 ) { // Informar normal this.nutritionalState = "normal"; } if ( bodyMassIndex >= 25.0 && bodyMassIndex < 30.0 ) { // Informar sobrepeso this.nutritionalState = "overweight"; } if ( bodyMassIndex >= 30.0 ) { // Informar obesidad this.nutritionalState = "obese"; } } } ]]>
Diseño de la solución:
Estructura del proyecto, sus carpetas y archivos:
Las clases deben estar en control de versiones en la carpeta src/
de su proyecto. Se presentan a continuación la clase controladora y la clase modelo.
0 ) { // Read a triangle from arguments and run in batch, that is, // do not ask user to type the arguments in standard input this.runInBatch(args); } else { // Read triangles from standard input this.runInteractively(); } } /** * Run interactively, that is, reads triangles from standard * input until the EOF is reached */ public void runInteractively() { // Create object to read data from standard input input = new Scanner(System.in); // Echoes the standard input while ( readTriangle() ) { this.triangle.print(); } // Close the standard input input.close(); } /** * Creates a Triangle object and read it from standard input * @return true if the Triangle was read, false otherwise */ public boolean readTriangle() { // True if a triangle was read, false otherwise boolean wasRead = false; // We assume if there is a real, there are also three edges if ( input.hasNextDouble() ) { // Create the triangle object and read its edges this.triangle = new Triangle(); wasRead = this.triangle.read(input); } else { // There is not more edges in standard input, return false wasRead = false; } return wasRead; } /** * Runs the program in batch mode, that is, read a triangle * from command line arguments instead of standard input * * @param args The command line arguments */ public void runInBatch(String args[]) { // Analyze the given arguments ArgumentAnalyzer argumentAnalyzer = new ArgumentAnalyzer(); argumentAnalyzer.analyze(args); // If help was asked, just print it and exit if ( argumentAnalyzer.wasHelpAsked() ) { this.printHelp(); } else { // Otherwise, if a valid triangle was given if ( argumentAnalyzer.hasThreeEdges() ) { // Create a triangle with the three edges double edge1 = argumentAnalyzer.getEdge1(); double edge2 = argumentAnalyzer.getEdge2(); double edge3 = argumentAnalyzer.getEdge3(); this.triangle = new Triangle( edge1, edge2, edge3 ); // Print the triangle properties this.triangle.print(); } else { // Otherwise. Print an error message System.err.println("Error: insufficient arguments"); } // If there was other error, report it if ( argumentAnalyzer.getErrorMessage().length() > 0 ) { System.err.print( argumentAnalyzer.getErrorMessage() ); } } } /** * Print usage of this program in standard output */ public void printHelp() { System.out.println("TriangleInequality v1.1 [2017-Oct-02] Jeisson Hidalgo-Cespedes"); System.out.println("Usage: java TriangleInequality [a b c]"); System.out.println(); System.out.println("Arguments:"); System.out.println(" a b c Edges of the triangle"); System.out.println(); System.out.println("Si no arguments are provided, program will run in interactive mode"); System.out.println("reading triangles from standard input until EOF is provided."); } } ]]>
= 3; } /** * Get a copy of the first triangle edge found * @return Length of first edge */ public double getEdge1() { return this.edge1; } /** * Get a copy of the second triangle edge found * @return Length of second edge */ public double getEdge2() { return this.edge2; } /** * Get a copy of the third triangle edge found * @return Length of third edge */ public double getEdge3() { return this.edge3; } /** * Get a reference to the collected error messages found * while the analysis process is done * * @return All error messages concatenated, or empty if no errors * were collected */ public String getErrorMessage() { return this.errorMessage; } /** * Start the command line analysis process * @param arguments The arguments received by main() function */ public void analyze(String arguments[]) { // Traverse all command line arguments for ( int index = 0; index < arguments.length; ++index ) { // If help was asked if ( arguments[index].equals("--help") || arguments[index].equals("-help") ) { this.helpAsked = true; } else if ( analyzeEdge( arguments[index] ) ) { // Do nothing, the method analyzeEdge updated what is required } else { // The argument is unknown, report it later this.errorMessage += "Error: invalid argument: " + arguments[index] + "\n"; } } } /** * Checks if the given argument text is a triangle's edge value * If so, the value will be stored in the next free edge attribute * * @param argument The text of the argument to be analyzed * @return true If the argument is an edge, false otherwise */ private boolean analyzeEdge(String argument) { try { // Try to convert the string to double double edge = Double.parseDouble(argument); // If reached this line, the string has a valid double value ++this.edgeCount; // Store the double value as the following edge's length switch ( this.edgeCount ) { case 1: this.edge1 = edge; break; case 2: this.edge2 = edge; break; case 3: this.edge3 = edge; break; default: // We ignore more edges, only first three are parsed System.err.println("Warning: ignoring argument " + argument); } return true; } catch ( NumberFormatException exception ) { // If entered here, the text is not a valid real value, report it return false; } } } ]]>
0.0 && this.edge2 > 0.0 && this.edge3 > 0.0 ) { valid = true; } return valid; */ // The following expression is equivalent to the previous code // But it is not debugger-friendly return this.edge1 > 0.0 && this.edge2 > 0.0 && this.edge3 > 0.0; } /** * Indicates if this triangle is actually a triangle if it fulfills the * triangle inequality principle, that is, each edge is less than the * sum the other edges. * * @return true if this triangle fulfills the triangle inequality principle, * false otherwise. */ public boolean isTriangle() { // We assume the triangle does not fulfill the principle boolean valid = false; // If any edge is less than the sum of the others if ( this.edge1 < this.edge2 + this.edge3 ) { if ( this.edge1 > Math.abs(this.edge2 - this.edge3) ) { // The triangle fulfills the inequality principle valid = true; } } return valid; } /** * Prints the perimeter of this triangle, for example: * P=15 */ public void printPerimeter() { System.out.printf("P=%s", format(this.calculatePerimeter()) ); } /** * Calculates the perimeter of this triangle. The perimeter is the * sum of the three edges of the triangle. * * @return The perimeter of this triangle as a real value */ public double calculatePerimeter() { return this.edge1 + this.edge2 + this.edge3; } /** * Calculates and prints the area of this triangle. For example: * A=14.28 */ public void printArea() { System.out.printf("A=%s", format(this.calculateArea()) ); } /** * Calculates the area of this triangle using its edges through the * Heron's formula * * @return The area of the triangle as a real value */ public double calculateArea() { // The Heron's formula uses the semiperimeter `s` of the triangle double semiperimeter = this.calculateSemiperimeter(); // Area is calculated as: // A = \sqrt{s(s-a)(s-b)(s-c)} // where `s` is semiperimeter and `a, b, c` are the triangle's edges double subradical = semiperimeter * (semiperimeter - this.edge1) * (semiperimeter - this.edge2) * (semiperimeter - this.edge3); return Math.sqrt(subradical); } /** * Calculates the semiperimeter of this triangle. The semiperimeter * is half of perimeter * * @return The semiperimeter of this triangle as a real value */ public double calculateSemiperimeter() { return this.calculatePerimeter() / 2.0; } /** * Prints the classification of this triangle according to its edges * @see getCategoryByEdge() */ public void printCategoryByEdge() { System.out.print( this.getCategoryByEdge() ); } /** * Returns a String indicating the classification of this triangle according * to its edges. The returned text is in Spanish. Possible values are: * "equilatero", "isosceles", or "escaleno". */ public String getCategoryByEdge() { String category = ""; // Compare the lengths of the sides if ( this.edge1 == this.edge2 && this.edge2 == this.edge3 ) { // All edges are equal, we have an equilateral triangle category = "equilatero"; } else if ( this.edge1 == this.edge2 || this.edge1 == this.edge3 || this.edge2 == this.edge3 ) { // Only two edges are equal, we have an isosceles triangle category = "isosceles"; } else { // Otherwise, we assume a scalene triangle category = "escaleno"; } return category; } /** * Prints the classification of this triangle according to its angles * @see getCategoryByAngle() */ public void printCategoryByAngle() { System.out.print( this.getCategoryByAngle() ); } /** * Returns a String indicating the classification of this triangle according * to its angles. The returned text is in Spanish. Possible values are: * "obtusangulo", "rectangulo", or "acutangulo". */ public String getCategoryByAngle() { // We need to find the hypotenuse and the two cathetus MutableDouble hypotenuse = new MutableDouble(0.0); MutableDouble cathetus1 = new MutableDouble(0.0); MutableDouble cathetus2 = new MutableDouble(0.0); // Find the hypotenuse and the two cathetus objects // This method will modify the objects referred by parameter findHypotenuseAndCathetuses(hypotenuse, cathetus1, cathetus2); // Text indicating the classification of this triangle according to angles String category = ""; // We use the Pythagorean theorem to check the type of triangle // We square each edge for convenience double squaredHypotenuse = hypotenuse.getValue() * hypotenuse.getValue(); double squaredCathetus1 = cathetus1.getValue() * cathetus1.getValue(); double squaredCathetus2 = cathetus2.getValue() * cathetus2.getValue(); // We compare the squares of the hypotenuse and sum of squared cathetus if ( squaredHypotenuse == squaredCathetus1 + squaredCathetus2 ) { // Edges fulfill the Pythagorean theorem, it is a rectangled triangle category = "rectangulo"; } else if ( squaredHypotenuse > squaredCathetus1 + squaredCathetus2 ) { // Hypotenuse area is larger than cathetus area, is an obtuse triangle category = "obtusangulo"; } else { // Otherwise, we assume it is an acute triangle category = "acutangulo"; } return category; } /** * Finds the largest edge of the triangle (hypotenuse) and the two smaller edges * and set the given objects to these results. * * @param hypotenuse This object will be modified to have the hypotenuse's length * @param cathetus1 This object will be modified to have a cathetus's length * @param cathetus2 This object will be modified to have a cathetus's length */ public void findHypotenuseAndCathetuses(MutableDouble hypotenuse, MutableDouble cathetus1, MutableDouble cathetus2) { // Test each edge against the remaining two looking for the largest if ( this.edge1 > this.edge2 && this.edge1 > this.edge3 ) { // The edge1 is larger than edge2 and edge3, it is the hypotenuse hypotenuse.setValue(this.edge1); cathetus1.setValue(this.edge2); cathetus2.setValue(this.edge3); } else if ( this.edge2 > this.edge1 && this.edge2 > this.edge3 ) { // The edge2 is larger than edge1 and edge3, it is the hypotenuse hypotenuse.setValue(this.edge2); cathetus1.setValue(this.edge1); cathetus2.setValue(this.edge3); } else { // The edge3 must be larger than edge1 and edge2, it is the hypotenuse hypotenuse.setValue(this.edge3); cathetus1.setValue(this.edge1); cathetus2.setValue(this.edge2); } } } ]]>
Solution.java
. Obtener código fuente.Persona
. Obtener código fuente.Estudiante
. Obtener código fuente.Funcionario
. Obtener código fuente.Profesor
. Obtener código fuente.Administrativo
. Obtener código fuente.Una clase arreglo dinámico puede crecer. En Java la clase de biblioteca ArrayList realiza esta funcionalidad.
En el siguiente ejemplo, la clase controladora Solution
usa el arreglo dinámico para calcular la mediana sin saber la cantidad de datos que vienen en la entrada estándar.
Solution
. Obtener código fuente.index; --current ) { this.elements[current] = this.elements[current - 1]; } this.elements[index] = element; ++this.count; } public int getCount() { return this.count; } public int getCapacity() { return this.elements.length; } public double getAt(int index) { return this.elements[index]; } private void increaseCapacity() { double[] newElements = new double[ INCREASE_FACTOR * this.getCapacity() ]; for ( int index = 0; index < this.count; ++index ) { newElements[index] = this.elements[index]; } this.elements = newElements; } public void sort() { Arrays.sort( this.elements, 0, this.getCount() ); } public void bubbleSort() { int changes = -1; int pass = 0; //for ( int pass = 0; pass < this.getCount(); ++pass ) while ( changes != 0 ) { changes = 0; for ( int index = 1; index < this.getCount() - pass; ++index ) { if ( this.elements[index - 1] > this.elements[index] ) { this.swap(index - 1, index); ++changes; } } ++pass; } } private void swap(int index1, int index2) { double copy1 = this.elements[index1]; this.elements[index1] = this.elements[index2]; this.elements[index2] = copy1; } /** * Sequential search in O(n) * @param element * @return */ public int searchFirst(double element) { int position = -1; for ( int index = 0; index < this.getCount() && position == -1; ++index ) { if ( this.elements[index] == element ) { position = index; } } return position; } public int binarySearch(double element) { int low = 0; int high = this.getCount(); while ( low < high ) { int middle = (low + high) / 2; if ( element == this.elements[middle] ) return middle; else if ( element < this.elements[middle] ) high = middle; else low = middle + 1; } return -1; } } ]]>
Una clase que administra una matriz, de dimensiones arbitrarias, y realiza operaciones matemáticas comunes de las matrices.
0 && columns > 0 ) { // Dimensions are valid, create the actual matrix this.matrix = new double[rows][columns]; } } /** * Read the dimensions and values from the given input * @param matrix */ public void read(Scanner input) { // Read the dimensions of the matrix int rows = input.nextInt(); int cols = input.nextInt(); // Create the matrix in heap, and keep a reference this.matrix = new double[rows][cols]; // Read all values for the matrix for ( int row = 0; row < this.matrix.length; ++row ) { // Read all values for current row for ( int col = 0; col < this.matrix[row].length; ++col ) { this.matrix[row][col] = input.nextDouble(); } } } /** * Print this matrix in the given output * @param output The file where print this matrix */ public void print(PrintStream output) { // Print each row for ( int row = 0; row < matrix.length; ++row ) { // Print each column in the current row for ( int col = 0; col < matrix[row].length; ++col ) { // Print the cell value output.printf("%.2f ", matrix[row][col]); } // Separate this row from next by a new line character output.println(); } } /** * Adds this matrix with another * * @param other Other matrix to be added with this * @return A reference to the resulting matrix object containing * the sum of this and the other matrix. If matrixes have different * dimensions, a null reference will be retorned */ public Matrix add(Matrix other) { // The resulting matrix of adding this one with other Matrix result = null; // Only matrixes of same size can be added if ( this.matchesSize(other) ) { // Create the matrix object to store the resulting sum result = new Matrix( this.getRowCount(), this.getColumnCount() ); // Add the rows of both matrixes. Because the three matrixes // (this, other, and result) have the same dimensions, we can use // the dimensions of anyone to control the loops for ( int row = 0; row < this.matrix.length; ++row ) { // Add all columns in this row for ( int col = 0; col < this.matrix[row].length; ++col ) { // The result cell is the sum of respectives cells in // this and other matrixes result.matrix[row][col] = this.matrix[row][col] + other.matrix[row][col]; } } } // Notice that we return null if matrixes do not match their size return result; } /** * Returns true if this matrix and other have the same amount of * rows and columns * * @param other Other matrix to be checked against this for size * @return true if this matrix and other have the same dimensions */ public boolean matchesSize(Matrix other) { return this.getRowCount() == other.getRowCount() && this.getColumnCount() == other.getColumnCount(); } /** * Return the number of rows that this matrix has * @return The number of rows, 0 if this is an invalid matrix */ public int getRowCount() { return this.matrix != null ? this.matrix.length : 0; } /** * Return the number of columns that this matrix has * @return The number of rows, 0 if this is an invalid matrix */ public int getColumnCount() { // Avoid to check lengths for null matrix references // We assume all rows have the same amount of columns, // therefore, we use the first row length return this.matrix != null && this.matrix.length > 0 ? this.matrix[0].length : 0; } } ]]>
0 ) { students.append( name ); } } students.print( System.out ); // Close the standard input this.input.close(); } } ]]>
0 ) { // The key to be inserted must go in the right subtree // Check if we alread have a right subtree if ( this.right == null ) { // We do not have a right subtree, create the node there this.right = new Node(key, value); } else { // We already have a right subtree, insert the node there this.right.insert(key, value); } } // else: notice we insert repeated keys in the tree, so it can // have multiple values for a same key. If we forbid this // behavior, we will have a set (in mathematical sense). } /** * Print this tree in in-order, which gives alphabetical order * @param out */ public void print(PrintStream out) { // First, print the entire left subtree recursively // because all its keys are less than mine if ( this.left != null ) { this.left.print(out); } // Second, print myself because I am the next out.printf("%s\t%s%n", this.key, this.value); // Third, print the entire right subtree recursively // because all its keys are greater than mine if ( this.right != null ) { this.right.print(out); } } /** * Finds the value for the given key. This method * will do log_2(n) comparisons if the tree is balanced * * @param key The key to be searched * @return The corresponding value for the key, null if * the key is not found in the tree */ public String findValue(String key) { // Compare the searched key with my key. E.g: if searching // for "board" and I have "body", it will produce: // "board".compareTo("body") == -3 int comparison = key.compareTo(this.key); // If both keys are identical if ( comparison == 0 ) { // I have the value for that key, return it return this.value; } else if ( comparison < 0 ) { // The searched key must be in the left subtree if ( this.left == null ) { // But I do not have a left subtree, stop here return null; } else { // I have a left subtree, search there return this.left.findValue(key); } } else { // The searched key must be in the right subtree if ( this.right == null ) { // But I do not have a right subtree, stop here return null; } else { // I have a right subtree, search there return this.right.findValue(key); } } } // findValue() } // class Node /** * A tree simply has a reference to the root node. * If this reference is null, the tree is empty */ private Node root = null; /** * The number of elements stored in the tree */ private long count = 0; /** * Return true if this tree is empty * @return true if the tree is empty, false otherwise */ public boolean isEmpty() { return root == null; } /** * Return the count of elements currently stored in the tree * @return The count of elements */ public long getCount() { return this.count; } /** * Insert the given pair (key,value) in the tree * @param key The key to be stored * @param value The value to be stored */ public void insert(String key, String value) { // The insertion depends on if the tree is empty if ( this.isEmpty() ) { // The tree is empty, make the new pair the root this.root = new Node(key, value); } else { // The tree has elements, ask the root to insert // the pair (key,value) in its place this.root.insert(key, value); } // We have one more element stored in the tree ++this.count; } /** * Prints this tree to the given output in alphabetical order * @param out The file were the tree will be printed */ public void print(PrintStream out) { // We can only print a tree if it has values if ( ! this.isEmpty() ) { // Print the nodes recursively this.root.print(out); } } /** * Finds the value for the given key. This method * will do log_2(n) comparisons if the tree is balanced * * @param key The key to be searched * @return The corresponding value for the key, null if * the key is not found in the tree */ public String findValue(String key) { // The search depends on if the tree is empty if ( this.isEmpty() ) { // The tree is empty, we do not have a value for the key return null; } else { // We have elements in the tree, search for the value // recursively return this.root.findValue(key); } } } ]]>
El archivo TrainLaneGame.zip contiene el proyecto completo, que incluye el código fuente, imágenes, archivos de configuración de Eclipse.
cellWidth ) { this.timerCarAnimation.stop(); this.movingCarX = 0; this.movingCarRow = this.movingCarColumn = -1; } } else { g.drawImage(this.obstacle , x + paddingHorizontal, y + paddingVertical , cellWidth - 2 * paddingHorizontal, cellHeight - 2 * paddingVertical, null); } } } } } /** * Invoked when an action occurs. */ @Override public void actionPerformed(ActionEvent event) { if ( event.getSource() == this.timerCarAnimation ) { this.repaint(); } } /** * Invoked when the mouse button has been clicked (pressed * and released) on a component. */ @Override public void mouseClicked(MouseEvent event) { int cellWidth = this.getWidth() / obstacleMatrix.getColumnCount(); int cellHeight = this.getHeight() / obstacleMatrix.getRowCount(); int row = event.getY() / cellHeight; int column = event.getX() / cellWidth; System.out.printf("mouseClicked(%d,%d)%n", event.getX(), event.getY()); System.out.printf("Obstacle(%d,%d)%n", row + 1, column + 1); this.movingCarRow = row; this.movingCarColumn = column; this.movingCarX = -5; this.timerCarAnimation.start(); } @Override public void mousePressed(MouseEvent event) { // TODO Auto-generated method stub // System.out.printf("mousePressed(%d,%d)%n", event.getX(), event.getY()); } @Override public void mouseReleased(MouseEvent event) { // TODO Auto-generated method stub // System.out.printf("mouseReleased(%d,%d)%n", event.getX(), event.getY()); } @Override public void mouseEntered(MouseEvent event) { // TODO Auto-generated method stub // System.out.printf("mouseEntered(%d,%d)%n", event.getX(), event.getY()); } @Override public void mouseExited(MouseEvent event) { // TODO Auto-generated method stub // System.out.printf("mouseExited(%d,%d)%n", event.getX(), event.getY()); } } ]]>