Ejercicios resueltos laboratorio 6 - Algoritmos condicionales múltiples

Asignatura: Fundamentos de Informática
Especialidad: Electrónica - UPV/EHU
Curso académico: 2013-2014
Profesor: Ismael Etxeberria Agiriano

Resolución 06-001-1

La resolución más directa es ir probando cada uno de los valores posibles uno a uno discriminando cada vez un día de la semana.

El diagrama de flujo sería:

La codificación correspondiente a la variante 1 podría ser:


/* 06-001-1.c (versión laboratorio)
 * Leer un número del 0 al 6 y escribir el nombre del día de la semana
 * correspondiente, "lunes", "martes", ..., "domingo".
 *
 * Si el número leído no está en el intervalo previsto escribirá "error". 
 *
 * Variante 1. Utilizando if-else.
 */
#include <stdio.h>
#include <stdlib.h>

int main (void)
{
  int diaSem;

  printf ("Introduce el número del día de la semana: ");
  scanf ("%d", &diaSem);

  if      (diaSem == 0) printf ("lunes\n");
  else if (diaSem == 1) printf ("martes\n");
  else if (diaSem == 2) printf ("miércoles\n");
  else if (diaSem == 3) printf ("jueves\n");
  else if (diaSem == 4) printf ("viernes\n");
  else if (diaSem == 5) printf ("sábado\n");
  else if (diaSem == 6) printf ("domingo\n");
  else                  printf ("error\n");

  system ("pause");
  return 0;
}

Resolución 06-001-2

Una variante de la resolución anterior consiste en utilizar una estructura switch.

Se observa que la diferencia principal es que sólo hay una condición, que es el valor de la variable diaSem. Si ejecutamos el programa paso a paso con el depurador veremos que nos posicionamos sobre la instrucción switch y en el paso siguiente vamos directamente al caso en cuestión, mientras en la variante anterior vamos evaluando una a una las condiciones hasta dar con la adecuada.

Este diagrama de flujo no es fácil de dibujar y no facilita la comprensión por lo que no se recomienda su utilización en este curso.

Se ilustra en este ejemplo para describir el funcionamiento.

El diagrama de flujo sería:

La codificación correspondiente a la variante 2 podría ser:


/* 06-001-2.c (versión laboratorio)
 * Leer un número del 0 al 6 y escribir el nombre del día de la semana
 * correspondiente, "lunes", "martes", ..., "domingo".
 *
 * Si el número leído no está en el intervalo previsto escribirá "error". 
 *
 * Variante 2. Utilizando switch.
 */
#include <stdio.h>
#include <stdlib.h>

int main (void)
{
  int diaSem;

  printf ("Introduce el número del día de la semana: ");
  scanf ("%d", &diaSem);

  switch (diaSem) {
    case 0:  printf ("lunes\n");     break;
    case 1:  printf ("martes\n");    break;
    case 2:  printf ("miércoles\n"); break;
    case 3:  printf ("jueves\n");    break;
    case 4:  printf ("viernes\n");   break;
    case 5:  printf ("sábado\n");    break;
    case 6:  printf ("domingo\n");   break;
    default: printf ("error\n");     break;
  }

  system ("pause");
  return 0;
}

Resolución 06-002-1 - Variante 1

Sean los tres números n1, n2 y n3, un posible algoritmo consiste en determinar si n1 es el mayor, comparándolo con n2 y n3. En caso afirmativo, escribimos que n1 es el mayor y comparamos los dos que quedan, n2 y n3. En caso negativo sólo los dos restantes n2 y n3 pueden ser el mayor y así sucesivamente.

El diagrama de flujo aclara esta multiplicación de casos:

El siguiente diagrama de flujo simplificado muestra los bloques de la primera condicional

La codificación correspondiente a la variante 1 podría ser:


/* 06-002-1.c (versión laboratorio)
 * Leer tres números enteros y decir cuál es el mayor, el mediano y el menor
 *
 * Variante 1. Escribiendo resultados sobre la marcha.
 */
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  int n1, n2, n3;

  printf ("Introduce tres números: ");
  scanf ("%d%d%d", &n1, &n2, &n3);

  if (n1 >= n2 && n1 >= n3) {
    printf ("Mayor: %d\n", n1);
    if (n2 >= n3)
      printf ("Mediano: %d\nMenor: %d\n", n2, n3);
    else
      printf ("Mediano: %d\nMenor: %d\n", n3, n2);
  }
  else {
    if (n2 >= n3) {
      printf ("Mayor: %d\n", n2);
      if (n1 >= n3)
        printf ("Mediano: %d\nMenor: %d\n", n1, n3);
      else
        printf ("Mediano: %d\nMenor: %d\n", n3, n1);
    }
    else {
      printf ("Mayor: %d\n", n3);
      if (n1 >= n2)
        printf ("Mediano: %d\nMenor: %d\n", n1, n2);
      else
        printf ("Mediano: %d\nMenor: %d\n", n2, n1);
    }
  }

  system ("pause");
  return 0;
}

Resolución 06-002-2 - Variante 2

Una variante de la solución propuesta consiste en calcular primero cuáles son el mayor, el mediano y el menor y finalmente sólo escribirlos una vez. Para ello necesitaremos tres variables suplementarias, ma, me y mi.

Se observará que disminuye el número de instrucciones de escritura, de nueve a una. En la misma medida se introducen nueve asignaciones.

Esta variante responde más a la estructura típica:

  1. Leer los datos de entrada
  2. Calcular los resultados
  3. Escribir los resultados

La codificación correspondiente a la variante 2 podría ser:


/* 06-002-2.c (versión laboratorio)
 * Leer tres números enteros y decir cuál es el mayor, el mediano y el menor
 *
 * Variante 2.  Utilizando variables suplementarias ma, me y mi, asignándoles
 * los valores sobre la marcha.
 */
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  int n1, n2, n3;
  int ma, me, mi;

  printf ("Introduce tres números: ");
  scanf ("%d%d%d", &n1, &n2, &n3);

  if (n1 >= n2 && n1 >= n3) {
    ma = n1;
    if (n2 >= n3) { me = n2; mi = n3; }
    else          { me = n3; mi = n2; }
  }
  else {
    if (n2 >= n3) {
      ma = n2;
      if (n1 >= n3) { me = n1; mi = n3; }
      else          { me = n3; mi = n1; }
    }
    else {
      ma = n3;
      if (n1 >= n2) { me = n1; mi = n2; }
      else          { me = n2; mi = n1; }
    }
  }

  printf ("Mayor: %d\nMediano: %d\nMenor: %d\n", ma, me, mi);

  system ("pause");
  return 0;
}

Resolución 06-002-3 - Variante 3

Podemos optar por determinar cada uno de los seis casos y luego asignar los valores correspondientes.

Se observará en el diagrama de flujo que hay menos mezcla de colores, por lo que la complejidad es menor.

La codificación correspondiente a la variante 3 podría ser:


/* 06-002-3.c (versión laboratorio)
 * Leer tres números enteros y decir cuál es el mayor, el mediano y el menor
 *
 * Variante 3. Utilizando variables suplementarias ma, me y mi, asignándoles
 * los valores según el caso.
 */
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  int n1, n2, n3;
  int ma, me, mi;

  printf ("Introduce tres números: ");
  scanf ("%d%d%d", &n1, &n2, &n3);

  if (n1 >= n2 && n1 >= n3)
    if (n2 >= n3) { ma = n1; me = n2; mi = n3; }
    else          { ma = n1; me = n3; mi = n2; }
  else
    if (n2 >= n3)
      if (n1 >= n3) { ma = n2; me = n1; mi = n3; }
      else          { ma = n2; me = n3; mi = n1; }
    else
      if (n1 >= n2) { ma = n3; me = n1; mi = n2; }
      else          { ma = n3; me = n2; mi = n1; }

  printf ("Mayor: %d\nMediano: %d\nMenor: %d\n", ma, me, mi);

  system ("pause");
  return 0;
}

Resolución 06-002-4 - Variante 4

Esta nueva variante propuesta contempla la utilización del operador condicional c?e1:e2.

Partiendo de la variante 3 es relativamente sencillo entender esta solución. La complejidad algoritmica es muy reducida pero se aumenta la complejidad de las expresiones condicionales.

Así, se calcula el valor del mayor (ma), mediano (m3) y menor (mi), cada una de golpe y teniendo en cuenta información de comparaciones previas.

Veamos cómo se calculan, recordando que el operador c?e1:e2 evalúa la condición c y si es cierta toda la expresión tomará el valor de la evaluación de e1 y si no, la de e2.

Veamos mediante una representación de diagramas de flujo la expresión para calcular el número mediano me:

Es de remarcar que hemos utilizado paréntesis para clarificar cuáles son las subexpresiones condicionales, aunque en realidad no serían necesarias ya que se ejecutarían en el orden apropiado.

Se puede simplificar esta expresión agrupando los elementos que resultan que me es n1 y n2. No vamos a proporcionar el diagrama de flujo correspondiente pero el código proporcionado contempla este agrupamiento.

La codificación correspondiente a la variante 4 podría ser:


/* 06-002-4.c (versión laboratorio)
 * Leer tres números enteros y decir cuál es el mayor, el mediano y el menor
 *
 * Variante 4. Utilizando operador condicional c?e1:e2.
 */
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  int n1, n2, n3;
  int ma, me, mi;

  printf ("Introduce tres números: ");
  scanf ("%d%d%d", &n1, &n2, &n3);

  ma = (n1 >= n2 && n1 >= n3)? n1 : (n2 >= n3)? n2 : n3;
  mi = (n1 <= n2 && n1 <= n3)? n1 : (n2 <= n3)? n2 : n3;
  me = (n1 == n2 || n1 == n3 || ma > n1 && n1 > mi)? n1 :
       (n2 == n3 || ma > n2 && n2 > mi)?             n2 : n3;

  printf ("Mayor: %d\nMediano: %d\nMenor: %d\n", ma, me, mi);

  system ("pause");
  return 0;
}

En esta cuarta variante se ha visto algo muy típico en el lenguaje C: se puede simplificar mucho el número de instrucciones a base de utilizar expresiones complejas.

Lo que nos tenemos que preguntar siempre es: ¿Es el programa resultante más fácil de escribir? ¿Es más fácil de entender? ¿Es más fácil equivocarse? ¿Es más fácil de mantener por uno mismo y por otros?

Resolución 06-002-5 - Variante 5

Con esta última variante se pretende mostrar una nueva solución al problema, similar a la variante 06-002-3 pero con una estructura condicional más sencilla.

Comparando esta nueva solución con las anteriores veremos que es más simple, que utiliza un algoritmo más directo.

La codificación correspondiente a la variante 5 podría ser:


/* 06-002-5.c (versión laboratorio)
 * Leer tres números enteros y decir cuál es el mayor, el mediano y el menor
 *
 * Variante 5. Solución más sencilla.
 */
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  int n1, n2, n3;
  int ma, me, mi;

  printf ("Introduce tres números: ");
  scanf ("%d%d%d", &n1, &n2, &n3);

  if (n1 > n2)
    if (n1 > n3)
      if (n2 > n3) { ma = n1; me = n2; mi = n3; }
      else         { ma = n1; me = n3; mi = n2; }
    else           { ma = n3; me = n1; mi = n2; }
  else
    if (n2 > n3)
      if (n1 > n3) { ma = n2; me = n1; mi = n3; }
      else         { ma = n2; me = n3; mi = n1; }
    else           { ma = n3; me = n2; mi = n1; }

  printf ("Mayor: %d; Mediano: %d; Menor: %d\n", ma, me, mi);

  system ("pause");
  return 0;
}