27 de noviembre de 2017

Ejercicios selectos (matrices).

  1. Considere el Ejemplo 6.7. ¿Qué pasa si hay más inicializadores que elementos físicos? Pruebe dicha situación en los dos esquemas de inicialización planteados en el blog.
  2. Escriba un programa que pruebe la función suma del Ejemplo 6.8.
  3. Modifique la función leeMatriz del Ejemplo 6.7 para que almacene valores de tipo float en la matriz matriz. Una vez que haya probado su función, agréguela a la biblioteca de funciones del Ejemplo 6.8.
  4. Modifique la función imprimeMatriz del Ejemplo 6.7 para que imprima los valores de tipo float de la matriz matriz. Una vez que haya probado su función, agréguela a la biblioteca de funciones del Ejemplo 6.8.
  5. Escriba un programa que defina y pruebe una función con el siguiente prototipo: void resta(float a[ ][N], float b[ ][N], float c[ ][N], int m, int n). La función deberá calcular en la matriz c la resta de la matriz a menos la matriz b de manera análoga a como lo hace la función suma del Ejemplo 6.8.
  6. Agregue la función resta del ejercicio anterior, a la biblioteca de funciones del Ejemplo 6.8.
  7. Escriba un programa que defina y pruebe una función con el siguiente prototipo: void imprimeTranspuesta(float a[ ][N], int m, int n). La función deberá imprimir en la salida estándar la matriz transpuesta de a. La matriz transpuesta se genera convirtiendo los renglones en columnas y viceversa.
  8. Escriba un programa que defina y pruebe una función con el siguiente prototipo: void transpuesta(float a[ ][N], float aT[ ][N],int m, int n). La función deberá generar en la matriz aT la matriz transpuesta de a. La matriz transpuesta se genera convirtiendo los renglones en columnas y viceversa.
  9. Agregue la función transpuesta del ejercicio anterior a la biblioteca de funciones del Ejemplo 6.8.
  10. Escriba un programa que defina y pruebe una función con el siguiente prototipo: int esSimetrica(float a[ ][N], int n). La función deberá determinar si la matriz a es o no simétrica. Una matriz simétrica es aquella que es igual con su matriz transpuesta.
  11. Agregue la función esSimetrica del ejercicio anterior, a la biblioteca de funciones del Ejemplo 6.8.
  12. Escriba un programa que defina y pruebe una función con el siguiente prototipo: void producto(float a[ ][N], float b[ ][N], float c[ ][N], int m, int n, int l). La función debe calcular el producto de las matrices  a y b almacenando el resultado en c. Para poder realizar este ejercicio, investigue cómo se define y obtiene el producto de matrices.
  13. Agregue la función producto del ejercicio anterior a la biblioteca de funciones del Ejemplo 6.8.
  14. Escriba una función que determine la suma de los elementos de la diagonal principal de una matriz.
  15. Escriba una función que determine la suma de los elementos de la diagonal secundaria de una matriz.
  16. Un cuadrado mágico es una matriz de n x n donde n es impar, en donde se colocan números enteros en cada una de sus entradas y que además cumple con las siguientes características:
    • La suma de los números de cualquier línea (horizontal, vertical o diagonal) será siempre la misma. A esta suma se le denomina constante mágica.
    • Todos los números almacenados en un cuadrado mágico deben ser distintos.
    Con base en lo anterior, escriba una función con el siguiente prototipo:

    int cuadradoMagico(int c[ ][N], int n);

    Dado un cuadrado c de dimensiones lógicas n, la función determina si representa (regresa 1) o no (regresa 0) un cuadrado mágico. Ejemplo:

    4     9     2
    3     5     7
    8     1     6
    es un cuadrado mágico.
  17.  Haga un programa que implemente el juego del gato (tic tac toe). En este programa el usuario jugará en contra de la computadora. Utilice una matriz de tipo char e inicialícela con espacios en blanco. Utilice "O" para la computadora y "X" para el usuario. Haga su algoritmo tan elaborado como considere, no permita que el usuario gane fácilmente; sin embargo, una posibilidad es que cuando sea el turno de la computadora, simplemente recorra la matriz buscando una posición que no esté ocupada.
  18. Considere una implementación básica del Juego de la Vida con base en una matriz de 0's y 1's. El Juego de la Vida fue diseñado por el matemático británico John Horton Conway en 1970.
Arreglos de n dimensiones.
  1. Las figuras del arreglo tridimensional discutidas en el blog (Arreglos de dimensiones) muestran en gris algunos de los elementos del arreglo de tres dimensiones. Denote todos los elementos visibles (para ambas) de dicho arreglo siguiendo la nomenclatura del lenguaje C.
  2. De manera análoga a lo descrito en la entrada Arreglos de dos dimensiones, dibuje y describa la representación física en la memoria del arreglo tridimensional del ejercicio anterior. Sugerencia: la representación en memoria se realiza también de manera lineal: los renglones de la primera matriz, después los de la segunda matriz, etcétera, la representación de malla puede ayudarle a visualizar mejor la representación.
  3. Basándose en el Ejemplo 6.9, escriba un programa que generalice la idea planteada para definir, inicializar, e imprimir en la salida estándar un hipercubo.
  4. Basándose en el Ejemplo 6.9, escriba un programa que generalice la idea planteada para definir, inicializar, e imprimir en la salida estándar un arreglo de cinco dimensiones cada una con un tamaño distinto, por ejemplo: dos para la primera dimensión, tres para la segunda, cuatro para la tercera y así sucesivamente.

1 de agosto de 2017

Diseño y consideraciones.

Diseño básico de programas estructurados.
   La esencia del diseño mostrado a continuación está basado principalmente en las reglas para la formación de programas estructurados propuestas en [Deitel].

   Al conectar de forma arbitraria o poco cuidadosa los símbolos de los diagramas de flujo, se puede incurrir en diagramas de flujo no estructurados como el de la siguiente figura:

Diagrama de flujo no estructurado.

   La generación de diagramas de flujo estructurados requiere de utilizar estructuras de control con una única entrada y una única salida, de tal manera que sólo haya una forma de entrar y una de salir de la estructura de control.

   Las estructuras de control descritas en las entradas Diagramas de flujo y Pseudo código cumplen con lo anterior. Se deja como ejercicio al lector el validar y verificar dicha situación; en éste sentido, observe que aunque la estructura de selección múltiple en el diagrama de flujo parece tener más de una salida, sólo una de ellas es finalmente procesada, y que independientemente de la(s) sentencia(s) que haya(n) sido seleccionada(s), su salida converge a un único punto de salida representado por el conector.

   Reglas para la formación de algoritmos estructurados.
   A continuación se muestran las reglas para la construcción de algoritmos estructurados, mismas que bien podrían denominarse como “Algoritmo para la construcción de algoritmos estructurados”:
  1. Empiece con el diagrama de flujo más simple.
  2. Cualquier rectángulo (acción, sentencia, etc.) puede ser reemplazado por dos rectángulos de manera secuencial. Esta es la regla de apilamiento.
  3. Cualquier rectángulo puede ser reemplazado por cualquier estructura de control. Esta es la regla de anidamiento.
  4. Aplicar de manera sucesiva las reglas 2 y 3.
   En la siguiente figura se muestra la regla 1 y la aplicación repetida de la regla 2.

Aplicación de las reglas 1 y 2.

   La aplicación de las reglas anteriores derivan siempre en un diagrama de flujo estructurado con una apariencia clara de bloques constructivos [Deitel].

   Por otro lado, la siguiente figura muestra la aplicación de la regla de anidamiento al diagrama de flujo más simple que puede haber. Note que los bloques han sido substituidos por estructuras de selección doble y de repetición.

Aplicación de la regla 3.

   Por último, es importante resaltar que la aplicación de la regla 4 genera estructuras más grandes, más complejas y con un nivel de anidamiento más intrincado. Adicionalmente, cabe mencionar también que los diagramas de flujo que resultan de aplicar las reglas descritas anteriormente, constituyen el conjunto de todos los diagramas de flujo estructurados posibles, y por lo tanto, también el conjunto de todos los posibles programas estructurados [Deitel].

Consideraciones finales.
   La programación estructurada no debe confundirse con el conocimiento de un lenguaje de programación. La programación estructurada es un modelo de programación y es independiente del lenguaje que se utilice para su implementación.

   El estudio y el conocimiento de técnicas, así como el desarrollo de algoritmos previos a la fase de implementación, no sólo es una buena práctica de programación, sino un principio esencial de la Ingeniería de Software.

   Por todo lo anterior, si lo que se quiere es llevar a buen fin sus proyectos de programación y evitar dolores de cabeza innecesarios, debe tomar en consideración que, antes de enfrentarse en una lucha encarnizada teniendo a la computadora como su adversario y al lenguaje de programación como arma, debería, antes de escribir su primera línea de código, hacer un análisis profundo del problema a resolver, elaborar un plan de solución general, especificar gradualmente dicho plan, y realizar un conjunto de pruebas representativas.

21 de junio de 2017

Pruebas de escritorio.

   En las secciones correspondientes al algoritmo de Euclides de las entradas Diagramas de flujo y Pseudo código respectivamente, se muestran esencialmente el mismo algoritmo en dos notaciones distintas. El algoritmo de Euclides determina el Máximo Común Divisor (MCD) de dos números enteros positivos.

   Una prueba de escritorio es un tipo de prueba algorítmica que consiste en la validación y verificación del algoritmo a través de la ejecución de las sentencias que lo componen (proceso) para determinar sus resultados (salida) a partir de un conjunto inicial determinado de elementos (entrada).
 
    Por simplicidad y para facilitar la comprensión de la prueba se repetirá aquí la versión en diagrama de flujo, pero se puede y recomienda consultar también la versión en Pseudo código:
Algoritmo de Euclides para determinar el MCD.

   Suponga que desea saber cuál es MCD de 15 y 4. Una prueba de escritorio para el algoritmo de MCD consistiría, en primer lugar, de la identificación de las variables involucradas, es decir:

      m =
      n =
      r =

   La sentencia Obtener(m, n) (proceso de entrada) definirá los valores de las variables m y n respectivamente que, con base en lo planteado en el algoritmo y en lo que se desea saber sería:

      m = 15
      n = 4
      r =

mientras que r se define en función de la expresión r = m mod n, es decir:

      m = 15
      n = 4
      r = 3

el siguiente paso es verificar la condición del while (¿es el residuo r distinto de cero?). Como dicha condición es evaluada como verdadera (tres es distinto de cero), se tendría la siguiente secuencia de valores para las variables con base en las operaciones descritas si se sigue el lado derecho del diamante, mismas que constituyen las operaciones realizadas dentro del ciclo:

      m = 15, 4
      n = 4, 3
      r = 3, 1

para la primera iteración o ejecución del ciclo. Como el residuo es distinto de cero, la condición del ciclo es verdadera y sea realiza una segunda iteración, generando ahora los valores:

      m = 15, 4, 3
      n = 4, 3, 1
      r = 3, 1, 0
 
de donde puede verse, que el MCD de 15 y 4 es 1 (almacenado en n) cuando la condición del ciclo se hace falsa, debido a que el residuo es finalmente cero.

   Asegúrese de comprender el proceso descrito y genere usted mismo cada uno de los valores descritos para corroborar lo aquí expuesto. También utilice ahora los mismos valores pero intercambiados, ¿qué sucede? ¿qué secuencia de valores se genera? ¿cuál es el MCD? ¿cuál es ahora el MCD de 15 y 10? ¿cuál es el MCD de 10 y 15?

   Pruebe con otros valores hasta que comprenda el funcionamiento del algoritmo, y compruebe los resultados de sus pruebas de escritorio con los algoritmos descritos en diagrama de flujo y pseudo código respectivamente.