Patrones de Programación

Al escribir un programa no se parte siempre de cero. Muchas veces es posible reutilizar y combinar elementos de programas ya conocidos. Al estudiar diversos programas es posible identificar patrones de instrucciones que se repiten.

El concocer diversos patrones nos ayuda a resolver nuevos problemas, pues no tenemos que reinventar soluciones para problemas similares una y otra vez.

Patrón de acumulación

Un ejemplo de estos patrones de programación es la acumulación. Este patrón se usa para realizar cálculos como la suma de varios valores calculados en las iteraciones de un ciclo:

suma= val1 + val2 + val3 + ... + valn

producto= fac1 * fac2 * fac3 * ... * facn

La forma general de este patrón es:

La siguiente pantalla muestra un programa que cuenta cuántos números ingresa el usuario, hasta llegar al número cero:

El programa, en el que aparece claramente el patrón de acumulación es:

  1. int cont= 0;

  2. float nota;

  3. printf("? ");

  4. scanf (“%f”,&nota);

  5. while (nota!=0.0) { /* OJO CON LOS PROBLEMAS DE REPRESENTACIÓN INTERNA */

  6. cont= cont+1;

  7. printF("? ");

  8. scanf (“%f”,&nota);

  9. }

  10. printf("Contador= ");

  11. printf(“%d\n”,cont);

    En un programa que calcula el promedio de notas se ve también un patrón de acumulación, cuya diferencia con el anterior es que tiene dos variables que se van acumulando en vez de una sola:

    ? 4.0

    ? 5.0

    ? 6.0

    ? 0.0

    Promedio= 5.0

  12. float suma= 0, nota;

  13. int cont= 0;

  14. printf("? ");

  15. scanf (“%f”,&nota);

  16. while (nota!=0.0) {

  17. suma= suma+nota;

  18. cont= cont+1;

  19. printf("? ");

  20. scanf (“%f”,&nota);

  21. }

  22. printf("Promedio= %1.1f\n", suma/cont);

    Patrón de lectura de datos

    En el último programa se presenta también el patrón de lectura de datos. Su forma general es:

    tipo variable;

    ...

    leer(variable);

    while (...) {

    ....

    leer(variable);

    }

    Típicamente se marca el fin de los datos con un cero o -1 (o un número que no pertenezca al universo de datos)

    Patrón de Recorrido de Intervalo de Enteros

    Si consideramos un programa que despliegue los números enteros de 1 a n, como se ve en la pantalla siguiente, podemos usar el patrón de acumulación:

    ? 4

    1

    2

    3

    4

    El programa termina cuando la variable i excede en valor a n

  23. int n,i;

  24. printf("? ");

  25. scanf(“%d”,&n);

  26. i= 1;

  27. while (i<=n) {

  28. printf(“%d”,i);

  29. i= i+1;

  30. }

    En realidad estamos en presencia de otro patrón muy utilizado: recorrido de un intervalo de enteros. Su forma general es:

    int i= valorInicial;

    while ( i <= ValorFinal ) {

    ...

    i= i + 1;

    }

    La variable i toma valores entre [valorInicial, valorFinal], incrementándose en 1 en cada iteración.

    Ejemplos

    Factorial de un número

    Para calcular el factorial de un número se agrega el producto de los valores sucesivos que toma la variable i en cada iteración. Usaremos el patrón de acumulación con el operador *.

  31. int fact, n, i;

  32. printf("? ");

  33. scanf(“%d”,&n);

  34. fact= 1;

  35. i= 1;

  36. while (i<=n) {

  37. fact= fact*i;

  38. i= i+1;

  39. }

  40. printf("El factorial es %d\n", fact);

    Exponencial de un número usando una aproximación:

    Como se sabe de cálculo, exp(x) se puede calcular mediante la siguiente aproximación:

    exp(x)= 1 + x + x^2/2! + x^3/3! + ... + x^i/i! + ... + x^n/n!

    El siguiente programa calcula i! al mismo tiempo que calcula x^i.

  41. float xi= 1.0, facti= 1.0;

  42. int i= 1;

  43. while (i<=n) {

  44. xi= xi*x;

  45. facti= facti*i;

  46. i= i+1;

  47. }

    Observa que en la i-ésima iteración, la variable xi es x^i y facti es i!

    A este programa podemos agregarle una acumulación de xi/facti:

  48. float x= ...; /* Obtener x y n */

  49. int n= ...;

  50. float xi= 1.0;

  51. float facti= 1.0;

  52. float expx= 1.0;

  53. int i= 1;

  54. while (i<=n) {

  55. xi= xi*x;

  56. facti= facti*i;

  57. expx= expx + xi/facti;

  58. i= i+1;

  59. }

  60. printf(“%f\n”,expx);

    La instrucción de la línea 60 simplemente despliega el resultado final

    Pon tus conocimientos a prueba

    Escrbe un programa que lea números hasta que el usuario ingrese un cero y diga cuántos números son pares y cuántos son impares, como se ve en la pantalla sigueinte:

    ?1

    ?2

    ?5

    ?2

    ?4

    ?6

    ?9

    ?14

    ?12

    ?8

    Hay 7 pares y 3 impares

    Calculo del máximo de un conjunto de datos

    Considera un programa que usando el patrón de lectura de datos lea un conjunto de números positivos y escriba el mayor de todos ellos al final:

    ?1

    ?4

    ?2

    ?1

    ?0

    El máximo es: 4

    Usando algo parecido al patrón de acumulación, obtenemos

  61. int num;

  62. int maximo;

  63. printf("? ");

  64. scanf(“%d”,&num);

  65. maximo= num;

  66. while (num!=0) {

  67. if (num>maximo)

  68. maximo= num;

  69. printf("? ");

  70. scanf(“%d”,&num);

  71. }

  72. printf("El máximo es %d\n", maximo);

    A primera vista puede parecer que este código no usa el patrón de acumulación, pero si te fijas bien, las líneas 67 y 68 equivalen a

    maximo=max(maximo, num);

    que es similar a

    variable = variable operador expresión;

    que era parte del patrón de acumulación.

    El hipopótamo en el zoológico de El Cairo

    Hay un viejo chiste que dice que para buscar un hipopótamo en Africa, el algoritmo que diseña un programador inexperto es el siguiente:

    pararse en Ciudad Del Cabo

    repetir

    recorrer hacia el oeste hasta llegar al oceano pacífico

    si se encuentra un hipopótamo, parar

    avanzar 1 kilómetro al norte

    recorrer hacia el este hasta llegar al oceano atlántico

    si se encuentra un hipopótamo, parar

    avanzar 1 kilómetro al norte

    El problema de este algoritmo, es que si no hay ningún hipopótamo el buscador se cae al mediterráneo (JA). El programador experto hace una pequeña modificación al código anterior, al agregar la siguiente instrucción al inicio del programa:

    poner un hipopótamo en el zoológico de El Cairo

    La "moraleja" de este chiste es que siempre hay que tener especial cuidado con las condiciones de borde en las iteraciones. Por ejemplo, el programa que encuentra el mínimo de un conjunto de datos, puede escribirse de la siguiente forma:

  73. int num;

  74. int minimo=MAXINT;

  75. printf("? ");

  76. scanf(“%d”,&num);

  77. while (num!=0) {

  78. if (num<minimo)

  79. minimo= num;

  80. printf("? ");

  81. scanf(“%d”,&num);

  82. }

  83. printf("El mínimo es %d\n",minimo);

    La constante MAXINT sería mayor número entero que C puede representar (en realidad hay que hacer un juego con la representación de los datos para lograrlo). Al asignarselo a minimo, uno asegura que la primera vez que se ejecute la línea 78 la condición del if será verdadera y por lo tanto num se guardará en minimo. Es decir, nos aseguramos que el primer número que leemos sea considerado como mínimo, al menos temporalmente.

    Pon tus conocimientos a prueba

    Escribe un programa que lea números desde el teclado e indique el rango de los números (el fin de datos es el 0)

    ?1

    ?2

    ?5

    ?2

    ?4

    ?0

    El rango es [1,5]

    De ahora en adelante y hasta el final del curso, iremos introduciendo distintos patrones de programación. Es importante tener presente qué hace cada patrón y cómo integrarlo a un nuevo programa. Es un excelente ejercicio buscar patrones ya conocidos en tus programas, y mejor aún, encontrar patrones nuevos.