Algoritmo y Estructura de Datos I - Universidad Tecnológica del Perú

Anuncio
 Algoritmo y Estructura de Datos I UNIVERSIDAD TECNOLÓGICA DEL PERÚ Vicerrectorado de Investigación Algoritmo y Estructura de Datos I TINS Básicos Ingeniería de Telecomunicaciones TEXTOS DE INSTRUCCIÓN BÁSICOS (TINS) / UTP Lima ‐ Perú 1
Algoritmo y Estructura de Datos I © Algoritmo y Estructura de Datos I Desarrollo y Edición: Vicerrectorado de Investigación Elaboración del TINS: Ing. Carlos Lon Kan Prado Diseño y Diagramación: Julia Saldaña Balandra Soporte académico: Instituto de Investigación Producción: Imprenta Grupo IDAT Queda prohibida cualquier forma de reproducción, venta, comunicación pública y transformación de esta obra. 2
Algoritmo y Estructura de Datos I “El presente material contiene una compilación de obras de Algoritmo I publicadas lícitamente, resúmenes de los temas a cargo del profesor; constituye un material auxiliar de enseñanza para ser empleado en el desarrollo de las clases en nuestra institución. Éste material es de uso exclusivo de los alumnos y docentes de la Universidad Tecnológica del Perú, preparado para fines didácticos en aplicación del Artículo 41 inc. C y el Art. 43 inc. A., del Decreto Legislativo 822, Ley sobre Derechos de Autor”. 3
Algoritmo y Estructura de Datos I 4
Algoritmo y Estructura de Datos I Presentación El presente texto elaborado en el marco de desarrollo de la Ingeniería, es un material de ayuda instruccional, en la Carrera de Ingeniería de Telecomunicaciones, para la Asignatura de Algoritmos y Estructura de Datos I. Plasma la iniciativa institucional de innovación de la enseñanza‐aprendizaje educativo universitario, que en acelerada continuidad promueve la producción de materiales educativos, actualizados en concordancia a las exigencias de estos tiempos. Esta primera edición apropiadamente recopilada, de diversas fuentes bibliográficas, de uso frecuente en la enseñanza de algoritmos, está ordenada en función del sillabus de la Asignatura, arriba mencionada. La conformación del texto ha sido posible gracias al esfuerzo y dedicación académica del Profesor Ing.Carlos Lo Kan Prado, como fruto de su destacada experiencia profesional y académica; contiene VII capítulos, cuyas descripciones genéricas son como sigue: En el Capítulo I está referido a los conceptos fundamentales de los algoritmos. En el Capítulo II se explica los diferentes tipos de datos que se utilizan en la programación. En el Capítulo III se aborda la herramienta informática que se utilizara para el desarrollo de las aplicaciones en el computador. En el Capítulo IV se explica las diversas estructuras de control que se presentan. El Capítulo V se centra en la solución de temas de programación modular. En el Capítulo VI se estudia los temas de recursividad. Y en el Capítulo VII se presenta las diversas aplicaciones en lenguaje C. Finalmente, al cierre de estas líneas, el agradecimiento institucional al profesor Ing.Carlos Lo Kan Prado por su contribución a la elaboración del presente texto. Ing. Lucio H. Huamán Ureta Vicerrectorado de Investigación
5
Algoritmo y Estructura de Datos I 6
Algoritmo y Estructura de Datos I Índice Capítulo I Conceptos Fundamentales 1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
1.11
1.12
1.13
Introducción ........................................................................................................... Definición de lenguaje ............................................................................................ Definición de algoritmo .......................................................................................... Tipos de algoritmos ................................................................................................ Lenguajes algorítmicos ........................................................................................... Metodología para la solución de problemas por medio de computadora ............ Definición del problema ......................................................................................... Análisis del problema ............................................................................................. Diseño del algoritmo .............................................................................................. Codificación ............................................................................................................ Prueba y depuración............................................................................................... Documentación ...................................................................................................... Mantenimiento....................................................................................................... 11 13 14 14 14 31 31 31 32 32 32 32 33 Capítulo II Tipos de Datos 2.1
2.2
2.3
2.4
Tipos de datos......................................................................................................... Expresiones............................................................................................................. Operadores y operandos........................................................................................ Identificadores........................................................................................................ 35 35 36 40 Capítulo III Lenguaje de Programación C 3.1
3.2
3.3
3.4
Introducción ........................................................................................................... Características ........................................................................................................ Proceso de edición y compilación .......................................................................... Estructura de un programa .................................................................................... 7
43 43 43 44 Algoritmo y Estructura de Datos I Capítulo IV Estructuras de Control 4.1
4.2
4.3
Tipos de estructuras básica .................................................................................... Estructura secuencial ............................................................................................. Problemas secuenciales.......................................................................................... 59 59 60 Capítulo V Programación Modular 5.1
5.2
6.1
6.2
6.3
El diseño descendente: subprogramas .................................................................. El diseño modular................................................................................................... Capítulo VI Recursividad 89 90 Recursividad ........................................................................................................... 99 Prototipos de funciones ......................................................................................... 107 Arreglos unidimensionales y multidimensionales.................................................. 108 Capítulo VII Aplicaciones Ejercicios............................................................................................................................ 115 Bibliografía ........................................................................................................................ 169 8
Algoritmo y Estructura de Datos I Distribución Temática Clase N° 1 2 3 4 5 Conceptos Fundamentales Concepto de algoritmo. Lenguajes de programación. Herramientas de programación. Tipos de datos. Constantes, variables, identificadores, expresiones, funciones. Estructura General de un Programa Estructura de un Programa en C. Estructura de algoritmos. Contadores, acumuladores. Estructuras de Control Programación Estructurada. Estructuras de Control ‐ Tipos Secuencial Selectiva simple (SI). Selectiva doble (SI ‐ SINO). Selectiva múltiple (SI ‐ SINO ‐ SI). Semana Horas 1 2 3 4 5 6 Selectiva de control (SEGÚN ‐SEA). 6 7 Iterativa (REPETIR ‐ DESDE). 7 8 Estructura Iterativa (REPETIR ‐ MIENTRAS). 8 9 Ejercicios propuestos y nivelación 9 10 11 12 13 10 11 12 13 Tema E X A M E N P A R C I A L Sub programación Programación Modular. Subprogramas – Tipos Variables globales y locales. Funciones, paso de parámetros. Procedimientos paso de parámetros Recursividad Datos estructurados 9
Algoritmo y Estructura de Datos I 14 Tipos. Arreglos unidimensionales, declaración y acceso. Clase N° 15 16 17 Tema Arreglos bidimensionales, declaración y acceso. Registros Concepto. Declaración y acceso. Arreglo de registros. Cadena de caracteres. 14 Semana Horas 15 16 17 18 Índices 18 19 Ejercicios propuestos y nivelación. 19 20 E X A M E N F I N A L 20 10
Algoritmo y Estructura de Datos I CAPÍTULO I Conceptos Fundamentales 1.1 Introducción La computadora no solamente es una máquina que puede realizar procesos para darnos resultados, sin que tengamos la noción exacta de las operaciones que realiza para llegar a esos resultados. Con la computadora además de lo anterior también podemos diseñar soluciones a la medida, de problemas específicos que se nos presenten. Más aun, si estos involucran operaciones matemáticas complejas y/o repetitivas, o requieren del manejo de un volumen muy grande de datos. El diseño de soluciones a la medida de nuestros problemas, requiere como en otras disciplinas una metodología que nos enseñe de manera gradual, la forma de llegar a estas soluciones. A las soluciones creadas por computadora se les conoce como programas y no son más que una serie de operaciones que realiza la computadora para llegar a un resultado, con un grupo de datos específicos. Lo anterior nos lleva al razonamiento de que un programa nos sirve para solucionar un problema específico. Para poder realizar programas, además de conocer la metodología mencionada, también debemos de conocer, de manera específica las funciones que pueden realizarse en la computadora y las formas en que se pueden manejar los elementos que hay en la misma. Computadora: Es un dispositivo electrónico utilizado para procesar información y obtener resultados. Los datos y la información se pueden introducir en la computadora como entrada (input) y a continuación se procesan para producir una salida (output). Proceso de información en la computadora (Fig. 1) Datos de
Entrada
Proceso
Datos de
salida
Figura 1. Proceso Programa: Es el conjunto de instrucciones escritas de algún lenguaje de programación y que ejecutadas secuencialmente resuelven un problema especifico. 11
Algoritmo y Estructura de Datos I Organización física de una computadora CPU
Dispositivos de
Entrada
Unida de
Control
Unidad
Arit.-Log.
Dispositivos de
Salida
Memoria
Figura 2. Organización del Computador Dispositivos de Entrada: Como su nombre lo indica, sirven para introducir datos (información) en la computadora para su proceso. Los datos se leen de los dispositivos de entrada y se almacenan en la memoria central o interna. Ejemplos: teclado, scanners (digitalizadores de rastreo), mouse (ratón), trackball (bola de ratón estacionario), joystick (palancas de juego), lápiz óptico. Dispositivos de Salida: Regresan los datos procesados que sirven de información al usuario. Ejemplo: monitor, impresora. La Unidad Central de Procesamiento (C.P.U) se divide en dos: 9 Unidad de control 9 Unidad Aritmético ‐ Lógica Unidad de Control: Coordina las actividades de la computadora y determina que operaciones se deben realizar y en qué orden; así mismo controla todo el proceso de la computadora. Unidad Aritmética ‐ Lógica: Realiza operaciones aritméticas y lógicas, tales como suma, resta, multiplicación, división y comparaciones. La Memoria de la computadora se divide en dos: 9 Memoria Central o Interna 9 Memoria Auxiliar o Externa Memoria Central (interna): La CPU utiliza la memoria de la computadora para guardar información mientras trabaja con ella; mientras esta información permanezca en memoria, la computadora puede tener acceso a ella en forma directa. Esta memoria construida internamente se llama memoria de acceso aleatorio (RAM). La memoria interna consta de dos áreas de memoria: La memoria RAM (Randon Access Memory): Recibe el nombre de memoria principal o memoria del usuario, en ella se almacena información solo mientras la computadora esta 12
Algoritmo y Estructura de Datos I encendida. Cuando se apaga o arranca nuevamente la computadora, la información se pierde, por lo que se dice que la memoria RAM es una memoria volátil. La memoria ROM (Read Only Memory): Es una memoria estática que no puede cambiar, la computadora puede leer los datos almacenados en la memoria ROM, pero no se pueden introducir datos en ella, o cambiar los datos que ahí se encuentran; por lo que se dice que esta memoria es de solo lectura. Los datos de la memoria ROM están grabados en forma permanente y son introducidos por el fabricante de la computadora. Memoria Auxiliar (Externa): Es donde se almacenan todos los programas o datos que el usuario desee. Los dispositivos de almacenamiento o memorias auxiliares (externas o secundarias) más comúnmente utilizados son: cintas magnéticas y discos magnéticos. 1.2 Definición de Lenguaje Lenguaje: Es una serie de símbolos que sirven para transmitir uno o más mensajes (ideas) entre dos entidades diferentes. A la transmisión de mensajes se le conoce comúnmente como comunicación. La comunicación es un proceso complejo que requiere una serie de reglas simples, pero indispensables para poderse llevar a cabo. Las dos principales son las siguientes: Los mensajes deben correr en un sentido a la vez. Debe forzosamente existir 4 elementos: Emisor, Receptor, Medio de Comunicación y Mensaje. Lenguajes de Programación Es un conjunto de símbolos, caracteres y reglas (programas) que permiten a las personas comunicarse con la computadora. Los lenguajes de programación tienen un conjunto de instrucciones que nos permiten realizar operaciones de entrada/salida, calculo, manipulación de textos, lógica/comparación y almacenamiento/recuperación. Los lenguajes de programación se clasifican en: Lenguaje Maquina: Son aquellos cuyas instrucciones son directamente entendibles por la computadora y no necesitan traducción posterior para que la CPU pueda comprender y ejecutar el programa. Las instrucciones en lenguaje maquina se expresan en términos de la unidad de memoria mas pequeña el bit (dígito binario 0 o 1). Lenguaje de Bajo Nivel (Ensamblador): En este lenguaje las instrucciones se escriben en códigos alfabéticos conocidos como mnemotécnicos para las operaciones y direcciones simbólicas. 13
Algoritmo y Estructura de Datos I Lenguaje de Alto Nivel: Los lenguajes de programación de alto nivel (BASIC, pascal, cobol, frotran, etc.) son aquellos en los que las instrucciones o sentencias a la computadora son escritas con palabras similares a los lenguajes humanos (en general en ingles), lo que facilita la escritura y comprensión del programa. 1.3 Definición de Algoritmo Un algoritmo es una serie de pasos organizados que describe el proceso que se debe seguir, para dar solución a un problema específico. Un algoritmo es una secuencia finita de instrucciones cada una de las cuales tiene un significado claro y puede ser efectuada con una cantidad finita de esfuerzo en una longitud de tiempo también finito. En matemáticas, ciencias de la computación y disciplinas relacionadas, un algoritmo (del latín, dixit algorithmus y éste a su vez del matemático persa al‐Jwarizmi) es una lista bien definida, ordenada y finita de operaciones que permite hallar la solución a un problema. Dado un estado inicial y una entrada, a través de pasos sucesivos y bien definidos se llega a un estado final, obteniendo una solución. Los algoritmos son objeto de estudio de la algoritmia. En la vida cotidiana se emplean algoritmos en multitud de ocasiones para resolver diversos problemas. Algunos ejemplos se encuentran en los instructivos (manuales de usuario), los cuales muestran algoritmos para usar el aparato en cuestión o inclusive en las instrucciones que recibe un trabajador por parte de su patrón. También existen ejemplos de índole matemática, como el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para calcular el máximo común divisor de dos enteros positivos, o el método de Gauss para resolver un Sistema lineal de ecuaciones. 1.4 Tipos de Algoritmos 9 Cualitativos: Son aquellos en los que se describen los pasos utilizando palabras. 9 Cuantitativos: Son aquellos en los que se utilizan cálculos numéricos para definir los pasos del proceso. 1.5 Lenguajes Algorítmicos Es una serie de símbolos y reglas que se utilizan para describir de manera explícita un proceso. Tipos de Lenguajes Algorítmicos Gráficos: Es la representación gráfica de las operaciones que realiza un algoritmo (diagrama de flujo). 14
Algoritmo y Estructura de Datos I No Gráficos: Representa en forma descriptiva las operaciones que debe realizar un algoritmo (pseudocodigo). Medios de expresión de un algoritmo Los algoritmos pueden ser expresados de muchas maneras, incluyendo al lenguaje natural, pseudocódigo, diagramas de flujo y lenguajes de programación entre otros. Las descripciones en lenguaje natural tienden a ser ambiguas y extensas. El usar pseudocódigo y diagramas de flujo evita muchas ambigüedades del lenguaje natural. Dichas expresiones son formas más estructuradas para representar algoritmos; no obstante, se mantienen independientes de un lenguaje de programación específico. La descripción de un algoritmo usualmente se hace en tres niveles: Descripción de alto nivel. Se establece el problema, se selecciona un modelo matemático y se explica el algoritmo de manera verbal, posiblemente con ilustraciones y omitiendo detalles. Descripción formal. Se usa pseudocódigo para describir la secuencia de pasos que encuentran la solución. Implementación. Se muestra el algoritmo expresado en un lenguaje de programación específico o algún objeto capaz de llevar a cabo instrucciones. También es posible incluir un teorema que demuestre que el algoritmo es correcto, un análisis de complejidad o ambos. Diagrama de flujo Definición Es la representación gráfica de flujo de un algoritmo o de secuencia rutinaria. Se basan en la utilización de diversos símbolos para representar operaciones específicas. Se les llama diagramas de flujo porque los símbolos utilizados se conectan por medio de flechas para indicar la secuencia de la operación. Un diagrama de flujo es una forma de representar gráficamente los detalles algorítmicos de un proceso multifactorial. Se utiliza principalmente en programación, economía y procesos industriales, pasando también a partir de estas disciplinas a formar parte fundamental de otras, como la Figura 3. Diagrama de flujo psicología cognitiva. Estos diagramas utilizan una 15
Algoritmo y Estructura de Datos I serie de símbolos con significados especiales y son la representación gráfica de los pasos de un proceso. En computación, son modelos tecnológicos utilizados para comprender los rudimentos de la programación lineal. Símbolos utilizados Los símbolos que se utilizan para diseño se someten a una normalización, es decir, se hicieron símbolos casi universales, ya que, en un principio cada usuario podría tener sus propios símbolos para representar sus procesos en forma de Diagrama de flujo. Esto trajo como consecuencia que sólo aquel que conocía sus símbolos, los podía interpretar. La simbología utilizada para la elaboración de diagramas de flujo es variable y debe ajustarse a las normas preestablecidas universalmente para dichos símbolos o datos. Los diagramas de flujo sirven para representar algoritmos de manera gráfica. Figura 4. Diagrama de flujo Características que debe cumplir un diagrama de flujo En los diagramas de flujo se presuponen los siguientes aspectos: 9 Existe siempre un camino que permite llegar a una solución (finalización del algoritmo). 9 Existe un único inicio del proceso. 9 Existe un único punto de fin para el proceso de flujo (salvo del rombo que indica una comparación con dos caminos posibles). 16
Algoritmo y Estructura de Datos I Desarrollo del Diagrama de Flujo Las siguientes son acciones previas a la realización del diagrama de flujo: 9 Identificar las ideas principales a ser incluidas en el diagrama de flujo. Deben estar presentes el dueño o responsable del proceso, los dueños o responsables del proceso anterior y posterior y de otros procesos interrelacionados, otras partes interesadas. 9 Definir qué se espera obtener del diagrama de flujo. 9 Identificar quién lo empleará y cómo. 9 Establecer el nivel de detalle requerido. 9 Determinar los límites del proceso a describir. Los pasos a seguir para construir el diagrama de flujo son: 9 Establecer el alcance del proceso a describir. De esta manera quedará fijado el comienzo y el final del diagrama. Frecuentemente el comienzo es la salida del proceso previo y el final la entrada al proceso siguiente. 9 Identificar y listar las principales actividades/subprocesos que están incluidos en el proceso a describir y su orden cronológico. 9 Si el nivel de detalle definido incluye actividades menores, listarlas también. 9 Identificar y listar los puntos de decisión. 9 Construir el diagrama respetando la secuencia cronológica y asignando los correspondientes símbolos. 9 Asignar un título al diagrama y verificar que esté completo y describa con exactitud el proceso elegido. Recomendaciones A su vez, es importante que al construir diagramas de flujo, se observen las siguientes recomendaciones: 9 Evitar sumideros infinitos, burbujas que tienen entradas pero no salidas. 9 Evitar las burbujas de generación espontánea, que tienen salidas sin tener entradas, porque son sumamente sospechosas y generalmente incorrectas. 9 Tener cuidado con los flujos y procesos no etiquetados. Esto suele ser un indicio de falta de esmero, pero puede esconder un error aún más grave: a veces el analista no etiqueta un flujo o un proceso porque simplemente no se le ocurre algún nombre razonable. 17
Algoritmo y Estructura de Datos I Ventajas de los diagrama de flujo Favorecen la comprensión del proceso a través de mostrarlo como un dibujo. El cerebro humano reconoce fácilmente los dibujos. Un buen diagrama de flujo reemplaza varias páginas de texto. Permiten identificar los problemas y las oportunidades de mejora del proceso. Se identifican los pasos redundantes, los flujos de los re‐procesos, los conflictos de autoridad, las responsabilidades, los cuellos de botella, y los puntos de decisión. Muestran las interfaces cliente‐proveedor y las transacciones que en ellas se realizan, facilitando a los empleados el análisis de las mismas. Son una excelente herramienta para capacitar a los nuevos empleados y también a los que desarrollan la tarea, cuando se realizan mejoras en el proceso. Tipos de diagramas de flujos Figura 5. Diagrama de flujo Formato vertical: En él el flujo o la secuencia de las operaciones, va de arriba hacia abajo. Es una lista ordenada de las operaciones de un proceso con toda la información que se considere necesaria, según su propósito. Formato horizontal: En él, el flujo o la secuencia de las operaciones, va de izquierda a derecha. Formato panorámico: El proceso entero está representado en una sola carta y puede apreciarse de una sola mirada mucho más rápido que leyendo el texto, lo que facilita su comprensión, aun para personas no familiarizadas. Registra no solo en línea vertical, sino también horizontal, distintas acciones simultáneas y la participación de más de un puesto o departamento que el formato vertical no registra. Formato Arquitectónico: Describe el itinerario de ruta de una forma o persona sobre el plano arquitectónico del área de trabajo. El primero de los flujogramas es eminentemente descriptivo, mientras que los utilizados son fundamentalmente representativos. Crear diagramas de flujos Un diagrama de flujo u organigrama es una representación diagramática que ilustra la secuencia de las operaciones que se realizarán para conseguir la solución de un problema. 18
Algoritmo y Estructura de Datos I Los diagramas de flujo se dibujan generalmente antes de comenzar a programar el código frente a la computadora. Los diagramas de flujo facilitan la comunicación entre los programadores y la gente del negocio. Estos diagramas de flujo desempeñan un papel vital en la programación de un problema y facilitan la comprensión de problemas complicados y sobre todo muy largos. Una vez que se dibuja el diagrama de flujo, llega a ser fácil escribir el programa en cualquier idioma de alto nivel. Vemos a menudo cómo los diagramas de flujo nos dan ventaja al momento de explicar el programa a otros. Por lo tanto, está correcto decir que un diagrama de flujo es una necesidad para la documentación mejor de un programa complejo. Reglas para dibujar un diagrama de flujo Los Diagramas de flujo se dibujan generalmente usando algunos símbolos estándares; sin embargo, algunos símbolos especiales pueden también ser desarrollados cuando sean requeridos. Algunos símbolos estándares, que se requieren con frecuencia para diagramar programas de computadora se muestran a continuación: Inicio o fin del programa Pasos, procesos o líneas de instrucción de programa de computo Operaciones de entrada y salida Toma de decisiones y Ramificación Conector para unir el flujo a otra parte del diagrama Cinta magnética Disco magnético Conector de pagina Líneas de flujo 19
Algoritmo y Estructura de Datos I Anotación Display, para mostrar datos Envía datos a la impresora Figura 6. Simbolos para el diseño de diagramas de flujo Observación: Para obtener la correcta elaboración de los símbolos, existen plantillas. Las puedes conseguir en Papelerías. Símbolos gráficos Dentro de los símbolos fundamentales para la creación de diagramas de flujo, los símbolos gráficos son utilizados específicamente para operaciones aritméticas y relaciones condicionales. La siguiente es una lista de los símbolos más comúnmente utilizados: + Sumar ‐ Menos * Multiplicación / División ± Mas o menos = Equivalente a > Mayor que < Menor que >= Mayor o igual que <= Menor o igual que < > Diferente de Figura 7. Simbolos comunes Reglas para la creación de Diagramas a. Los Diagramas de flujo deben escribirse de arriba hacia abajo, y/o de izquierda a derecha. b. Los símbolos se unen con líneas, las cuales tienen en la punta una flecha que indica la dirección que fluye la información procesos, se deben de utilizar solamente líneas de flujo horizontal o verticales (nunca diagonales). c. Se debe evitar el cruce de líneas, para lo cual se quisiera separar el flujo del diagrama a un sitio distinto, se pudiera realizar utilizando los conectores. Se debe tener en cuenta que solo se van a utilizar conectores cuando sea estrictamente necesario. d. No deben quedar líneas de flujo sin conectar 20
Algoritmo y Estructura de Datos I e. Todo texto escrito dentro de un símbolo debe ser legible, preciso, evitando el uso de muchas palabras. f. Todos los símbolos pueden tener más de una línea de entrada, a excepción del símbolo final. g. Solo los símbolos de decisión pueden y deben tener más de una línea de flujo de salida. Ejemplos de diagramas de flujo Diagrama de flujo que encuentra la suma de los primeros 50 números naturales Figura 8. Diagrama de flujo Bueno, ahora la descripción detallada del diagrama anterior Suma, es la variable a la que se le va agregando el valor de cada número natural. N, es el contador. Éste recorrerá los números hasta llegar al 50. 21
Algoritmo y Estructura de Datos I • El primer bloque indica el inicio del Diagrama de flujo • El segundo bloque, es un Símbolo de procesos En este bloque se indica que las variables suma y N han sido declaradas previamente y se inicializan en 0 para comenzar el conteo y la suma de valores. • El tercer bloque, es también un Símbolo de procesos En éste paso se incrementa en 1 la variable N (N = N + 1). Por lo que, en la primera lectura la variable N valdrá 1, ya que se inicializo en 0. • El cuarto bloque es exactamente lo mismo que el anterior Pero aquí la variable suma es igual a la variable suma agregada en el valor de N (En el primer caso Suma contendrá 1, ya que N = 1). • El quinto bloque es un Símbolo de Toma de decisiones y Ramificación Lo que hay dentro del bloque es una pregunta que se le hace a alguna variable para validar una condición. En este caso ¿Es N=50?, Obviamente la respuesta es no, ya que N todavía es 1. por lo que el flujo de nuestro programa se dirigirá hacía la parte en donde se observa la palabra no: Tercer Bloque, éste le sumará 1 (N=N+1) y vuelve a llegar a éste bloque, donde preguntará ¿Es N=50?... ¡No!, todavía es 2. Entonces, regresa al Tercer bloque y vuelve hacer lo mismo. Y así hasta llegar a 50, obteniendo así la suma de los primeros 50 primeros números naturales. • Por último indicamos que el resultado será mostrado en la pantalla (Display). • Fin del programa (o diagrama) Pseudocódigo Pseudocódigo es la descripción de un algoritmo que asemeja a un lenguaje de programación pero con algunas convenciones del lenguaje natural. Tiene varias ventajas con respecto a los diagramas de flujo, entre las que se destaca el poco espacio que se requiere para representar instrucciones complejas. El pseudocódigo no está regido por ningún estándar. Pseudo viene de falso y por ende es un código al que aunque es entendible no se aplica al proceso que debe realizar la máquina o computador. 22
Algoritmo y Estructura de Datos I Un pseudocódigo (lenguaje natural), es una serie de palabras léxicas y gramaticales referidos a los lenguajes de programación, pero sin llegar a la rigidez de la sintaxis de estos ni a la fluidez del lenguaje coloquial. Esto permite codificar un programa con mayor agilidad que en cualquier lenguaje de programación, con la misma validez semántica, normalmente se utiliza en las fases de análisis o diseño de Software, o en el estudio de un algoritmo. Forma parte de las distintas herramientas de la ingeniería de software. Es, netamente, lenguaje de tipo informático. Para probar el algoritmo se utiliza un Pseudo intérprete el cual se encuentra disponible para las plataformas GNU/Linux y Windows, es de código libre y está escrito en C++. El mismo se ejecuta en un Terminal. El pseudocódigo describe un algoritmo utilizando una mezcla de frases en lenguaje común, instrucciones de programación y palabras clave que definen las estructuras básicas. Su objetivo es permitir que el programador se centre en los aspectos lógicos de la solución a un problema. No siendo el pseudocódigo un lenguaje formal, varían de un programador a otro, es decir, no hay una estructura semántica ni arquitectura estándar. Es una herramienta ágil para el estudio y diseño de aplicaciones, veamos un ejemplo, que podríamos definir como: lenguaje imperativo, de tercera generación, según el método de programación estructurada. Pseudocódigo = Pseudo (Supuesto) + Código (Instrucción) Comencemos aclarando que no es una forma de programación. Se trata de una herramienta que los analistas de sistemas utilizan para comunicar a los programadores la estructura del programa que van a realizar, de forma de tener una idea bien clara de lo que se necesita programar. Digamos que el pseudo código es una forma de diagramar un algoritmo para resolver un determinado problema, sin atenerse a ningún lenguaje de programación en especial. Un algoritmo es un conjunto de procedimientos que permiten resolver un problema. En vez de escribir el programa directamente en un lenguaje de programación determinado (C, C++, Visual Basic, etc.), crearemos un borrador entendible para todos, para luego de tener bien en claro lo que se debe hacer, pasar a la programación propiamente dicha. Figura 9. Pseudo codigo 23
Algoritmo y Estructura de Datos I No hay que confundirlo con un diagrama de flujo. En el diagrama de flujo se representa el transcurso del programa, el momento donde se obtienen los datos, cuando se procesan y el momento de presentar los resultados. Si bien son dos herramientas que se utilizan en conjunto, cada una representa dos partes distintas en el diseño de un sistema. El pseudo código se refiere a crear un código para orientar a los programadores, pero sin la sintaxis ni la estructura propia de ningún lenguaje. Utilización en la práctica En el trabajo de un ingeniero analista, una de las partes más trabajosas es la de determinar qué es lo que necesitan de un sistema los usuarios finales. Se dedican muchas horas a hacer un relevamiento de los datos que serán necesarios, los tipos de procesamientos, las salidas, etc. Y debe existir una realimentación entre el diseño y el usuario, para garantizar que el sistema cumpla con los requisitos del usuario. Figura 10. Un sistema Supongamos que tenemos un sistema para una empresa que utiliza una interfaz gráfica en Visual Basic, algunas aplicaciones específicas en C, y páginas PHP para trabajo vía Internet. Seguramente que crear un diagrama específico para cada lenguaje sería una tarea tediosa. Gracias a esta herramienta, podemos reunir a todos los programadores, dar las pautas de trabajo, y mediante el pseudo código, cada programador sabrá lo que hace el sistema, y podrá escribir el código correspondiente. Incluso dos programadores que dominen el mismo lenguaje pueden tener metodologías de trabajo distintas. Un problema puede ser resuelto de muchas maneras, cada una más o menos eficiente que la otra, pero todas cumplen con el objetivo. 24
Algoritmo y Estructura de Datos I Figura 11. Lenguajes y el pseudo codigo El pseudo código elimina estas diferencias, dando libertad a los programadores para que puedan ajustarse a su metodología de trabajo. Generalmente, este código se escribe con la participación de todos los programadores. Esto representa la ventaja de que muchas opiniones ayudan a elegir la mejor entre todas, logrando una solución efectiva y eficaz al problema planteado. Definición de datos del Pseudocódigo La definición de datos se da por supuesta, sobre todo en las variables sencillas, si se emplea formaciones: pilas, colas, vectores o registros, se pueden definir en la cabecera del algoritmo, y naturalmente cuando empleemos el pseudocódigo para definir estructuras de datos, esta parte la desarrollaremos adecuadamente. Funciones y operaciones Como se había mencionado antes, cada autor usa su propio pseudocódigo con sus respectivas convenciones. Por ejemplo, considere la instrucción "Reemplace el valor de la variable x por el valor de la variable y"; algunas de las posibles sintaxis para indicar lo anterior podrían ser: Asigne a el valor de Las operaciones aritméticas se representan de la forma usual en matemáticas. 25
Algoritmo y Estructura de Datos I y las operaciones complejas se representan del mismo modo: Ejemplo 1: Hacer un pseudocodigo que imprima los números del 1 al 100. PROGRAMA contador1 ENTORNO: c Å 0 ALGORITMO: Borrar_pantalla( ) MIENTRAS c < 101 HACER ESCRIBIR c c Å c + 1 FINMIENTRAS FINPROGRAMA Ejemplo 2: Hacer un pseudocodigo que imprima los números del 100 al 0, en orden decreciente. PROGRAMA contador2 ENTORNO: c Å 100 ALGORITMO: Borrar_pantalla( ) MIENTRAS c >= 0 HACER ESCRIBIR c c Å c ‐ 1 FINMIENTRAS FINPROGRAMA 26
Algoritmo y Estructura de Datos I Ejemplo 3: Hacer un pseudocodigo que imprima los números pares entre 0 y 100. PROGRAMA pares ENTORNO: c Å 2 ALGORITMO: Borrar_pantalla( ) MIENTRAS c < 101 HACER ESCRIBIR c c Å c + 2 FINMIENTRAS FINPROGRAMA Ejemplo 4: Hacer un programa que imprima la suma de los 100 primeros números. PROGRAMA suma ENTORNO: c Å 1 suma Å 0 ALGORITMO: Borrar_pantalla( ) MIENTRAS c <= 100 HACER suma Å suma + c c Å c + 1 FINMIENTRAS ESCRIBIR "La suma de los 100 primeros números es: " ESCRIBIR suma FINPROGRAMA 27
Algoritmo y Estructura de Datos I Ejemplo 5: Hacer un pseudocódigo que imprima los números impares hasta el 100 y que imprima cuantos impares hay. PROGRAMA impares ENTORNO: c Å 1 son Å 0 ALGORITMO: Borrar_pantalla( ) MIENTRAS c < 100 ESCRIBIR c c Å c + 2 son Å son + 1 FINMIENTRAS ESCRIBIR "El numero de impares: " ESCRIBIR son FINPROGRAMA Ejemplo 6: Hacer un pseudocodigo que imprima todos los números naturales que hay desde la unidad hasta un numero que introducimos por teclado. PROGRAMA natural ENTORNO: i Å 0 n Å 0 ALGORITMO: Borrar_pantalla( ) ESCRIBIR "Introduce un numero: " LEER n MIENTRAS i < n HACER i Å i + 1 ESCRIBIR i FINMIENTRAS FINPROGRAMA 28
Algoritmo y Estructura de Datos I Ejemplo 7: Introducir un numero por teclado. Que nos diga si es par o impar. PROGRAMA paridad ENTORNO: num Å 0 ALGORITMO: Borrar_pantalla( ) ESCRIBIR "Introduce un n£mero: " LEER num SI num = int( num / 2 ) * 2 ENTONCES ESCRIBIR "es par" SINO ESCRIBIR "es impar" FINSI FINPROGRAMA Ejemplo 8: Imprimir y contar los múltiplos de 3 desde la unidad hasta un numero que introducimos por teclado. PROGRAMA multiplo ENTORNO: i Å 3 n Å 0 c Å 0 ALGORITMO: Borrar_pantalla( ) ESCRIBIR "Numero: " LEER n MIENTRAS i <= n HACER SI i = int( i / 3 ) * 3 ENTONCES ESCRIBIR i c Å c + 1 FINSI i Å i + 1 FINMIENTRAS ESCRIBIR "El n£mero de m£ltiplos de 3 son: " ESCRIBIR c FINPROGRAMA 29
Algoritmo y Estructura de Datos I Ejercicios Propuestos Construir diagramas de Flujo y Pseudo Códigos para los siguientes enunciados: 1. Mostrar su Nombre y su Apellido 2. Mostrar el Nombre y Apellido de cualquier persona de quien se introduzcan los datos. 3. Sumar 2 + 2 y mostrar el resultado (por pantalla, por impresora, por pantalla e impresora) 4. Sumar 2 números cualesquiera. 5. Dados 2 números, estar en capacidad de sumarlos, restarlos, multiplicarlos y dividirlos. 6. Dados los coeficientes de una Ecuación de 2do Grado, calcular y mostrar x1 y x2. 7. Calcular la Serie de Fibonacci hasta un número dado. 8. Calcular la edad 9 fácil: al introducir sólo el año de nacimiento 9 mediano: al introducir el mes y año de nacimiento 9 complejo: al introducir el día, mes y año de nacimiento 9. Calcular la nota definitiva para 5 alumnos, tomando en cuenta las ponderaciones siguientes: 9 1er Practica: 30% 9 2do Practica: 25% 9 3er Practica: 20% 9 4ta Practica: 25% 10. 10.Calcular el sueldo quincenal, tomando en cuenta los siguientes parámetros: 9 Bs 450.000 por quincena 9 Bono de 10% de profesionalización a los que tienen título universitario 9 Bono quincenal de transporte de Bs 70.000 9 Bono de alimentación de Bs 5.000 por día laborado 9 Deducciones: ƒ 2% Seguro Colectivo ƒ 1% Paro Forzoso ƒ 2% Seguro Social ƒ 2% Caja de Ahorro 11. Calcular los números primos en un rango dado. 12. Calcular la suma de todos los números enteros impares, en un rango dado. 13. Calcular el factorial de un número. 14. Problema: Buscar una carta Se tiene un mazo de cartas inglesas, el cual no está completo, pero se sabe que tiene “n” cartas, y está desordenado. Se desea determinar si una carta determinada está o no en el mazo, y si está, en qué posición 15. Problema: serie de ulam Dado un valor inicial “x”, se pide generar los términos de la serie de Ulam. 30
Algoritmo y Estructura de Datos I Se dice que cualquier número menor que 1800 converge a 1 si se calcula cada término siguiendo las reglas de la serie de Ulam. La regla para calcular el término siguiente a “x” es: 9 Si x par, el siguiente término se obtiene dividiendo x por 2 9 Si x es impar, el siguiente término se obtiene multiplicando x por 3 y sumando 1 al resultado. 16. Problema: caída libre La ecuación que rige el movimiento uniformemente acelerado de una partícula está dado por la siguiente fórmula: x(t)= xo + vo * t + ½ * a * t2, donde xo es la posición inicial de la partícula, vo es la velocidad inicial y a, la aceleración. El movimiento de caída libre se rige por la misma ecuación anterior, salvo que la velocidad inicial es cero, (se deja caer el objeto del reposo), y la aceleración es la constante g, que se puede aproximar por 10 con signo negativo. Construya un algoritmo que reciba como entrada una altura h, desde la cual se deja caer un objeto, y entregue como salida la posición de la partícula, y el tiempo transcurrido en cada segundo desde que es soltado hasta que llega al suelo. Indicación. Considere posición inicial h, y posición final 0 (suelo) 17. Problema: Máquina de Sencillar Se tiene una máquina que permite sencillar dinero. La máquina está diseñada para que, dado un monto cualquiera, indique cuantos billetes de 1000 y monedas de 100, 10 y 1 debe entregar, a cambio de ese monto. Una característica de esta máquina es que siempre intentará dar la menor cantidad de monedas. Construya el algoritmo que permita que la máquina funcione de la forma descrita. Es decir, un algoritmo que reciba como entrada un monto de dinero, entero, positivo y entregue como salida la cantidad de billetes y de monedas de las distintas denominaciones que equivalen a dicho monto. 1.6 Metodología para la solución de problemas por medio de computadora 1.7 Definición del Problema Esta fase está dada por el enunciado del problema, el cual requiere una definición clara y precisa. Es importante que se conozca lo que se desea que realice la computadora; mientras esto no se conozca del todo no tiene mucho caso continuar con la siguiente etapa. 1.8 Análisis del Problema Una vez que se ha comprendido lo que se desea de la computadora, es necesario definir: 9 Los datos de entrada. 9 Cuál es la información que se desea producir (salida) 9 Los métodos y fórmulas que se necesitan para procesar los datos. 31
Algoritmo y Estructura de Datos I Una recomendación muy practica es el que nos pongamos en el lugar de la computadora y analicemos que es lo que necesitamos que nos ordenen y en que secuencia para producir los resultados esperados. 1.9 Diseño del Algoritmo Las características de un buen algoritmo son: 9 Debe tener un punto particular de inicio. 9 Debe ser definido, no debe permitir dobles interpretaciones. 9 Debe ser general, es decir, soportar la mayoría de las variantes que se puedan presentar en la definición del problema. 9 Debe ser finito en tamaño y tiempo de ejecución. 1.10 Codificación La codificación es la operación de escribir la solución del problema (de acuerdo a la lógica del diagrama de flujo o pseudocodigo), en una serie de instrucciones detalladas, en un código reconocible por la computadora, la serie de instrucciones detalladas se le conoce como código fuente, el cual se escribe en un lenguaje de programación o lenguaje de alto nivel. 1.11 Prueba y Depuración Los errores humanos dentro de la programación de computadoras son muchos y aumentan considerablemente con la complejidad del problema. El proceso de identificar y eliminar errores, para dar paso a una solución sin errores se le llama depuración. La depuración o prueba resulta una tarea tan creativa como el mismo desarrollo de la solución, por ello se debe considerar con el mismo interés y entusiasmo. Resulta conveniente observar los siguientes principios al realizar una depuración, ya que de este trabajo depende el éxito de nuestra solución. 1.12 Documentación Es la guía o comunicación escrita es sus variadas formas, ya sea en enunciados, procedimientos, dibujos o diagramas. A menudo un programa escrito por una persona, es usado por otra. Por ello la documentación sirve para ayudar a comprender o usar un programa o para facilitar futuras modificaciones (mantenimiento). La documentación se divide en tres partes: ƒ Documentación Interna ƒ Documentación Externa ƒ Manual del Usuario 32
Algoritmo y Estructura de Datos I Documentación Interna: Son los comentarios o mensaje que se añaden al código fuente para hacer más claro el entendimiento de un proceso. Documentación Externa: Se define en un documento escrito los siguientes puntos: 9 Descripción del Problema 9 Nombre del Autor 9 Algoritmo (diagrama de flujo o pseudocodigo) 9 Diccionario de Datos 9 Código Fuente (programa) Manual del Usuario: Describe paso a paso la manera cómo funciona el programa, con el fin de que el usuario obtenga el resultado deseado. 1.13 Mantenimiento Se lleva a cabo después de terminado el programa, cuando se detecta que es necesario hacer algún cambio, ajuste o complementación al programa para que siga trabajando de manera correcta. Para poder realizar este trabajo se requiere que el programa este correctamente documentado. 33
Algoritmo y Estructura de Datos I 34
Algoritmo y Estructura de Datos I CAPÍTULO II Tipos de Datos 2.1 Tipos De Datos Todos los datos tienen un tipo asociado con ellos. Un dato puede ser un simple carácter, tal como ‘b’, un valor entero tal como 35. El tipo de dato determina la naturaleza del conjunto de valores que puede tomar una variable. Simples
Tipos de
datos
Numéricos
Lógicos
Alfanuméricos (string)
Arreglos (Vectores, Matrices)
Estructurados Registros
(Def. por el
Archivos
usuario)
Apuntadores
Tipos de Datos Simples Datos Numéricos: Permiten representar valores escalares de forma numérica, esto incluye a los números enteros y los reales. Este tipo de datos permiten realizar operaciones aritméticas comunes. Datos Lógicos: Son aquellos que solo pueden tener dos valores (cierto o falso) ya que representan el resultado de una comparación entre otros datos (numéricos o alfanuméricos). Datos Alfanuméricos (String): Es una secuencia de caracteres alfanuméricos que permiten representar valores identificables de forma descriptiva, esto incluye nombres de personas, direcciones, etc. Es posible representar números como alfanuméricos, pero estos pierden su propiedad matemática, es decir no es posible hacer operaciones con ellos. Este tipo de datos se representan encerrados entre comillas. Ejemplo: “Instituto Tecnológico de los Olivos” “2009” 2.2 Expresiones Las expresiones son combinaciones de constantes, variables, símbolos de operación, paréntesis y nombres de funciones especiales. Por ejemplo: 35
Algoritmo y Estructura de Datos I a+(b + 3)/c Cada expresión toma un valor que se determina tomando los valores de las variables y constantes implicadas y la ejecución de las operaciones indicadas. Una expresión consta de operadores y operandos. Según sea el tipo de datos que manipulan, se clasifican las expresiones en: 9 Aritméticas 9 Relaciónales 9 Lógicas 2.3 Operadores y Operandos Operadores: Son elementos que relacionan de forma diferente, los valores de una o más variables y/o constantes. Es decir, los operadores nos permiten manipular valores. Tipos de Operadores
Aritméticos
Relaciónales
Lógicos
Operadores Aritméticos: Los operadores aritméticos permiten la realización de operaciones matemáticas con los valores (variables y constantes). Los operadores aritméticos pueden ser utilizados con tipos de datos enteros o reales. Si ambos son enteros, el resultado es entero; si alguno de ellos es real, el resultado es real. Operando (Operador) Operando
Valor
(constante o variable)
Operadores Aritméticos + Suma ‐ Resta * Multiplicación / División Mod Modulo (residuo de la división entera) 36
Algoritmo y Estructura de Datos I Ejemplos: Expresión Resultado 9 7 / 2 = 3.5 9 12 mod 7 = 5 9 4 + 2 * 5 = 14 Prioridad de los Operadores Aritméticos Todas las expresiones entre paréntesis se evalúan primero. Las expresiones con paréntesis anidados se evalúan de dentro a fuera, el paréntesis más interno se evalúa primero. Dentro de una misma expresión los operadores se evalúan en el siguiente orden. 1.‐ ^ Exponenciación 2.‐ *, /, mod Multiplicación, división, modulo. 3.‐ +, ‐ Suma y resta. Los operadores en una misma expresión con igual nivel de prioridad se evalúan de izquierda a derecha. Ejemplos: ƒ 4 + 2 * 5 = 14 ƒ 23 * 2 / 5 = 9.2 ƒ 46 / 5 = 9.2 ƒ 3 + 5 * (10 ‐ (2 + 4)) = 23 3 + 5 * (10 ‐ 6) = 3 + 5 * 4 = 3 + 20 = 23 ƒ 3.5 + 5.09 ‐ 14.0 / 40 = 5.09 3.5 + 5.09 ‐ 3.5 = 8.59 ‐ 3.5 = 5.09 ƒ 2.1 * (1.5 + 3.0 * 4.1) = 28.98 2.1 * (1.5 + 12.3) = 2.1 * 13.8 = 28.98 Operadores Relaciónales: 9 Se utilizan para establecer una relación entre dos valores. 9 Compara estos valores entre si y esta comparación produce un resultado de certeza o falsedad (verdadero o falso). 37
Algoritmo y Estructura de Datos I 9 Los operadores relaciónales comparan valores del mismo tipo (numéricos o cadenas) 9 Tienen el mismo nivel de prioridad en su evaluación. 9 Los operadores relaciónales tiene menor prioridad que los aritméticos. Operadores Relaciónales > Mayor que < Menor que > = Mayor o igual que < = Menor o igual que < > Diferente = Igual Ejemplos: Si a = 10, b = 20, c = 30 a + b > c Falso a ‐ c Verdadero a ‐ b = c Falso a * b < > c Verdadero Ejemplos no lógicos: a < b < c 10 < 20 < 30 T < 30 (no es lógico porque tiene diferentes operandos) Operadores Lógicos: 9 Estos operadores se utilizan para establecer relaciones entre valores lógicos. 9 Estos valores pueden ser resultado de una expresión relacional. Operadores Lógicos And Y Or O Not Negación 38
Algoritmo y Estructura de Datos I Operando And Operando1
T
T
F
F
Operador
AND
Operando2
T
F
T
F
Resultado
T
F
F
F
Operando1
T
T
F
F
Operador
OR
Operando2
T
F
T
F
Resultado
T
T
T
F
Operando
T
F
Resultado
F
T
Operando Or Operando Not Ejemplos: (a < b) and (b < c)
(10<20) and (20<30)
T and
T
T
Prioridad de los Operadores Lógicos
Not
And
Or
Prioridad de los Operadores en General
1.- ( )
2.- ^
3.- *, /, Mod, Not
4.- +, -, And
5.- >, <, > =, < =, < >, =, Or
39
Algoritmo y Estructura de Datos I Ejemplos: a = 10 b = 12 c = 13 d =10
1)
((a > b) or (a < c)) and ((a = c) or (a > = b))
F
T
F
F
T
F
F
2)
((a > = b) or (a < d)) and (( a > = d) and (c > d))
F
F
T
T
F
T
F
3)
not (a = c) and (c > b)
F
T
T
T
2.4 Identificadores Los identificadores representan los datos de un programa (constantes, variables, tipos de datos). Un identificador es una secuencia de caracteres que sirve para identificar una posición en la memoria de la computadora, que nos permite tener acceso a su contenido. Ejemplo: 9 Nombre 9 Num_hrs 9 Calif2 Reglas para formar un Identificador 9 Debe comenzar con una letra (A a Z, mayúsculas o minúsculas) y no deben contener espacios en blanco. 9 Letras, dígitos y caracteres como la subraya ( _ ) están permitidos después del primer carácter. 9 La longitud de identificadores puede ser de hasta 8 caracteres. Constantes y Variables Constante: Una constante es un dato numérico o alfanumérico que no cambia durante la ejecución del programa. Ejemplo: pi = 3.1416 40
Algoritmo y Estructura de Datos I Variable: Es un espacio en la memoria de la computadora que permite almacenar temporalmente un dato durante la ejecución de un proceso, su contenido puede cambia durante la ejecución del programa. Para poder reconocer una variable en la memoria de la computadora, es necesario darle un nombre con el cual podamos identificarla dentro de un algoritmo. Ejemplo: área = pi * radio ^ 2 Las variables son: el radio, el área y la constate es pi Clasificación de las Variables Numéricas
Por su Contenido
Lógicas
Alfanuméricas (String)
Variables
De Trabajo
Contadores
Acumuladores
Por su Uso
Por su Contenido Variable Numéricas: Son aquellas en las cuales se almacenan valores numéricos, positivos o negativos, es decir almacenan números del 0 al 9, signos (+ y ‐) y el punto decimal. Ejemplo: IGV=0.15 pi=3.1416 costo=2500 Variables Lógicas: Son aquellas que solo pueden tener dos valores (cierto o falso) estos representan el resultado de una comparación entre otros datos. Variables Alfanuméricas: Esta formada por caracteres alfanuméricos (letras, números y caracteres especiales). Ejemplo: letra=’a’ apellido=’lopez’ direccion=’Av. Libertad #190’ 41
Algoritmo y Estructura de Datos I Por su Uso Variables de Trabajo: Variables que reciben el resultado de una operación matemática completa y que se usan normalmente dentro de un programa. Ejemplo: Suma=a+b/c Contadores: Se utilizan para llevar el control del número de ocasiones en que se realiza una operación o se cumple una condición. Con los incrementos generalmente de uno en uno. Acumuladores: Forma que toma una variable y que sirve para llevar la suma acumulativa de una serie de valores que se van leyendo o calculando progresivamente. 42
Algoritmo y Estructura de Datos I CAPÍTULO III Lenguaje de Programación C 3.1 Introducción Fue creado por Dennis Ritchie de los laboratorios BELL en 1972, cuando trabajaba junto a Ken Thompson, en el diseño del sistema operativo UNIX. Se deriva del lenguaje B de Thompson, que a su vez se deriva del BCPL de Martín Richards. 3.2 Características Es un lenguaje moderno de propósito general, que incorpora las características de control apuntadas como deseables por la teoría y práctica de la informática. 9 Planificación escalonada. 9 Programación estructurada. 9 Diseño modular. 9 Programas compactos. 9 Rapidez de ejecución. 9 Portátil. 9 De relativo bajo nivel. 9 Precisa compilarse. 3.3 Proceso de edición y compilación Los pasos necesarios para desarrollar un programa C son los siguientes: a. Edición: Utilizar un editor para escribir el programa fuente texto. b. Compilación: Compilar el programa fuente, es decir, traducir el programa a lenguaje máquina. c. Ejecución: Una vez compilado se procede a la ejecución del programa tecleando el nombre del fichero‐programa. 43
Algoritmo y Estructura de Datos I Figura 1. Diagrama de flujo 3.4 Estructura de un programa Un programa en C consiste en una o más funciones, de las cuales una de ellas, debe llamarse main() y es la principal de todas. 9 El programa comienza con la función: main() 9 Cada función o programa, consta de un cuerpo de función delimitado por llaves de comienzo y fin { } 9 En el cuerpo de la función irán incluidas: sentencias, variables, funciones, etc. terminadas cada una de ellas por un punto y coma; 44
Algoritmo y Estructura de Datos I Programa ejemplo: /* Este programa imprime un mensaje */ #include <stdio.h> main() { printf(“LENGUAJE C\n”); } En el programa anterior, existen dos funciones: main() que es la principal del programa en sí y la función printf() que es una función de la librería estándar del lenguaje C. Al ejecutar el programa, en pantalla aparece el texto LENGUAJE C. Programa ejemplo: /* El programa solicita el radio y muestra el */ /* valor del área del círculo y la longitud de */ /* la circunferencia */ #include <stdio.h> #define PI 3.14159 main() { int r; float l, a; printf(“Introduce radio (entero): “); scanf(“%d”, &r); l=2*PI*r; a=PI*r*r; printf(“La longitud de la circunferencia vale %f\n”, l); printf(“El área del círculo vale %f\n”, a); } 45
Algoritmo y Estructura de Datos I Los datos en C: Variables y Constantes Tipos de Datos Los datos manejados en C pueden ser de cinco tipos básicos. 9 INT: enteros sin decimales entre (‐32768 y +32767). Ocupan en la memoria 2 bytes. 9 CHAR: caracteres alfabéticos, signos especiales, etc. El rango es (0 y 255). Ocupan en la memoria 1 byte. 9 FLOAT: números decimales entre (3.4E‐38 a 3.4E+38) con ocho dígitos de precisión. Ocupan en la memoria 4 bytes. 9 DOUBLE: números decimales entre (1.7E‐308 a 1.7E+308) con 16 dígitos de precisión. Ocupan en la memoria 8 bytes. 9 VOID: sin valor. No almacenar nada y por tanto no necesitan espacio físico de la memoria. Identificadores de Tipo Todos los tipos básicos excepto void pueden tener modificadores. Se usan para alterar el significado de un tipo base de acuerdo con nuestras necesidades. Los modificadores son: 9 signed 9 unsigned 9 long 9 short Se pueden aplicar todos los modificadores para los tipos base carácter y entero. También se puede aplicar el modificador long a double. A continuación mostramos todas las posibles combinaciones de los tipos básicos y los modificadores. 46
Algoritmo y Estructura de Datos I Figura 2. Tipos de identificadores NOTA: El espacio ocupado en la memoria por los tipos de datos aquí mostrados vendrá determinado por el tipo de compilador implementado. En cualquier caso, mediante la función sizeof (tipo de dato) se podrá determinar el número de bytes ocupados. Variables Se utilizan para almacenar datos internamente en la memoria de trabajo del ordenador, durante la ejecución de un programa. Como nombres de variables se admiten letras y números (por norma letras minúsculas). 9 El primer carácter debe ser una letra. 9 No se admiten blancos pero sí el signo de subrayado. 9 Sólo se admiten los ocho primeros caracteres. 9 Mayúsculas y minúsculas se diferencian. 9 No se pueden emplear palabras clave del lenguaje. Las variables deben ser declaradas según el tipo de datos que van a almacenar. Bien al comienzo del programa o antes de ser usadas por primera vez. La forma de declararlas es: 9 Se define el tipo de dato a almacenar. 9 Nombre de la variable. 9 Asignación de un valor inicial (no obligatorio). 47
Algoritmo y Estructura de Datos I Ejemplo: /* Declaración de variables */ #include <stdio.h> main() { int a=3, b=7, c=0; c=a*b; printf(“El resultado es: %d”,c); } Constantes Son valores que no varían durante la ejecución de un programa. Pueden adoptar cualquiera de los tipos de datos declarados anteriormente. Es conveniente declararlas al principio del programa. La sentencia #define es usada para definir las constantes y se coloca al principio del programa antes de la función main(). #define PI 3.14159 #define PRIMO 13 Las constantes como norma se suelen escribir con mayúsculas. Operadores Fundamentales En C se utilizan operadores para representar operaciones matemáticas. Por ejemplo, el operador + hace que se sumen los valores situados a su izquierda y derecha. Veamos los que hemos dado en llamar fundamentales. Operador de asignación: = Asigna a la variable de la izquierda el valor de la derecha. bmw=2002; Operador de adición: + Hace que los dos valores situados a su izquierda y derecha se sumen. bmw=10+20; 48
Algoritmo y Estructura de Datos I Operador de sustracción: ‐ Hace que se reste el número situado a su derecha del situado a su izquierda. costo=350‐25; El signo menos también se utiliza para indicar o cambiar el signo algebraico de un valor. pepe=‐12; paco=‐pepe; Operador de multiplicación: * Hace que se multipliquen los dos valores situados a su izquierda y derecha. pulg=10; cm=2.54*pulg; Operador de división: / Hace que el valor situado a su izquierda sea dividido por el que se encuentra a su derecha. cuatro=12.0/3.0; Operadores Adicionales A la lista de los operadores anteriores (que son los más comunes), vamos a añadir ahora tres operadores que resultan bastantes útiles. Operador módulo: % Proporciona el resto de la división entera del número situado a su izquierda entre el situado a su derecha. pepe=15%5; Operador incremento: ++ Realiza la tarea de incrementar en uno el valor de su operando. a++; modo sufijo ++a; modo prefijo La diferencia entre ambos, reside en el preciso momento en que se realiza la operación incremento. Operador decremento: ‐‐ Realiza la tarea de disminuir en uno el valor de su operando. b‐‐; modo sufijo ‐‐b; modo prefijo 49
Algoritmo y Estructura de Datos I La diferencia entre ambos, es la misma que en el caso anterior. Operadores Condicionales o de Relación Los operadores de relación o condicionales se emplean para hacer comparaciones. A continuación, mostramos una lista completa de estos operadores en C. Operadores Lógicos Cuando necesitamos combinar dos o más expresiones de relación, hacemos uso de los operadores lógicos. Existen tres operadores lógicos en C. Operadores de Bit Las operaciones sobre bits se refieren a la comprobación, configuración o desplazamiento de los bits reales en un byte o palabra, que corresponden a los tipos de datos char e int. No se pueden usar operaciones sobre bits en los tipos float, double, long doublé y void. Los operadores que existen para el tratamiento de bits, son los siguientes: 50
Algoritmo y Estructura de Datos I Normas de Precedencia de los Operadores No todos los operadores tienen la misma prioridad, lo que quiere decir, que aquellas operaciones que utilizan ciertos operadores se efectuarán antes que otras. Libreria stdio.h stdio.h, que significa "standard input‐output header" (cabecera estandar E/S), es la biblioteca estándar del lenguaje de programación C, el archivo de cabecera que contiene las definiciones de macros, las constantes, las declaraciones de funciones y la definición de tipos usados por varias operaciones estándar de entrada y salida. Por motivos de compatibilidad, el lenguaje de programación C++ (derivado de C) también tiene su propia implementación de estas funciones, que son declaradas con el archivo de cabecera cstdio. Las funciones declaradas en stdio.h son sumamente populares. 51
Algoritmo y Estructura de Datos I Ejemplo: En lenguaje C y sus derivados, todas las funciones son declaradas en archivos de cabecera. Así, los programadores tienen que incluir el archivo de cabecera stdio.h dentro del código fuente para poder utilizar las funciones que están declaradas. nota: el compilador diferencia las mayúsculas entre las minúsculas. #include <stdio.h> int main(void) { int ch; while ((ch = getchar()) != EOF) putchar(ch); putchar('\n'); return 0; } El programa lee todas las entradas desde la entrada estándar y las muestra en la salida estándar, línea a línea. Funciones miembro Las funciones declaradas en stdio.h pueden clasificarse en dos categorías: Funciones de manipulación de ficheros y funciones de manipulación de entradas y salidas. Nombre Descripción Funciones de manipulación de ficheros fclose cierra un fichero a través de su puntero fopen, freopen, fdopen abre un fichero para lectura, para escritura/reescritura o para adición remove elimina un fichero rename cambia al fichero de nombre rewind La función rewind coloca el indicador de posición de fichero para el stream apuntado por stream al comienzo del fichero. tmpfile crea y abre un fichero temporal que es borrado cuando cerramos con la función fclose() 52
Algoritmo y Estructura de Datos I Funciones de manipulación de entradas y salidas clearerr Despeja los indicadores de final de fichero y de posición de fichero para el stream apuntado por stream al comienzo del fichero. feof comprueba el indicador de final de fichero ferror comprueba el indicador de errores fflush Si stream apunta a un stream de salida o de actualización cuya operación más reciente no era de entrada, la función fflush envía cualquier dato aún sin escribir al entorno local o a ser escrito en el fichero; si no, entonces el comportamiento no está definido. Si stream es un puntero nulo, la función fflush realiza el despeje para todos los streams cuyo comportamiento está descrito anteriormente. fgetpos devuelve la posición actual del fichero fgetc devuelve un carácter de un fichero fgets consigue una cadena de caracteres de un fichero fputc escribe un carácter en un fichero fputs escribe una cadena de caracteres en un fichero ftell devuelve la posición actual del fichero como número de bytes fseek sitúa el puntero de un fichero en una posición aleatoria fsetpos cambia la posición actual de un fichero fread lee diferentes tamaños de datos de un fichero fwrite envía, desde el array apuntado por puntero, hasta nmemb de elementos cuyo tamaño es especificado por tamanyo. El indicador de posición de ficheros es avanzado por el número de caracteres escritos correctamente. Si existe un error, el valor resultante del indicador de posición de ficheros es indeterminado. getc devuelve un carácter desde un fichero getchar igual que getc gets lee caracteres de entrada hasta que encuentra un salto de línea, y los almacena en un único argumento. printf, fprintf, sprintf snprintf usados para imprimir salidas de datos vprintf también utilizado para imprimir salidas 53
Algoritmo y Estructura de Datos I perror escribe un mensaje de error a stderr putc devuelve un carácter de un fichero putchar, fputchar igual que putc(stdout) scanf, fscanf, sscanf utilizado para introducir entradas. vfscanf, vscanf, vsscanf también utilizado para introducir entradas. setbuf Esta función es equivalente a la función setvbuf pasando los valores _IOFBF para modo y BUFSIZ para tamaño, o (si acumulador es un puntero nulo), con el valor _IONBF para modo. setvbuf sólo puede ser usada después de que el stream apuntado por stream ha sido asociado con un fichero abierto y antes de otra operación cualquiera es llevada acabo al stream. El argumento modo determina cómo stream será almacenado según lo siguiente: _IOFBF ocasiona la entrada/salida a ser completamente almacenado; _IOLBF ocasiona la entrada/salida a almacenar por líneas; _IONBF ocasiona la entrada/salida a no ser almacenado. Si acumulador no es un puntero nulo, el array al que es apuntado puede ser usado en vez de la acumulación adjudicada por la función setvbuf. El argumento tamanyo específica el tamaño del array. tmpnam Genera una cadena de caracteres que es un nombre válido para ficheros y que no es igual al nombre de un fichero existente. La función tmpnam genera una cadena diferente cada vez que es llamada, hasta un máximo de TMP_MAX veces. Si la función es llamada más veces que TMP_MAX,
entonces el comportamiento de la función está definido según la implementación del compilador. ungetc puts imprime una de cadena de caracteres Funciones de Entrada/Salida Las funciones de entrada/salida permiten al programa comunicarse con el exterior. Son utilizadas para sacar determinadas informaciones por la pantalla y capturar valores por el teclado. Son estándar de la propia librería de C por lo que no hay necesidad de definirlas de nuevo. 54
Algoritmo y Estructura de Datos I Función printf() Lee datos del programa (variables, resultados de operaciones, frases, mensajes, etc.) y los envía a la pantalla. El formato es el siguiente: printf(“Cadena de control”, variables, operaciones, ...); La cadena de control se usa para escribir mensajes, identificar el tipo de dato que se va a mostrar, indicar controles tales como: salto de línea, salto de página, etc. Los identificadores empleados son los siguientes: Un número colocado entre el % y el orden de formato, actúa como especificador mínimo de ancho de campo. Este especificador completa la salida con blancos o ceros para asegurar que al menos es la longitud mínima. Si la cadena o el número a representar es mayor que el campo mínimo, el campo se amplía para imprimir la cadena o el número completo. Ejemplos: %5d ajuste a la derecha, rellena con espacios %05d juste a la derecha, rellena con ceros %10.4f ajuste a la derecha, rellena con espacios y cuatro decimales %‐10.2f ajuste a la izquierda, rellena con espacios y dos decimales Caracteres de control son: Control Efecto en pantalla \n cambia de línea \r retorno de carro \t tabulador \b retroceso del cursor una posición \f cambio de página 55
Algoritmo y Estructura de Datos I \\ \’ \” barra atrás (\) apóstrofe (‘) comillas (“) Función scanf() Esta función, lee datos del teclado y los entrega al programa. El formato es el siguiente: scanf(“Cadena de control”, variable, variable, ...); La cadena de control se usa para identificar el tipo de dato que se va a introducir o capturar. Los identificadores empleados son los mismos que los empleados en la función printf(). La variable o variables que se van a introducir tendrán que ir acompañadas delante del nombre por el signo (&). Si el dato que se va a introducir es una tira de caracteres tipo char[ ], no es necesario el signo. Ejemplo: /* Programa de empleo de printf() y scanf() */ main() { int edad; char nombre[20]; printf(“Introduce nombre: \n“); scanf(“%s”, nombre); printf(“Introduce edad: \n”); scanf(“%d”,&edad); printf(“Tu nombre es %s y tienes %d años. \n”, nombre, edad); } Librería conio.h Las funciones de conio (CONsole Input Output) permiten, como las de Ncurses, cambiar el color del texto y del fondo, mostrar caracteres en cualquier posición de la consola, leer datos de entrada sin necesidad de pulsar intro, y un montón de cosas más. Eso sí, es bastante más restrictiva que Ncurses en otros aspectos, como la definición y manipulación de ventanas. Conio es una librería no estándar. Estaba disponible en la mayor parte de los compiladores de C para entornos MS‐DOS y Windows 3.x, pero había diferencias sustanciales entre unas implementaciones y otras, precisamente debido a que la librería no es estándar. 56
Algoritmo y Estructura de Datos I En lenguaje C esta librería contiene los prototipos de las funciones, macros, y constantes para preparar y manipular la consola en modo texto en el entorno de MS‐DOS. Lee un solo carácter directamente desde el teclado, sin mostrar tal carácter en pantalla. La función getch retorna el carácter leído desde el teclado. Ejemplo: #include <conio.h> int main() { cprintf( "Pulsa una tecla: " ); cprintf( "\'%c\'\r\n", getch() ); getch(); return 0; } Funciones importantes para la librería conio A continuación se resumen las funciones más relevantes de la librería conio. Puede encontrar una referencia completa en http://c.conclase.net/Borland. gotoxy (columna, fila) Sitúa el cursor en la columna y fila especificada. Por ejemplo, esta instrucción: gotoxy (5, 2);…sitúa el cursor en la fila 2, columna 5 de la pantalla. La siguiente instrucción de escritura en consola comenzará a escribir a partir de esas coordenadas. cprintf() y cscanf() Son las equivalentes a printf() y scanf(). Su sintaxis es la misma, y es recomendable usarlas en lugar de las funciones estándar para evitar funcionamientos extraños. textcolor(color) Cambia el color del texto. Los colores predefinidos son: BLACK, BLUE, RED, GREEN, CYAN, MAGENTA, BROWN, DARKGRAY. Además, existen las variedades “claras” de estos colores: LIGHTBLUE, LIGHTRED, LIGHTGREEN, etc. Así, si ejecutamos: textcolor (LIGHTRED);…el texto que se escriba a continuación aparecerá el color rojo intenso. 57
Algoritmo y Estructura de Datos I textbackground (color) Establece el color del fondo del texto. Los colores predefinidos son los mismos que para textcolor(). Así, este código: textbackground (BLUE);…hace que el texto que se escriba a continuación aparezca con el fondo en color azul oscuro. getch () Lee un carácter desde el teclado, sin mostrar el eco y sin necesidad de pulsar Return. Devuelve el código ASCII del carácter tecleado. Ahí va un ejemplo: char c; c = getch();clrscr () Borra la pantalla. No necesita argumentos. 58
Algoritmo y Estructura de Datos I CAPÍTULO IV Estructuras de Control Sentencias de Control del Programa 4.1 Tipos de Estructuras Básicas Las sentencias de control de los programas especifican el orden en que se han de realizar las operaciones. Existen tres formas básicas de flujo en los programas. • Estructuras secuenciales: se componen de una serie de sentencias que se ejecutan unas tras otras en el orden escrito en el programa. Para estas estructuras no se necesita ninguna sentencia de control del flujo del programa. • Estructuras condicionales: dentro del flujo del programa se toman decisiones para realizar unas acciones u otras dependiendo de que se cumplan una serie de condiciones. • Estructuras repetitivas: repetición de una serie de sentencias mientras no se cumpla una determinada condición. También denominadas bucles. - Asignación
Secuenciales
- Entrada
- Salida
- Simples
Estructuras Condicionales
Algoritmicas
- Múltiples
- Hacer para
- Hacer mientras
- Repetir hasta
Cíclicas
4.2 Estructura Secuencial La estructura secuencial es aquella en la que una acción (instrucción) sigue a otra en secuencia. Las tareas se suceden de tal modo que la salida de una es la entrada de la siguiente y así sucesivamente hasta el fin del proceso. Una estructura secuencial se representa de la siguiente forma: 59
Algoritmo y Estructura de Datos I Inicio Accion1 Accion2 . . AccionN Fin Asignación: La asignación consiste, en el paso de valores o resultados a una zona de la memoria. Dicha zona será reconocida con el nombre de la variable que recibe el valor. La asignación se puede clasificar de la siguiente forma: 9 Simples: Consiste en pasar un valor constate a una variable (a=15) 9 Contador: Consiste en usarla como un verificador del número de veces que se realiza un proceso (a=a+1) 9 Acumulador: Consiste en usarla como un sumador en un proceso (a=a+b) 9 De trabajo: Donde puede recibir el resultado de una operación matemática que involucre muchas variables (a=c+b*2/4). Lectura: La lectura consiste en recibir desde un dispositivo de entrada (p.ej. el teclado) un valor. Esta operación se representa en un pseudocodigo como sigue: 9 Leer a, b 9 Donde “a” y “b” son las variables que recibirán los valores Escritura: Consiste en mandar por un dispositivo de salida (p.ej. monitor o impresora) un resultado o mensaje. Este proceso se representa en un pseudocodigo como sigue: 9 Escribe “El resultado es:”, R 9 Donde “El resultado es:” es un mensaje que se desea aparezca y R es una variable que contiene un valor. 4.3 Problemas Secuenciales P1: Suponga que un individuo desea invertir su capital en un banco y desea saber cuánto dinero ganara después de un mes si el banco paga a razón de 2% mensual. Inicio Leer cap_inv gan = cap_inv * 0.02 Imprimir gan Fin 60
Algoritmo y Estructura de Datos I P2: Un vendedor recibe un sueldo base más un 10% extra por comisión de sus ventas, el vendedor desea saber cuánto dinero obtendrá por concepto de comisiones por las tres ventas que realiza en el mes y el total que recibirá en el mes tomando en cuenta su sueldo base y comisiones. Inicio Leer sb, v1, v2, v3 tot_vta = v1 + v2 + v3 com = tot_vta * 0.10 tpag = sb + com Figura 1. Lenguaje C
Imprimir tpag, com Fin P3: Una tienda ofrece un descuento del 15% sobre el total de la compra y un cliente desea saber cuánto deberá pagar finalmente por su compra. Inicio Leer tc d = tc * 0.15 tp = tc ‐ d Imprimir tp Fin P4: Un alumno desea saber cuál será su calificación final en la materia de Algoritmos. Dicha calificación se compone de los siguientes porcentajes: 55% del promedio de sus tres calificaciones parciales. 30% de la calificación del examen final. 15% de la calificación de un trabajo final. Inicio Leer c1, c2, c3, ef, tf prom = (c1 + c2 + c3)/3 ppar = prom * 0.55 pef = ef * 0.30 ptf = tf * 0.15 cf = ppar + pef + ptf Imprimir cf Fin 61
Algoritmo y Estructura de Datos I P5: Un maestro desea saber qué porcentaje de hombres y que porcentaje de mujeres hay en un grupo de estudiantes. Inicio Leer nh, nm ta = nh + nm ph = nh * 100 / ta pm = nm * 100 / ta Imprimir ph, pm Fin P6: Realizar un algoritmo que calcule la edad de una persona. Inicio Leer fnac, fact edad = fact ‐ fnac Imprimir edad Fin. Problemas Propuestos Problema1: Dada un cantidad en soles, obtener la equivalencia en dólares, asumiendo que la unidad cambiaría es un dato desconocido. Problema2: Leer un numero y escribir el valor absoluto del mismo. Problema3: La presión, el volumen y la temperatura de una masa de aire se relacionan por la formula: Figura 2. Conversion monedas masa = (presión * volumen)/(0.37 * (temperatura + 460)) Problema4: Calcular el número de pulsaciones que una persona debe tener por cada 10 segundos de ejercicio, si la formula es: num. pulsaciones = (220 ‐ edad)/10 Problema5: Calcular el nuevo salario de un obrero si obtuvo un incremento del 25% sobre su salario anterior. 62
Algoritmo y Estructura de Datos I Problema6: En un hospital existen tres áreas: Ginecología, Pediatría, Traumatología. El presupuesto anual del hospital se reparte conforme a la siguiente tabla: Área Porcentaje del presupuesto Ginecología 40% Traumatología 30% Pediatría 30% Obtener la cantidad de dinero que recibirá cada área, para cualquier monto presupuestal. Problema7: El dueño de una tienda compra un artículo a un precio determinado. Obtener el precio en que lo debe vender para obtener una ganancia del 30%. Problema8: Todos los lunes, miércoles y viernes, una persona corre la misma ruta y cronometra los tiempos obtenidos. Determinar el tiempo promedio que la persona tarda en recorrer la ruta en una semana cualquiera. Figura 3. Lenguaje C Problema9: Tres personas deciden invertir su dinero para fundar una empresa. Cada una de ellas invierte una cantidad distinta. Obtener el porcentaje que cada quien invierte con respecto a la cantidad total invertida. Problema10: Un alumno desea saber cuál será su promedio general en las tres materias más difíciles que cursa y cuál será el promedio que obtendrá en cada una de ellas. Estas materias se evalúan como se muestra a continuación: La calificación de Matemáticas se obtiene de la siguiente manera: Examen 90% Promedio de tareas 10% En esta materia se pidió un total de tres tareas. La calificación de Física se obtiene de la siguiente manera: Examen 80% Promedio de tareas 20% En esta materia se pidió un total de dos tareas. 63
Algoritmo y Estructura de Datos I La calificación de Química se obtiene de la siguiente manera: Examen 85% Promedio de tareas 15% En esta materia se pidió un promedio de tres tareas. Estructuras Condicionales: Las estructuras condicionales comparan una variable contra otro(s) valor(es), para que en base al resultado de esta comparación, se siga un curso de acción dentro del programa. Cabe mencionar que la comparación se puede hacer contra otra variable o contra una constante, según se necesite. Existen dos tipos básicos, las simples y las múltiples. Simples: Las estructuras condicionales simples se les conocen como “Tomas de decisión”. Estas tomas de decisiones tienen la siguiente forma: Si <condición> entonces Acción(es) Fin‐si Dobles: Las estructuras condicionales dobles permiten elegir entre dos opciones o alternativas posibles en función del cumplimiento o no de una determinada condición. Se representa de la siguiente forma: Si <condición> entonces Acción(es) si no Acción(es) Fin‐si Sentencia if‐else. El formato es el siguiente: Formato 1: if (condición) { sentencias } 64
Figura 4. Estructuras Condicionales Algoritmo y Estructura de Datos I Formato 2: if (condición) { sentencias 1} else { sentencias 2 } Ejemplo: main() { float cm, pul, valor; char unidad; printf(“Introduce número y unidad (p=pulg. o c=cm: “); scanf(“%f %c”,&valor, &unidad); if (unidad==’p’) { cm=valor*2.54; printf(“Las %f pulgadas son %f centímetros\n”,valor,cm); } if (unidad==’c’) { pul=valor/2.54; printf(“Los %f centímetros son %f pulgadas\n”,valor,pul); } if (unidad!=’p’ && unidad!=’c’) printf(“No está puesta correctamente la unidad\n”); } En C existe una forma abreviada de expresar la sentencia if‐else. Se denomina “expresión condicional” y emplea el operador condicional? : . El formato es el siguiente: expresión 1 ? expresión 2 : expresión 3 El valor de la expresión total es igual al valor de la expresión 2, si expresión 1 es cierta, mientras que si es falsa toma el valor de la expresión 3. Sentencia switch‐case‐default. El formato es el siguiente: 65
Algoritmo y Estructura de Datos I switch (variable) { case etiq 1: sentencia 1 case etiq 2: sentencia 2 .................................... default: sentencia 3 } Ejemplo: main() { float cm, pul, valor; char unidad; printf(“Introduce número y unidad (p=pulg. o c=cm: “); scanf(“%f %c”,&valor, &unidad); switch(unidad) { case ‘p’: cm=valor*2.54; pul=valor; break; case ‘c’: pul=valor/2.54; cm=valor; break; default: printf(“No está puesta correctamente la unidad\n”); exit(); } printf(“\nLas %f pulgadas son %f centímetros\n”, pul, cm); } Problemas Condicionales Problemas Selectivos Simples Prob1: Un hombre desea saber cuánto dinero se genera por concepto de intereses sobre la cantidad que tiene en inversión en el banco. El decidirá reinvertir los intereses siempre y cuando estos excedan a $7000, y en ese caso desea saber cuánto dinero tendrá finalmente en su cuenta. 66
Algoritmo y Estructura de Datos I Inicio Leer p_int, cap int = cap * p_int si int > 7000 entonces capf = cap + int fin‐si Imprimir capf fin Prob2: Determinar si un alumno aprueba a reprueba un curso, sabiendo que aprobara si su promedio de tres calificaciones es mayor o igual a 70; reprueba en caso contrario. Inicio Leer calif1, calif2, calif3 prom = (calif1 + calif2 + calif3)/3 Si prom >= 70 entonces Imprimir “alumno aprobado” si no Imprimir “alumno reprobado” Fin‐si Fin Prob3: En un almacén se hace un 20% de descuento a los clientes cuya compra supere los $1000 ¿Cuál será la cantidad que pagara una persona por su compra? Inicio Leer compra Si compra > 1000 entonces desc = compra * 0.20 si no desc = 0 fin‐si tot_pag = compra ‐ desc imprimir tot_pag fin. 67
Figura 5. Ejercicios condicionales Algoritmo y Estructura de Datos I Problemas Selectivos Dobles Prob4: Un obrero necesita calcular su salario semanal, el cual se obtiene de la siguiente manera: 9 Si trabaja 40 horas o menos se le paga $16 por hora 9 Si trabaja más de 40 horas se le paga $16 por cada una de las primeras 40 horas y $20 por cada hora extra. Inicio Leer ht Si ht > 40 entonces he = ht ‐ 40 ss = he * 20 + 40 * 16 si no ss = ht * 16 Fin‐si Imprimir ss Fin Prob5: Un hombre desea saber cuánto dinero se genera por concepto de intereses sobre la cantidad que tiene en inversión en el banco. El decidirá reinvertir los intereses siempre y cuando estos excedan a $7000, y en ese caso desea saber cuánto dinero tendrá finalmente en su cuenta. Inicio Leer p_int, cap int = cap * p_int si int > 7000 entonces capf = cap + int fin‐si Imprimir capf fin Prob6: Que lea dos números y los imprima en forma ascendente Inicio Leer num1, num2 Si num1 < num2 entonces Imprimir num1, num2 si no Imprimir num2, num1 fin‐si fin 68
Algoritmo y Estructura de Datos I Prob7: Una persona enferma, que pesa 70 kg, se encuentra en reposo y desea saber cuántas calorías consume su cuerpo durante todo el tiempo que realice una misma actividad. Las actividades que tiene permitido realizar son únicamente dormir o estar sentado en reposo. Los datos que tiene son que estando dormido consume 1.08 calorías por minuto y estando sentado en reposo consume 1.66 calorías por minuto. Inicio Leer act$, tiemp Si act$ = “dormido” entonces Figura 6. Condicionales dobles cg = 1.08 * tiemp si no cg = 1.66 * tiemp fin‐si Imprimir cg Fin Prob8: Hacer un algoritmo que imprima el nombre de un articulo, clave, precio original y su precio con descuento. El descuento lo hace en base a la clave, si la clave es 01 el descuento es del 10% y si la clave es 02 el descuento en del 20% (solo existen dos claves). Inicio Leer nomb, cve, prec_orig Si cve = 01 entonces prec_desc = prec_orig ‐ prec_orig * 0.10 si no prec_desc = prec_orig ‐ prec_orig * 0.20 fin‐si Imprimir nomb, cve, prec_orig, prec_desc fin Prob9: Hacer un algoritmo que calcule el total a pagar por la compra de camisas. Si se compran tres camisas o mas se aplica un descuento del 20% sobre el total de la compra y si son menos de tres camisas un descuento del 10% 69
Algoritmo y Estructura de Datos I Inicio Leer num_camisas, prec tot_comp = num_camisas * prec Si num_camisas > = 3 entonces tot_pag = tot_comp ‐ tot_comp * 0.20 si no tot_pag = tot_comp ‐ tot_comp * 0.10 fin‐si Imprimir tot_pag fin Prob10: Una empresa quiere hacer una compra de varias piezas de la misma clase a una fábrica de refacciones. La empresa, dependiendo del monto total de la compra, decidirá qué hacer para pagar al fabricante. 9 Si el monto total de la compra excede de $500 000 la empresa tendrá la capacidad de invertir de su propio dinero un 55% del monto de la compra, pedir prestado al banco un 30% y el resto lo pagara solicitando un crédito al fabricante. 9 Si el monto total de la compra no excede de $500 000 la empresa tendrá capacidad de invertir de su propio dinero un 70% y el restante 30% lo pagara solicitando crédito al fabricante. El fabricante cobra por concepto de intereses un 20% sobre la cantidad que se le pague a crédito. Inicio Leer costopza, numpza totcomp = costopza * numpza Si totcomp > 500 000 entonces cantinv = totcomp * 0.55 préstamo = totcomp * 0.30 crédito = totcomp * 0.15 si no cantinv = totcomp * 0.70 crédito = totcomp * 0.30 préstamo = 0 fin‐si int = crédito * 0.20 Imprimir cantinv, préstamo, crédito, int Fin 70
Algoritmo y Estructura de Datos I Problemas Propuestos 1. Calcular el total que una persona debe pagar en una llantera, si el precio de cada llanta es de $800 si se compran menos de 5 llantas y de $700 si se compran 5 o más. 2. En un supermercado se hace una promoción, mediante la cual el cliente obtiene un descuento dependiendo de un número que se escoge al azar. Si el numero escogido es menor que 74 el descuento es del 15% sobre el total de la compra, si es mayor o igual a 74 el descuento es del 20%. Obtener cuánto dinero se le descuenta. 3. Calcular el número de pulsaciones que debe tener una persona por cada 10 segundos de ejercicio aeróbico; la formula que se aplica cuando el sexo es femenino es: a. num. pulsaciones = (220 ‐ edad)/10 y si el sexo es masculino: b. num. pulsaciones = (210 ‐ edad)/10 4. Una compañía de seguros está abriendo un depto. de finanzas y estableció un programa para captar clientes, que consiste en lo siguiente: Si el monto por el que se efectúa la fianza es menor que $50 000 la cuota a pagar será por el 3% del monto, y si el monto es mayor que $50 000 la cuota a pagar será el 2% del monto. La afianzadora desea determinar cuál será la cuota que debe pagar un cliente. 5. En una escuela la colegiatura de los alumnos se determina según el número de materias que cursan. El costo de todas las materias es el mismo. Se ha establecido un programa para estimular a los alumnos, el cual consiste en lo siguiente: si el promedio obtenido por un alumno en el último periodo es mayor o igual que 18, se le hará un descuento del 30% sobre la colegiatura y no se le cobrara IGV; si el promedio obtenido es menor que 18 deberá pagar la colegiatura completa, la cual incluye el 18% de IGV. Obtener cuanto debe pagar un alumno. 6. Una empresa de bienes raíces ofrece casas de interés social, bajo las siguientes condiciones: Si los ingresos del comprador son menores de $8000 o más el enganche será del 15% del costo de la casa y el resto se distribuirá en pagos mensuales, a pagar en diez años. Si los ingresos del comprador son menos de $8000 o más el enganche será del 30% del costo de la casa y el resto se distribuirá en pagos mensuales a pagar en 7 años. 71
Algoritmo y Estructura de Datos I La empresa quiere obtener cuanto debe pagar un comprador por concepto de enganche y cuanto por cada pago parcial. 7. El gobierno ha establecido el programa SAR (Sistema de Ahorro para el Retiro) que consiste en que los dueños de la empresa deben obligatoriamente depositar en una cuenta bancaria un porcentaje del salario de los trabajadores; adicionalmente los trabajadores pueden solicitar a la empresa que deposite directamente una cuota fija o un porcentaje de su salario en la cuenta del SAR, la cual le será descontada de su pago. Un trabajador que ha decidido aportar a su cuenta del SAR desea saber la cantidad total de dinero que estará depositado a esa cuenta cada mes, y el pago mensual que recibirá. 8. Una persona desea iniciar un negocio, para lo cual piensa verificar cuanto dinero le prestara el banco por hipotecar su casa. Tiene una cuenta bancaria, pero no quiere disponer de ella a menos que el monto por hipotecar su casa sea muy pequeño. Si el monto de la hipoteca es menor que $1 000 000 entonces invertirá el 50% de la inversión total y un socio invertirá el otro 50%. Si el monto de la hipoteca es de $ 1 000 000 o más, entonces invertirá el monto total de la hipoteca y el resto del dinero que se necesite para cubrir la inversión total se repartirá a partes iguales entre el socio y el. 9. El gobierno del Perú desea reforestar un bosque que mide determinado número de hectáreas. Si la superficie del terreno excede a 1 millón de metros cuadrados, entonces decidirá sembrar de la siguiente manera: Porcentaje de la superficie del bosque Tipo de árbol a. 70% pino b. 20% oyamel c. 10% cedro Si la superficie del terreno es menor o igual a un millón de metros cuadrados, entonces decidirá sembrar de la siguiente manera: Porcentaje de la superficie del bosque Tipo de árbol d. 50% pino e. 30% oyamel f. 20% cedro El gobierno desea saber el número de pinos, oyameles y cedros que tendrá que sembrar en el bosque, si se sabe que en 10 metros cuadrados caben 8 pinos, en 15 72
Algoritmo y Estructura de Datos I metros cuadrados caben 15 oyameles y en 18 metros cuadrados caben 10 cedros. También se sabe que una hectárea equivale a 10 mil metros cuadrados. 10. Una fábrica ha sido sometida a un programa de control de contaminación para lo cual se efectúa una revisión de los puntos IMECA generados por la fábrica. El programa de control de contaminación consiste en medir los puntos IMECA que emite la fabrica en cinco días de una semana y si el promedio es superior a los 170 puntos entonces tendrá la sanción de parar su producción por una semana y una multa del 50% de las ganancias diarias cuando no se detiene la producción. Si el promedio obtenido de puntos IMECA es de 170 o menor entonces no tendrá ni sanción ni multa. El dueño de la fábrica desea saber cuánto dinero perderá después de ser sometido a la revisión. 11. Una persona se encuentra con un problema de comprar un automóvil o un terreno, los cuales cuestan exactamente lo mismo. Sabe que mientras el automóvil se devalúa, con el terreno sucede lo contrario. Esta persona comprara el automóvil si al cabo de tres años la devaluación de este no es mayor que la mitad del incremento del valor del terreno. Ayúdale a esta persona a determinar si debe o no comprar el automóvil. Problemas Selectivos Compuestos PP1: Leer 2 números; si son iguales que los multiplique, si el primero es mayor que el segundo que los reste y si no que los sume. Inicio Leer num1, num2 si num1 = num2 entonces resul = num1 * num2 si no si num1 > num2 entonces resul = num1 ‐ num2 si no resul = num1 + num2 fin‐si fin‐si fin 73
Algoritmo y Estructura de Datos I PP2: Leer tres números diferentes e imprimir el número mayor de los tres. Inicio Leer num1, num2, num3 Si (num1 > num2) and (num1 > num3) entonces mayor = num1 si no Si (num2 > num1) and (num2 > num3) entonces mayor = num2 si no mayor = num3 fin‐si fin‐si Imprimir mayor fin PP3: Determinar la cantidad de dinero que recibirá un trabajador por concepto de las horas extras trabajadas en una empresa, sabiendo que cuando las horas de trabajo exceden de 40, el resto se consideran horas extras y que estas se pagan al doble de una hora normal cuando no exceden de 8; si las horas extras exceden de 8 se pagan las primeras 8 al doble de lo que se pagan las horas normales y el resto al triple. Inicio Leer ht, pph Si ht < = 40 entonces tp = ht * pph si no he = ht ‐ 40 Si he < = 8 entonces pe = he * pph * 2 si no pd = 8 * pph * 2 pt = (he ‐ 8) * pph * 3 pe = pd + pt fin‐si tp = 40 * pph + pe fin‐si Imprimir tp fin 74
Algoritmo y Estructura de Datos I PP4: Calcular la utilidad que un trabajador recibe en el reparto anual de utilidades si este se le asigna como un porcentaje de su salario mensual que depende de su antigüedad en la empresa de acuerdo con la siguiente tabla: Tiempo Utilidad Menos de 1 año 5 % del salario 1 año o más y menos de 2 años 7% del salario 2 años o más y menos de 5 años 10% del salario 5 años o más y menos de 10 años 15% del salario 10 años o más 20% del salario Inicio Leer sm, antig Si antig < 1 entonces util = sm * 0.05 si no Si (antig > = 1) and (antig < 2) entonces util = sm * 0.07 si no Si (antig > = 2) and (antig < 5) entonces util = sm * 0.10 si no Si (antig > = 5) and (antig < 10) entonces util = sm * 0.15 si no util = sm * 0.20 fin‐si fin‐si fin‐si fin‐si Imprimir util fin PP5: En una tienda de descuento se efectúa una promoción en la cual se hace un descuento sobre el valor de la compra total según el color de la bolita que el cliente saque al pagar en caja. Si la bolita es de color blanco no se le hará descuento alguno, si es verde se le hará un 10% de descuento, si es amarilla un 25%, si es azul un 50% y si es roja un 100%. Determinar la cantidad final que el cliente deberá pagar por su compra. se sabe que solo hay bolitas de los colores mencionados. 75
Algoritmo y Estructura de Datos I Inicio leer tc, b$ si b$ = ‘blanca’ entonces d=0 si no si b$ = ‘verde’ entonces d=tc*0.10 si no si b$ = ‘amarilla’ entonces d=tc*0.25 si no si b$ = ‘azul’ entonces d=tc*0.50 si no d=tc fin‐si fin‐si fin‐si fin‐si fin PP6: El IMSS requiere clasificar a las personas que se jubilaran en el año de 1997. Existen tres tipos de jubilaciones: por edad, por antigüedad joven y por antigüedad adulta. Las personas adscritas a la jubilación por edad deben tener 60 años o más y una antigüedad en su empleo de menos de 25 años. Las personas adscritas a la jubilación por antigüedad joven deben tener menos de 60 años y una antigüedad en su empleo de 25 años o más. Las personas adscritas a la jubilación por antigüedad adulta deben tener 60 años o más y una antigüedad en su empleo de 25 años o más. Determinar en qué tipo de jubilación, quedara adscrita una persona. Inicio leer edad,ant si edad >= 60 and ant < 25 entonces imprimir “la jubilación es por edad” si no si edad >= 60 and ant > 25 entonces imprimir “la jubilación es por edad adulta” si no si edad < 60 and ant > 25 entonces imprimir “la jubilación es por antigüedad joven” 76
Algoritmo y Estructura de Datos I si no imprimir “no tiene por que jubilarse” fin‐si fin‐si fin‐si fin Problemas Propuestos Prob‐1: En una fábrica de computadoras se planea ofrecer a los clientes un descuento que dependerá del número de computadoras que compre. Si las computadoras son menos de cinco se les dará un 10% de descuento sobre el total de la compra; si el número de computadoras es mayor o igual a cinco pero menos de diez se le otorga un 20% de descuento; y si son 10 o más se les da un 40% de descuento. El precio de cada computadora es de $11,000 Prob‐2: En una llantera se ha establecido una promoción de las llantas marca “Ponchadas”, dicha promoción consiste en lo siguiente: 9 Si se compran menos de cinco llantas el precio es de $300 cada una, de $250 si se compran de cinco a 10 y de $200 si se compran más de 10. 9 Obtener la cantidad de dinero que una persona tiene que pagar por cada una de las llantas que compra y la que tiene que pagar por el total de la compra. Prob‐3: En un juego de preguntas a las que se responde “Si” o “No” gana quien responda correctamente las tres preguntas. Si se responde mal a cualquiera de ellas ya no se pregunta la siguiente y termina el juego. Las preguntas son: 1. Colon descubrió América? 2. La independencia de Perú fue en el año 1866? 3. The Doors fue un grupo de rock Americano? Prob‐4: Un proveedor de estéreos ofrece un descuento del 10% sobre el precio sin IGV, de algún aparato si este cuesta $2000 o más. Además, independientemente de esto, ofrece un 5% de descuento si la marca es “PONY”. Determinar cuánto pagara, con IGV incluido, un cliente cualquiera por la compra de su artefacto. 77
Algoritmo y Estructura de Datos I Prob‐5: Una frutería ofrece las manzanas con descuento según la siguiente tabla: NUM. DE KILOS COMPRADOS % DESCUENTO 0 ‐ 2 0% 2.01 ‐ 5 10% 5.01 ‐ 10 15% 10.01 en adelante 20% Determinar cuánto pagara una persona que compre manzanas es esa frutería. Prob‐6: El dueño de una empresa desea planificar las decisiones financieras que tomara en el siguiente año. La manera de planificarlas depende de lo siguiente: Si actualmente su capital se encuentra con saldo negativo, pedirá un préstamo bancario para que su nuevo saldo sea de $10 000. Si su capital tiene actualmente un saldo positivo pedirá un préstamo bancario para tener un nuevo saldo de $20 000, pero si su capital tiene actualmente un saldo superior a los $20 000 no pedirá ningún préstamo. Posteriormente repartirá su presupuesto de la siguiente manera. $5 000 para equipo de computo $2 000 para mobiliario y el resto la mitad será para la compra de insumos y la otra para otorgar incentivos al personal. Desplegar que cantidades se destinaran para la compra de insumos e incentivos al personal y, en caso de que fuera necesario, a cuánto ascendería la cantidad que se pediría al banco. Prob‐7: Tomando como base los resultados obtenidos en un laboratorio de análisis clínicos, un medico determina si una persona tiene anemia o no, lo cual depende de su nivel de hemoglobina en la sangre, de su edad y de su sexo. Si el nivel de hemoglobina que tiene una persona es menor que el rango que le corresponde, se determina su resultado como positivo y en caso contrario como negativo. La tabla en la que el médico se basa para obtener el resultado es la siguiente: EDAD NIVEL HEMOGLOBINA 0 ‐ 1 mes 13 ‐ 26 g% > 1 y < = 6 meses 10 ‐ 18 g% > 6 y < = 12 meses 11 ‐ 15 g% > 1 y < = 5 años 11.5 ‐ 15 g% 78
Algoritmo y Estructura de Datos I > 5 y < = 10 años 12.6 ‐ 15.5 g% > 10 y < = 15 años 13 ‐ 15.5 g% mujeres > 15 años 12 ‐ 16 g% hombres > 15 años 14 ‐ 18 g% Prob‐8: Una institución educativa estableció un programa para estimular a los alumnos con buen rendimiento académico y que consiste en lo siguiente: 9 Si el promedio es de 19 o más y el alumno es de preparatoria, entonces este podrá cursar 55 unidades y se le hará un 25% de descuento. 9 Si el promedio es mayor o igual a 18 pero menor que 19 y el alumno es de preparatoria, entonces este podrá cursar 50 unidades y se le hará un 10% de descuento. 9 Si el promedio es mayor que 14 y menor que 18 y el alumno es de preparatoria, este podrá cursar 50 unidades y no tendrá ningún descuento. 9 Si el promedio es de 14 o menor, el numero de materias reprobadas es de 0 a 3 y el alumno es de preparatoria, entonces podrá cursar 45 unidades y no tendrá descuento. 9 Si el promedio es de 14 o menor, el numero de materias reprobadas es de 4 o más y el alumno es de preparatoria, entonces podrá cursar 40 unidades y no tendrá ningún descuento. 9 Si el promedio es mayor o igual a 19 y el alumno es de profesional, entonces podrá cursar 55 unidades y se le hará un 20% de descuento. 9 Si el promedio es menor de 19 y el alumno es de profesional, entonces podrá cursar 55 unidades y no tendrá descuento. Obtener el total que tendrá que pagar un alumno si la colegiatura para alumnos de profesional es de $300 por cada cinco unidades y para alumnos de preparatoria es de $180 por cada cinco unidades. Prob‐9: Que lea tres números diferentes y determine el número medio del conjunto de los tres números (el número medio es aquel número que no es ni mayor, ni menor). Estructuras Cíclicas Se llaman problemas repetitivos o cíclicos a aquellos en cuya solución es necesario utilizar un mismo conjunto de acciones que se puedan ejecutar una cantidad específica de veces. Esta cantidad puede ser fija (previamente determinada por el programador) o puede ser variable (estar en función de algún dato dentro del programa).Los ciclos se clasifican en: 79
Algoritmo y Estructura de Datos I Bucle for. El formato es el siguiente: for (inicio; condición; incremento) { sentencias } Bucle while. El formato es el siguiente: while ( condición) { sentencias } Bucle do‐while. El formato es el siguiente: do { sentencias } while (condición); Ejemplo: main() { long acum=1; int i, n; do { printf(“Introduce número positivo: “); scanf(“%d”,&n); } while(n<0); for(i=n; i>1; ‐‐i) acum*=i; printf(“\nEl factorial es %ld”, acum); } 80
Algoritmo y Estructura de Datos I Problemas (Hacer para) Ejercicio 1: Calcular el promedio de un alumno que tiene 7 calificaciones en la materia de Diseño Estructurado de Algoritmos Inicio Sum=0 Leer Nom Hacer para c = 1 a 7 Leer calif Sum = sum + calif Fin‐para prom = sum /7 Imprimir prom Fin. Ejercicio 2: Leer 10 números y obtener su cubo y su cuarta. Inicio Hacer para n = 1 a 10 Leer num cubo = num * num * num cuarta = cubo * num Imprimir cubo, cuarta Fin‐para Fin. Ejercicio 3: Leer 10 números e imprimir solamente los números positivos Inicio Hacer para n = 1 a 10 Leer num Si num > 0 entonces Imprimir num fin‐si Fin‐para Fin. 81
Algoritmo y Estructura de Datos I Ejercicio 4: Leer 20 números e imprimir cuantos son positivos, cuantos negativos y cuantos neutros. Inicio cn = 0 cp = 0 cneg = 0 Hacer para x = 1 a 20 Leer num Sin num = 0 entonces cn = cn + 1 si no Si num > 0 entonces cp = cp + 1 si no cneg = cneg + 1 Fin‐si Fin‐si Fin‐para Imprimir cn, cp, cneg Fin. Ejercicio 5: Leer 15 números negativos y convertirlos a positivos e imprimir dichos números. Inicio Hacer para x = 1 a 15 Leer num pos = num * ‐1 Imprimir num, pos Fin‐para Fin. Ejercicio 6: Suponga que se tiene un conjunto de calificaciones de un grupo de 40 alumnos. Realizar un algoritmo para calcular la calificación media y la calificación más baja de todo el grupo. 82
Algoritmo y Estructura de Datos I Inicio sum = 0 baja = 9999 Hacer para a = 1 a 40 Leer calif sum = sum + calif Si calif < baja entonces baja = calif fin‐si Fin‐para media = sum / 2 Imprimir media, baja fin Ejercicio 7: Calcular e imprimir la tabla de multiplicar de un número cualquiera. Imprimir el multiplicando, el multiplicador y el producto. Inicio Leer num Hacer para X = 1 a 10 resul = num * x Imprimir num, “ * “, X, “ = “, resul Fin‐para fin. Ejercicio 8: Simular el comportamiento de un reloj digital, imprimiendo la hora, minutos y segundos de un día desde las 0:00:00 horas hasta las 23:59:59 horas Inicio Hacer para h = 1 a 23 Hacer para m = 1 a 59 Hacer para s = 1 a 59 Imprimir h, m, s Fin‐para Fin‐para Fin‐para fin. 83
Algoritmo y Estructura de Datos I Problemas Propuestos Prop‐1: Una persona debe realizar un muestreo con 50 personas para determinar el promedio de peso de los niños, jóvenes, adultos y viejos que existen en su zona habitacional. Se determinan las categorías con base en la sig, tabla: CATEGORIA EDAD Niños 0 ‐ 12 Jóvenes 13 ‐ 29 Adultos 30 ‐ 59 Viejos 60 en adelante Prop‐2: Al cerrar un expendio de naranjas, 15 clientes que aun no han pagado recibirán un 15% de descuento si compran más de 10 kilos. Determinar cuánto pagara cada cliente y cuanto percibirá la tienda por esas compras. Prop‐3: En un centro de verificación de automóviles se desea saber el promedio de puntos contaminantes de los primeros 25 automóviles que lleguen. Asimismo se desea saber los puntos contaminantes del carro que menos contamino y del que más contamino. Prop‐4: Un entrenador le ha propuesto a un atleta recorrer una ruta de cinco kilómetros durante 10 días, para determinar si es apto para la prueba de 5 Kilómetros o debe buscar otra especialidad. Para considerarlo apto debe cumplir por lo menos una de las siguientes condiciones: 9 Que en ninguna de las pruebas haga un tiempo mayor a 16 minutos. 9 Que al menos en una de las pruebas realice un tiempo mayor a 16 minutos. 9 Que su promedio de tiempos sea menor o igual a 15 minutos. Prop‐5: Un Zoólogo pretende determinar el porcentaje de animales que hay en las siguientes tres categorías de edades: de 0 a 1 año, de más de 1 año y menos de 3 y de 3 o más años. El zoológico todavía no está seguro del animal que va a estudiar. Si se decide por elefantes solo tomara una muestra de 20 de ellos; si se decide por las jirafas, tomara 15 muestras, y si son chimpancés tomara 40. Ciclos con un Número Indeterminado de Iteraciones (Hacer‐Mientras, Repetir‐Hasta) Son aquellos en que el número de iteraciones no se conoce con exactitud, ya que esta dado en función de un dato dentro del programa. 84
Algoritmo y Estructura de Datos I Hacer‐Mientras: Esta es una estructura que repetirá un proceso durante “N” veces, donde “N” puede ser fijo o variable. Para esto, la instrucción se vale de una condición que es la que debe cumplirse para que se siga ejecutando. Cuando la condición ya no se cumple, entonces ya no se ejecuta el proceso. La forma de esta estructura es la siguiente: Figura 7. Hacer mientras Ejemplo: #include <stdio.h> int main (){ int i = 1; do{ printf("i = %i\n",i); i++; } while ( i <= 3 ); } Problemas (Hacer Mientras) Ejemplo 1: Una compañía de seguros tiene contratados a n vendedores. Cada uno hace tres ventas a la semana. Su política de pagos es que un vendedor recibe un sueldo base, y un 10% extra por comisiones de sus ventas. El gerente de su compañía desea saber cuánto dinero obtendrá en la semana cada vendedor por concepto de comisiones por las tres ventas realizadas, y cuanto tomando en cuenta su sueldo base y sus comisiones. Ejemplo 2: En una empresa se requiere calcular el salario semanal de cada uno de los “n” obreros que laboran en ella. El salario se obtiene de la siguiente forma: 85
Algoritmo y Estructura de Datos I Si el obrero trabaja 40 horas o menos se le paga $20 por hora Si trabaja más de 40 horas se le paga $20 por cada una de las primeras 40 horas y $25 por cada hora extra. Ejemplo 3: Determinar cuántos hombres y cuantas mujeres se encuentran en un grupo de n personas, suponiendo que los datos son extraídos alumno por alumno. Ejemplo 4: El Depto. de Seguridad Publica y Transito del D.F. desea saber, de los n autos que entran a la ciudad de México, cuantos entran con calcomanía de cada color. Conociendo el último dígito de la placa de cada automóvil se puede determinar el color de la calcomanía utilizando la siguiente relación: DÍGITO COLOR 1 o 2 amarilla 3 o 4 rosa 5 o 6 roja 7 o 8 verde 9 o 0 azul Ejemplo 5: Obtener el promedio de calificaciones de un grupo de n alumnos. Ejemplo 6: Una persona desea invertir su dinero en un banco, el cual le otorga un 2% de interés. ¿Cuál será la cantidad de dinero que esta persona tendrá al cabo de un año si la ganancia de cada mes es reinvertida? Ejemplo 7: Calcular el promedio de edades de hombres, mujeres y de todo un grupo de alumnos. Ejemplo 8: Encontrar el menor valor de un conjunto de n números dados. Ejemplo 9: Encontrar el mayor valor de un conjunto de n números dados. Ejemplo 10: En un supermercado un cajero captura los precios de los artículos que los clientes compran e indica a cada cliente cual es el monto de lo que deben pagar. Al final 86
Algoritmo y Estructura de Datos I del día le indica a su supervisor cuanto fue lo que cobro en total a todos los clientes que pasaron por su caja. Ejemplo 11: Cinco miembros de un club contra la obesidad desean saber cuánto han bajado o subido de peso desde la última vez que se reunieron. Para esto se debe realizar un ritual de pesaje en donde cada uno se pesa en diez básculas distintas para así tener el promedio más exacto de su peso. Si existe diferencia positiva entre este promedio de peso y el peso de la última vez que se reunieron, significa que subieron de peso. Pero si la diferencia es negativa, significa que bajaron. Lo que el problema requiere es que por cada persona se imprima un letrero que diga: “SUBIO” o “BAJO” y la cantidad de kilos que subió o bajo de peso. Ejemplo 12: Se desea obtener el promedio de “g” grupos que están en un mismo año escolar; siendo que cada grupo puede tener n alumnos que cada alumno puede llevar “m” materias y que en todas las materias se promedian tres calificaciones para obtener el promedio de la materia. Lo que se desea desplegar es el promedio de los grupos, el promedio de cada grupo y el promedio de cada alumno. Repetir‐Hasta Esta es una estructura similar en algunas características, a la anterior. Repite un proceso una cantidad de veces, pero a diferencia del Hacer‐
Mientras, el Repetir‐Hasta lo hace hasta que la condición se cumple y no mientras, como en el Hacer‐Mientras. Por otra parte, esta estructura permite realizar el proceso cuando menos una vez, ya que la condición se evalúa al final del proceso, mientras que en el Hacer‐Mientras puede ser que nunca llegue a entrar si la condición no se cumple desde un principio. La forma de esta estructura es la siguiente: Figura 8. Repetir hasta Ejemplo1: En una tienda de descuento las personas que van a pagar el importe de su compra llegan a la caja y sacan una bolita de color, que les dirá que descuento tendrán sobre el total de su compra. Determinar la cantidad que pagara cada cliente desde que la tienda abre hasta que cierra. Se sabe que si el color de la bolita es roja el cliente obtendrá un 40% de descuento; si es amarilla un 25% y si es blanca no obtendrá descuento. 87
Algoritmo y Estructura de Datos I Ejemplo 2: En un supermercado una ama de casa pone en su carrito los artículos que va tomando de los estantes. La señora quiere asegurarse de que el cajero le cobre bien lo que ella ha comprado, por lo que cada vez que toma un articulo anota su precio junto con la cantidad de artículos iguales que ha tomado y determina cuánto dinero gastara en ese artículo; a esto le suma lo que ira gastando en los demás artículos, hasta que decide que ya tomo todo lo que necesitaba. Ayúdale a esta señora a obtener el total de sus compras. Ejemplo 3: Un teatro otorga descuentos según la edad del cliente. Determinar la cantidad de dinero que el teatro deja de percibir por cada una de las categorías. Tomar en cuenta que los niños menores de 5 años no pueden entrar al teatro y que existe un precio único en los asientos. Los descuentos se hacen tomando en cuenta el siguiente cuadro: Edad Descuento Categoría 1 5 ‐ 14 35 % Categoría 2 15 ‐ 19 25 % Categoría 3 20 ‐ 45 10 % Categoría 4 46 ‐ 65 25 % Categoría 5 66 en adelante 35 % 88
Algoritmo y Estructura de Datos I CAPÍTULO V Programación Modular La modularización, es una técnica usada por los programadores para hacer sus códigos más cortos, ya que consiste en reducir un gran problema complejo, en pequeños problemitas más sencillos, concentrándose en la solución por separado, de cada uno de ellos. En C, se conocen como funciones aquellos trozos de códigos utilizados para dividir un programa con el objetivo que, cada bloque realice una tarea determinada. En las funciones juegan un papel muy importe las variables, ya que como se ha dicho estas pueden ser locales o globales. Una estrategia muy utilizada para la resolución de problemas complejos con la computadora, es como lo he venido comentando, la división del problema en otros problemas más pequeños o sub problemas. Estos sub problemas se implementan mediante módulos o subprogramas. Los subprogramas son una herramienta importante para el desarrollo de algoritmos y programas de modo que normalmente un proyecto de programación está compuesto generalmente de un programa principal y un conjunto de subprogramas con las llamadas a los mismos dentro del programa principal. Los subprogramas se clasifican en: procedimientos y funciones. 5.1 El Diseño Descendente: Subprogramas Uno de los métodos fundamentales para resolver un problema es dividirlo en problemas más pequeños, llamados sub problemas, en referencias sucesivas. Estos problemas a su vez pueden ser divididos repetidamente en problemas más pequeños hasta que los problemas más pequeños puedan ser solucionados. Esta técnica de dividir el problema principal en sub problemas se denomina frecuentemente divide y vencerás. El método de diseño se denomina diseño descendente, debido a que se comienza en la parte superior con un problema general y se diseñan soluciones específicas a sus sub problemas. El problema principal se resuelve con el programa principal (también llamado conductor del programa), y los sub problemas (módulos) mediante subprogramas: procedimientos y funciones. 89
Algoritmo y Estructura de Datos I Un subprograma realiza una tarea concreta que se describe con una serie de instrucciones. Veamos un ejemplo: Leer el radio de un círculo y calcular e imprimir su superficie y longitud. •
Análisis Especificaciones de Entrada Radio: Real Especificaciones de Salida Superficie: Real Longitud: Real •
Algoritmo 1. Leer el valor del radio 2. Calcular la Superficie 3. Calcular la Longitud 4. Visualizar los valores de la superficie y la longitud •
Refinamiento del Algoritmo 1. Leer el valor del radio 2. Calcular la superficie 1. pi <‐ 3.141592 (constante pi) 2. S <‐ pi * Radio * Radio 3. Calcular la longitud 1. pi <‐ 3.141592 2. L <‐ 2 * pi * Radio 4. Visualizar los valores de la superficie y la longitud 5.2 El Diseño Modular Los sub problemas o módulos se diseñan con subprogramas, que a su vez se clasifican en procedimientos y funciones. Los procedimientos y las funciones son unidades de programas diseñadas para ejecutar una tarea específica. Por ejemplo, los procedimientos predefinidos, printf() y scanf(), están diseñados para realizar operaciones de entrada y salida. El proceso de descomposición de un problema en módulos se conoce como modulación y a la programación relativa a ellos programación modular. Los procedimientos y funciones son similares, aunque presentan notables diferencias entre ellos: 9 Las funciones normalmente, devuelven un solo valor a la unidad de programa (programa principal u otro subprograma) que la referencia o la llama. 90
Algoritmo y Estructura de Datos I 9 Los procedimientos pueden devolver cero, uno o varios valores. En el caso de no devolver ningún valor, realizan alguna tarea tal como alguna operación de entrada/salida. A un nombre de procedimiento no se puede asignar un valor, y por consiguiente ningún tipo está asociado con un nombre de procedimiento. Una función se referencia utilizando su nombre en una instrucción (de asignación o expresión matemática), mientras que un procedimiento se referencia por una llamada o invocación al mismo. Transferencia de Información a/desde Módulos Los Parámetros Los módulos o subprogramas sirven para ejecutar tareas concretas, pero no utilizan ningún tipo de dato del resto del programa. Sin embargo, una de las características importantes y diferenciadora de los subprogramas es la posibilidad de comunicación entre el programa principal y los subprogramas (o entre los subprogramas). Esta comunicación se realiza a través de una lista de parámetros Un parámetro es un método para pasar información (valores a variables) del programa principal a un módulo o viceversa. Así pues, los módulos se clasifican en: Módulos sin parámetros (no existe comunicación entre el programa principal y los módulos o entre módulos). Módulos con parámetros (existe comunicación entre el programa principal y los módulos, y entre ellos). Un parámetro es prácticamente, una variable cuyo valor debe ser o bien proporcionado por el programa principal al módulo o ser devuelto desde el módulo hasta el programa principal. Por consiguiente hay dos tipos de parámetros: entrada y salida. Los parámetros de entrada son aquellos cuyos valores deben ser proporcionados por el programa principal, y los de salida son aquellos cuyos valores se calcularán en el subprograma o módulo y se deben devolver al programa principal para su proceso posterior. Las sentencias llamadas a subprogramas constan de dos partes: un nombre de subprograma y una lista de parámetros llamados actuales. 91
Algoritmo y Estructura de Datos I nombreSubprograma(pa1,pa2,...) En la declaración de un subprograma, cuando se incluyen parámetros, estos se denominan parámetros formales o ficticios. Ellos sirven para contener los valores de parámetros actuales cuando se llama al subprograma. Procedimiento o función nombresubprograma(pf1,pf2,...) Los parámetros actuales en la llamada al subprograma deben coincidir en número, orden y tipo con los parámetros ficticios de la declaración del subprograma. Es decir, debe existir una correspondencia entre parámetros actuales y ficticios. Parámetros Valor y Parámetros Variable Existen dos tipos de parámetros, como se indico anteriormente, que nos ayudan a transferir/recibir información de otros subprogramas, o del programa principal, a saber: parámetros de entrada (por valor) y parámetros de salida o de entrada/salida (variable). Parámetros Valor Son parámetros unidireccionales que se utilizan para proporcionar información a un subprograma, pero no pueden devolver valores, al programa llamador. Se les llama parámetros de entrada, ya que en la llamada al subprograma el valor del parámetro actual se pasa a la variable que representa a la variable actual. Este valor puede ser modificado dentro del subprograma pero el valor modificado no es devuelto al programa o subprograma llamador. Parámetros Variable Se utilizan tanto para recibir como para transmitir valores entre el subprograma y el programa llamador. Este puede actuar como parámetro de salida o de entrada/salida. Nota: En la notación de pseudocódigo representaré a estos parámetros anteponiendo la palabra var antes del identificador;). Este algoritmo ilustra la diferencia entre parámetros valor y parámetros variable, y la correspondencia entre ellos. Algoritmo Ejemplo_Parametros Variables A, B, C: enteros procedimiento imprimir (D,E,F: enteros) inicio escribir ("A =", D, "B =", E, "C =", F) fin_imprimir 92
Algoritmo y Estructura de Datos I procedimiento pasar (D,E: entero; var F: entero) inicio escribir ("Entrada al procedimiento pasar:") imprimir (D,E,F) F <‐ D * F escribir ("Salida del procedimiento pasar:") imprimir (D,E,F) fin_pasar inicio A <‐ 2 B <‐ 3 C <‐ 4 escribir ("Antes de llamar al procedimiento pasar") imprimir (A,B,C) pasar (A,B,C) escribir ("Despues del retorno del procedimiento pasar") imprimir (A,B,C) fin La salida del programa en pantalla sería la siguiente: Antes de llamar al procedimiento pasar A = 2, B = 3, C = 4 Entrada al procedimiento pasar A = 2, B = 3, C = 4 Salida del procedimiento pasar A = 2, B = 3, C = 6 Despues del retorno del procedimiento pasar A = 2, B = 3, C = 6 Variables Locales y Variables Globales Las variables utilizadas en un programa con subprogramas pueden ser de dos tipos: locales y globales. Variables Locales Una variable local es una variable que está declarada dentro de un subprograma y se dice que es local al subprograma. Una variable local solo está disponible durante el funcionamiento del subprograma, al terminar su función el subprograma y regresar al programa llamador, se pierde el valor que se encontraba guardado en la variable local. 93
Algoritmo y Estructura de Datos I Variables Globales Las variables declaradas en el programa principal se denominan variables globales. Al contrario que las variables locales cuyos valores se pueden utilizar solo dentro del subprograma en que fueron declaradas, las variables globales se pueden utilizar en todo el programa principal y en todos los subprogramas, donde se haga referencia al identificador de esta variable. Ámbito de un Identificador La mayoría de los programas tienen una estructura tipo árbol, el programa principal es la raíz y de este penden muchas ramas (procedimientos y funciones). Los subprogramas en los que un identificador puede ser utilizado se conocen como ámbito o alcance del identificador, dicho de otro modo, es en esta sección donde el identificador es válido. Reglas de Ámbito a. El ámbito de un identificador es el dominio en que está declarado. Por consiguiente un identificador declarado en un bloque P puede ser usado en el subprograma P y en todos los subprogramas llamados en el subprograma P. b. Si un identificador j declarado en el procedimiento P se redeclara en algún subprograma interno Q invocado en P, entonces el subprograma Q y todas sus invocaciones a otros subprogramas se excluyen del ámbito de j declarado en P. Procedimientos y Funciones Los procedimientos y funciones son la base principal en la programación modular, estudiaremos aquí su funcionamiento y su sintaxis. Procedimientos Un procedimiento es un subprograma que realiza una tarea específica. Puede recibir cero o más valores del programa que llama y devolver cero o más valores a dicho programa. Un procedimiento está compuesto de un grupo de sentencias a las que se asigna un nombre (identificador) y constituye una unidad de programa. La tarea determinada al procedimiento se ejecuta siempre que se encuentra el nombre del procedimiento. La declaración indica las instrucciones a ejecutar. Su sintaxis es: procedimiento nombreproc (lista de par) declaraciones locales inicio cuerpo del procedimiento (instrucciones) fin. 94
Algoritmo y Estructura de Datos I Un procedimiento es llamado en un programa o dentro de otro procedimiento directamente por su nombre en cualquiera de las dos formas: nombreproc nombreproc (lista par. actuales) Funciones Una función es un subprograma que recibe como argumentos o parámetros, datos de tipos numérico o no numérico, y devuelve un único resultado. Esta característica le diferencia esencialmente de un procedimiento. Su formato es el siguiente: funcion nombrefuncion (p1,p2,...) : tipo a devolver declaraciones locales inicio cuerpo de la función nombrefuncion <‐ valor a devolver fin Una función es llamada por medio de su nombre, en una sentencia de asignación o en una sentencia de salida. Se puede llamar a una función en cualquiera de las siguientes formas: nombrefuncion o nombrefuncion(par) idVar <‐ nombrefuncion. Un problema complejo se puede dividir en pequeños subproblemas más sencillos. Estos subproblemas se conocen como “Módulos” y su complementación en un lenguaje se llama subprograma (procedimientos y funciones). Un subprograma realiza las mismas acciones que un programa, sin embargo, un subprograma lo utiliza solamente un programa para un propósito especifico. Un subprograma recibe datos de un programa y le devuelve resultados (el programa “llama” o “invoca” al subprograma, este ejecuta una tarea específica y devuelve el “control” al programa que lo llamo). 95
Algoritmo y Estructura de Datos I Funciones Tipos de Módulos Procedimientos Función: Una función en matemáticas, es una operación que toma un o mas valores (argumentos) y devuelve un resultado (valor de la función para los argumentos dados). Por ejemplo: F(X) = X / (1+X2) Donde: F ………….. Nombre de la función X …………. Es el argumento (también conocido como parámetro formal) Definición de funciones: Una definición de función se presenta de la siguiente manera: Función nombre_funcion (p1, p2, …, pn) Inicio Bloque de instrucciones Fin Donde: Función …………… Es la palabra clave que nos indica una definición de función. Nombre_funcion …. Es el identificador con el cual se reconoce a la función en el cuerpo del algoritmo principal. P1,p2,…,pn ……... Es el grupo de parámetros que define a la función. Llamado a una función Cuando definimos una función solo le indicamos al algoritmo que esta función existe, pero una definición de función no implica la realización de las instrucciones que la constituyen. Para hacer uso de una función, el algoritmo principal la debe llamar. Por ejemplo: Función F(X) Inicio F = X /(1 + X^2) Fin Inicio Imprimir “Este es el algoritmo principal” Leer N 96
Algoritmo y Estructura de Datos I R = F(N) llamado de la función Imprimir “El resultado de la función es:”,R Fin Podemos definir una función cualquiera de la misma manera en que definimos la función main(). Basta con poner su tipo, su nombre, sus argumentos entre paréntesis y luego, entre llaves, su código: /* Inclusión de archivos */ #include <stdio.h> void holamundo(void) /*Función donde se ejecuta la lógica del programa*/ { printf("Hola Mundo\n"); /*imprime la cadena*/ return; /*sale de la función*/ } int main(void) /*Función principal del programa*/ { holamundo(); /*llamada a la función que lleva el peso*/ return 0; /*sale del programa: correcto*/ } Este código es en todo equivalente al "Hola Mundo" original, sólo que nos muestra cómo escribir y cómo utilizar una función. Y además nos muestra un principio de buena programación: meter las sentencias que "hacen el trabajo" en otras funciones específicas para sacarlas de main(), dejando en ésta tan sólo un guión general de lo que hace el programa, no las órdenes específicas. De esta manera se facilita la comprensión del programa, y por tanto el futuro trabajo de modificarlo. De la misma manera que tenemos que declarar una variable antes de utilizarla, no es indiferente el orden en que se sitúen las diferentes funciones en el fichero: las funciones deben declararse antes de ser llamadas. Igualmente vemos que, para una función void, la sentencia de control return no puede llamarse como pseudofunción, porque en dicho caso la función void (en nuestro caso holamundo()) devolvería un valor, cosa que su definición no permite. Las funciones también permiten recibir tipos de datos, así pues las funciones nos sirven para hacer de un gran problema pequeñas partes de un problema o sea dividir un gran problema en diferentes problemas más pequeños. Así que las funciones también pueden retornar un tipo de dato que hemos definido dentro de la misma. 97
Algoritmo y Estructura de Datos I Así que si definimos una función para sumar dos números seria de la siguiente manera: /* * suma.c * * Julio Calderon Bramo <[email protected]> 2009 * * para el libro "Programación en C" * adaptado del Dominio Público */ #include <stdio.h> int sumar(int numero1, int numero2); /* prototipo de la función */ int main(void) { int suma; /* definimos una variable*/ suma = sumar(5, 3); /* la variable obtiene el valor retornado de sumar * puede verse que entre los paréntesis se mandan los valores * de los números que se desean sumar en este caso 5 y 3 * pueden haberse declarados estos dos números en otras variables * int dato = 4, valor = 3; * suma = sumar(dato, valor); */ /* imprimimos la suma de los dos números */ printf("La suma es: %d ", suma); return 0; } int sumar(int numero1, int numero2) { int retsuma; /* creamos la variable a retornar*/ retsuma = numero1 + numero2; /* asignamos esa varia la suma de número 1 y 2*/ return retsuma; /* retornamos la suma de los números */ } 98
Algoritmo y Estructura de Datos I CAPÍTULO VI Recursividad 6.1 Recursividad: La recursividad es una técnica de programación importante. Se utiliza para realizar una llamada a una función desde la misma función. Como ejemplo útil se puede presentar el cálculo de números factoriales. Él factorial de 0 es, por definición, 1. Los factoriales de números mayores se calculan mediante la multiplicación de 1 * 2 * ..., incrementando el número de 1 en 1 hasta llegar al número para el que se está calculando el factorial. El siguiente párrafo muestra una función, expresada con palabras, que calcula un factorial. "Si el número es menor que cero, se rechaza. Si no es un entero, se redondea al siguiente entero. Si el número es cero, su factorial es uno. Si el número es mayor que cero, se multiplica por él factorial del número menor inmediato." Para calcular el factorial de cualquier número mayor que cero hay que calcular como mínimo el factorial de otro número. La función que se utiliza es la función en la que se encuentra en estos momentos, esta función debe llamarse a sí misma para el número menor inmediato, para poder ejecutarse en el número actual. Esto es un ejemplo de recursividad. La recursividad y la iteración (ejecución en bucle) están muy relacionadas, cualquier acción que pueda realizarse con la recursividad puede realizarse con iteración y viceversa. Normalmente, un cálculo determinado se prestará a una técnica u otra, sólo necesita elegir el enfoque más natural o con el que se sienta más cómodo. Claramente, esta técnica puede constituir un modo de meterse en problemas. Es fácil crear una función recursiva que no llegue a devolver nunca un resultado definitivo y no pueda llegar a un punto de finalización. Este tipo de recursividad hace que el sistema ejecute lo que se conoce como bucle "infinito". Para entender mejor lo que en realidad es el concepto de recursión veamos un poco lo referente a la secuencia de Fibonacci. Principalmente habría que aclarar que es un ejemplo menos familiar que el del factorial, que consiste en la secuencia de enteros. 0,1,1,2,3,5,8,13,21,34,..., 99
Algoritmo y Estructura de Datos I Cada elemento en esta secuencia es la suma de los precedentes (por ejemplo 0 + 1 = 0, 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, ...) sean fib(0) = 0, fib (1) = 1 y así sucesivamente, entonces puede definirse la secuencia de Fibonacci mediante la definición recursiva (define un objeto en términos de un caso más simple de sí mismo): fib (n) = n if n = = 0 or n = = 1 fib (n) = fib (n ‐ 2) + fib (n ‐ 1) if n >= 2 Por ejemplo, para calcular fib (6), puede aplicarse la definición de manera recursiva para obtener: Fib (6) = fib (4) + fib (5) = fib (2) + fib (3) + fib (5) = fib (0) + fib (1) + fib (3) + fib (5) = 0 + 1 fib (3) + fib (5) 1.+ fib (1) + fib (2) + fib(5) = 1.+ 1 + fib(0) + fib (1) + fib (5) = 2.+ 0 + 1 + fib(5) = 3 + fib (3) + fib (4) = 3.+ fib (1) + fib (2) + fib (4) = 3 + 1 + fib (0) + fib (1) + fib (4) = 4.+ 0 + 1 + fib (2) + fib (3) = 5 + fib (0) + fib (1) + fib (3) = 5.+ 0 + 1 + fib (1) + fib (2) = 6 + 1 + fib (0) + fib (1) = 6.+ 0 + 1 = 8 Obsérvese que la definición recursiva de los números de Fibonacci difiere de las definiciones recursivas de la función factorial y de la multiplicación. La definición recursiva de fib se refiere dos veces a sí misma. Por ejemplo, fib (6) = fib (4) + fib (5), de tal manera que al calcular fib (6), fib tiene que aplicarse de manera recursiva dos veces. Sin embargo calcular fib (5) también implica calcular fib (4), así que al aplicar la definición hay mucha 100
Algoritmo y Estructura de Datos I redundancia de cálculo. En ejemplo anterior, fib(3) se calcula tres veces por separado. Sería mucho más eficiente "recordar" el valor de fib(3) la primera vez que se calcula y volver a usarlo cada vez que se necesite. Es mucho más eficiente un método iterativo como el que sigue parar calcular fib (n). If (n < = 1) return (n); lofib = 0 ; hifib = 1 ; for (i = 2; i < = n; i ++) { x = lofib ; lofib = hifib ; hifib = x + lofib ; } /* fin del for*/ return (hifib) ; Hasta el momento, las únicas funciones que hemos estudiado han sido llamadas desde otra función; pero es posible crear funciones que puedan llamarse a sí mismas, estas son llamadas: funciones recursivas. Una función puede ser recursiva tanto de forma directa (si es llamada a sí misma) o de forma indirecta (si llama a una función que luego la llama). Existen algunos problemas que pueden ser resueltos de forma más eficiente (o su resolución puede ser más naturalmente pensada) utilizando funciones recursivas. Una función recursiva puede dar origen a un típico problema en programación, la recursión infinita, que es cuando una función se llama a sí misma infinitas veces. Esto detiene el normal funcionamiento de un programa. 101
Algoritmo y Estructura de Datos I Para que esto no suceda una función recursiva debe ser muy bien pensada. Principalmente una función recursiva debe saber resolver el caso más simple, llamado caso base. Si la función es llamada con el caso base, inmediatamente retorna el resultado (no necesita volver a llamarse a sí misma para poder resolverlo). Compárese el numero de adiciones (sin incluir los incrementos de la variable índice, i) que se ejecutan para calcular fib (6) mediante este algoritmo al usar la definición recursiva. En el caso de la función factorial, tienen que ejecutarse el mismo número de multiplicaciones para calcular n! Mediante ambos métodos: recursivo e iterativo. Lo mismo ocurre con el número de sumas en los dos métodos al calcular la multiplicación. Sin embargo, en el caso de los números de Fibonacci, el método recursivo es mucho más costoso que el iterativo. Para definir una función en forma recursiva es necesario especificar: Caso(s) base: Donde la recursividad se detiene Paso de recursión: Como se define un elemento distinto de la base, en términos de elementos anteriores. Usualmente los lenguajes de programación permiten definir funciones de manera recursiva. El lenguaje C es uno de ellos. La definición recursiva para el factorial sería: int factorial(int n) { if ((n == 0) || (n == 1)) return(1); else return(n*factorial(n‐1)); } Normalmente las definiciones recursivas pueden expresarse en forma no recursiva. Sin embargo, dependiendo del caso, el resultado puede ser más confuso. Por ejemplo, una función en C que calcula el factorial en forma iterativa sería: int factorial(int n) { int i, fact = 1; for (i=2; i<=n; i++) fact = fact * i; return(fact); } Sin embargo, los algoritmos iterativos tienen una ventaja en cuanto al uso de memoria, si se comparan con los iterativos. La recursividad requiere que se guarde el estado de la ejecución antes de cada llamado recursivo, implicando un gasto considerable de memoria. 102
Algoritmo y Estructura de Datos I Es probable que, por esta razón, las versiones recursivas tengan mayores limitaciones al ejecutarse en un computador. La aplicación de las definiciones recursivas puede ampliarse a una amplia gama de problemas, en los que la solución más natural puede ser la que se expresa de esta forma. Ejemplo: /*************************************************************************
** * Ejemplo: Obtención del máximo en un vector de números (recursivamente). **************************************************************************
*/ /* Definición del tamaño máximo del vector */ #define TAMANO_VECTOR 100 /*************************************************************************
** * Función recursiva que obtiene el máximo en un vector de números enteros. * Recibe como argumento el vector que contiene los números y el número * de posiciones del vector que están siendo utilizadas. La función * retorna el valor del máximo elemento dentro del vector. **************************************************************************
*/ int Maximo(int vector[], int n) { int max, maxResto; if (n == 1) /* Caso base */ max = vector[0]; else { maxResto = Maximo(vector+1, n‐1); /* Maximo del resto del vector */ if (vector[0] > maxResto) max = vector[0]; else max = maxResto; } return(max); } 103
Algoritmo y Estructura de Datos I /*************************************************************************
** * Programa de prueba: Lee los valores del vector y despliega el maximo **************************************************************************
*/ main() { int i; int n=0; int vec[TAMANO_VECTOR]; /* Garantiza que el usuario ingresa un numero de elementos > 0 */ while (n < 1) { printf("Ingrese el numero de elementos: "); scanf("%d", &n); } /* Lee los elementos del vector */ for (i=0; i<n; i++) { printf("\tElemento[%d]: ", i); scanf("%d", &vec[i]); } /* Calcula el maximo a la vez que despliega el resultado */ printf("\nMaximo: %d\n", Maximo(vec, n)); } /*************************************************************************
** * Ejemplo: Calculo iterativo del n‐esimo termino de fibonacci * Por definición: * Fibonacci(0) = 0 * Fibonacci(1) = 1 * Fibonacci(n) = Fibonacci(n ‐ 1) + Fibonacci(n ‐ 2) **************************************************************************
*/ /*************************************************************************
** * Función que calcula iterativamente el n‐esimo termino de fibonacci 104
Algoritmo y Estructura de Datos I **************************************************************************
*/ double Fibonacci(int n) { int i; double Fibi, Fibn1, Fibn2; switch (n) { case 0 : return 0; case 1 : return 1; default : Fibn2 = 0; /* Fibonacci(n ‐ 2) */ Fibn1 = 1; /* Fibonacci(n ‐ 1) */ for (i = 2; i <= n; i++) { Fibi = Fibn1 + Fibn2; Fibn2 = Fibn1; Fibn1 = Fibi; } return Fibi; } } /*************************************************************************
** * Programa que calcula, de forma iterativa, el termino n‐esimo de la * sucesión de fibonacci, para un valor n dado por el usuario. **************************************************************************
*/ main() { int n; /* Se solicita al usuario el valor de n */ printf("Ingrese el valor de n: "); scanf("%d", &n); /* scanf requiere puntero: & */ /* Imprime el fibonacci de n */ printf("El termino %d de Fibonacci es: %.0lf\n", n, Fibonacci(n)); } 105
Algoritmo y Estructura de Datos I /*************************************************************************
** * Ejemplo: Obtención del maximo en un vector de números (recursivamente). **************************************************************************
*/ /* Definición del tamaño máximo del vector */ #define TAMANO_VECTOR 100 /*************************************************************************
** * Función recursiva que obtiene el maximo en un vector de números enteros. * Recibe como argumento el vector que contiene los números y el número * de posiciones del vector que estan siendo utilizadas. La función * retorna el valor del maximo elemento dentro del vector. **************************************************************************
*/ int Maximo(int vector[], int n) { int max, maxResto; if (n == 1) /* Caso base */ max = vector[0]; else { maxResto = Maximo(vector+1, n‐1); /* Maximo del resto del vector */ if (vector[0] > maxResto) max = vector[0]; else max = maxResto; } return(max); } /*************************************************************************
** * Programa de prueba: Lee los valores del vector y despliega el maximo **************************************************************************
*/ main() { 106
Algoritmo y Estructura de Datos I int i; int n=0; int vec[TAMANO_VECTOR]; /* Garantiza que el usuario ingresa un numero de elementos > 0 */ while (n < 1) { printf("Ingrese el numero de elementos: "); scanf("%d", &n); } /* Lee los elementos del vector */ for (i=0; i<n; i++) { printf("\tElemento[%d]: ", i); scanf("%d", &vec[i]); } /* Calcula el maximo a la vez que despliega el resultado */ printf("\nMaximo: %d\n", Maximo(vec, n)); } 6.2 Prototipos de funciones Antes de usar una función C debe tener conocimiento acerca del tipo de dato que regresará y el tipo de los parámetros que la función espera. El estándar ANSI de C introdujo una nueva (mejor) forma de hacer lo anterior respecto a las versiones previas de C. La importancia de usar prototipos de funciones es la siguiente: Se hace el código más estructurado y por lo tanto, más fácil de leer. Se permite al compilador de C revisar la sintaxis de las funciones llamadas. Lo anterior es hecho, dependiendo del alcance de la función. Básicamente si una función ha sido definida antes de que sea usada (o llamada), entonces se puede usar la función sin problemas. Si no es así, entonces la función se debe declarar. La declaración simplemente maneja el tipo de dato que la función regresa y el tipo de parámetros usados por la función. Es una práctica usual y conveniente escribir el prototipo de todas las funciones al principio del programa, sin embargo esto no es estrictamente necesario. 107
Algoritmo y Estructura de Datos I Para declarar un prototipo de una función se indicará el tipo de dato que regresará la función, el nombre de la función y entre paréntesis la lista del tipo de los parámetros de acuerdo al orden que aparecen en la definición de la función. Por ejemplo: int longcad(char []); Lo anterior declara una función llamada longcad que regresa un valor entero y acepta una cadena como parámetro. Ejercicios Escribir una función ``reemplaza'', la cual toma una cadena como parámetro, le reemplaza todos los espacios de la cadena por un guión bajo, y devuelve el número de espacios reemplazados. Por ejemplo: char cadena[] = "El gato negro"; n = reemplaza( cadena ); deberá devolver: cadena convertida "El_gato_negro" n = 2 Escribir un programa que lea una línea de texto en un buffer (una cadena de caracteres) usando la función gets y calcule la longitud de la línea (NO usar la función strlen). Modificar el programa anterior para que lea un archivo de texto. El archivo deberá redireccionarse al programa, debiendo mostrar el contenido del mismo. En caso de que se lea una línea con longitud 0 deberá terminar el programa. 6.3 Arreglos unidimensionales y multidimensionales Los arreglos son una colección de variables del mismo tipo que se referencian utilizando un nombre común. Un arreglo consta de posiciones de memoria contigua. La dirección más baja corresponde al primer elemento y la más alta al último. Un arreglo puede tener una o varias dimensiones. Para acceder a un elemento en particular de un arreglo se usa un índice. El formato para declarar un arreglo unidimensional es: tipo nombre_arr [ tamaño ] Por ejemplo, para declarar un arreglo de enteros llamado listanum con diez elementos se hace de la siguiente forma: 108
Algoritmo y Estructura de Datos I int listanum[10]; En C, todos los arreglos usan cero como índice para el primer elemento. Por tanto, el ejemplo anterior declara un arreglo de enteros con diez elementos desde listanum[0] hasta listanum[9]. La forma como pueden ser accesados los elementos de un arreglo, es de la siguiente forma: listanum[2] = 15; /* Asigna 15 al 3er elemento del arreglo listanum*/ num = listanum[2]; /* Asigna el contenido del 3er elemento a la variable num */ El lenguaje C no realiza comprobación de contornos en los arreglos. En el caso de que sobrepase el final durante una operación de asignación, entonces se asignarán valores a otra variable o a un trozo del código, esto es, si se dimensiona un arreglo de tamaño N, se puede referenciar el arreglo por encima de N sin provocar ningún mensaje de error en tiempo de compilación o ejecución, incluso aunque probablemente se provoque el fallo del programa. Como programador se es responsable de asegurar que todos los arreglos sean lo suficientemente grandes para guardar lo que pondrá en ellos el programa. C permite arreglos con más de una dimensión, el formato general es: tipo nombre_arr [ tam1 ][ tam2 ] ... [ tamN]; Por ejemplo un arreglo de enteros bidimensionales se escribirá como: int tabladenums[50][50]; Observar que para declarar cada dimensión lleva sus propios paréntesis cuadrados. Para acceder los elementos se procede de forma similar al ejemplo del arreglo unidimensional, esto es, tabladenums[2][3] = 15; /* Asigna 15 al elemento de la 3ª fila y la 4ª columna*/ num = tabladenums[25][16]; A continuación se muestra un ejemplo que asigna al primer elemento de un arreglo bidimensional cero, al siguiente 1, y así sucesivamente. main() { int t,i,num[3][4]; 109
Algoritmo y Estructura de Datos I for(t=0; t<3; ++t) for(i=0; i<4; ++i) num[t][i]=(t*4)+i*1; for(t=0; t<3; ++t) { for(i=0; i<4; ++i) printf("num[%d][%d]=%d ", t,i,num[t][i]); printf("\n"); } } En C se permite la inicialización de arreglos, debiendo seguir el siguiente formato: tipo nombre_arr[ tam1 ][ tam2 ] ... [ tamN] = {lista‐valores}; Por ejemplo: int i[10] = {1,2,3,4,5,6,7,8,9,10}; int num[3][4]={0,1,2,3,4,5,6,7,8,9,10,11}; Un arreglo es un conjunto de variables del mismo tipo que pueden ser referenciadas a través de un mismo nombre. La forma de identificar a un elemento determinado es a través de un índice. La declaración int Array[10]; instruye al compilador a que reserve una cantidad de memoria suficiente para almacenar 10 entidades enteras y referirse a esa memoria a traves del identificador Array. Dado que el número de elementos en un arreglo suele ser utilizado en distintos lugares de un programa, es buen estilo de programación el referenciarlo a través de una constante simbólica: #define N 10 int Array[N]; Los elementos individuales del arreglo se comienza a numerar a partir del elemento 0, asi, Array[0] individualiza al primer elemento y Array[9] al último. Los arreglos pueden ser multidimensionales, asi por ejemplo 110
Algoritmo y Estructura de Datos I double Matriz[10][20]; Define una región de memoria como para almacenar 200 reales en doble precisión. La forma en que se organizan en la memoria estos 200 elementos es la siguiente: Matriz[0][0], Matriz[0][1], Matriz[0][2], ..., Matriz[1][0], Matriz[1][1],...,...,Matriz[9][19] La inicialización de un arreglo puede realizarse a través de una lista, si la lista es más corta que el número de elementos en el arreglo, el resto de los elementos se inicializan a 0. Se puede obviar el tamaño de un arreglo al inicializarlo con una lista, el tamaño será el mismo que el de la lista en este caso. Ej: float a[5] = {0.1, 1.2, 2.3, 3.4, 4.5}; double b[100] = {1.0}; /* los 99 restantes serán 0.0 */ int a[] = {2, 3, ‐5, 7}; /* equivale a a[4]={2,3,‐5,7} */ Ejemplo: /* Utilización de arreglos. Programa que cuenta cuántas veces se repite cada dígito, cada carácter separador, y otros carácteres. */ #include <stdio.h> #define ND 10 int main() { int c, i, nWhite = 0, nOther = 0, nDigit[ND]; for(i = 0; i < ND; i++) nDigit[i] = 0; while((c = getchar()) != EOF) if(c >= '0' && c <= '9') nDigit[c ‐ '0']++; else if(c == ' ' || c == '\n' || c == '\t') nWhite++; else nOther++; for(i = 0; i < ND; i++) printf("Dígito %d: %d\n",i,nDigit[i]); printf("Caracteres separadores: %d\n",nWhite); 111
Algoritmo y Estructura de Datos I printf("Otros caracteres: %d\n",nOther); return 0; } Compile y corra el siguiente programa y explique lo que ocurre: #include <stdio.h> int main(){ int a[4] = {0, 1, 2, 3}; int b[4] = {4, 5, 6, 7}; int i; for (i=0; i<8; i++) printf ("a[%d] = %d\n",i,a[i]); return 0; } Cadenas A diferencia de otros lenguajes de programación que emplean un tipo denominado cadena string para manipular un conjunto de simbolos, en C, se debe simular mediante un arreglo de caracteres, en donde la terminación de la cadena se debe indicar con nulo. Un nulo se especifica como '\0'. Por lo anterior, cuando se declare un arreglo de caracteres se debe considerar un carácter adicional a la cadena más larga que se vaya a guardar. Por ejemplo, si se quiere declarar un arreglo cadena que guarde una cadena de diez caracteres, se hará como: char cadena[11]; Se pueden hacer también inicializaciones de arreglos de caracteres en donde automáticamente C asigna el caracter nulo al final de la cadena, de la siguiente forma: char nombre_arr[ tam ]="cadena"; Por ejemplo, el siguiente fragmento inicializa cadena con ``hola'': char cadena[5]="hola"; El código anterior es equivalente a: char cadena[5]={'h','o','l','a','\0'}; 112
Algoritmo y Estructura de Datos I Para asignar la entrada estándar a una cadena se puede usar la función scanf con la opción %s (observar que no se requiere usar el operador &), de igual forma para mostrarlo en la salida estándar. Por ejemplo: main() { char nombre[15], apellidos[30]; printf("Introduce tu nombre: "); scanf("%s",nombre); printf("Introduce tus apellidos: "); scanf("%s",apellidos); printf("Usted es %s %s\n",nombre,apellidos); } El lenguaje C no maneja cadenas de caracteres, como se hace con enteros o flotantes, por lo que lo siguiente no es válido: main() { char nombre[40], apellidos[40], completo[80]; nombre="José María"; /* Ilegal */ apellidos="Morelos y Pavón"; /* Ilegal */ completo="Gral."+nombre+appellidos; /* Ilegal */ } 113
Algoritmo y Estructura de Datos I 114
Algoritmo y Estructura de Datos I CAPÍTULO VII Aplicaciones Ejercicio 1: /* Ejemplo 1 El primer programa en C */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main( void ) { printf( "Bienvenido a C!\n" ); return 0; /* indica que el programa terminó con exito */ } /* fin de la función main */ Ejercicio 2: /* Ejemplo 2 Impresión de una línea mediante dos instrucciones printf */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { printf( "Bienvenido " ); printf( "a C!\n" ); return 0; /* indica que el programa terminó con éxito */ } /* fin de la función main */ 115
Algoritmo y Estructura de Datos I Ejercicio 3: /* Ejemplo 3.c Impresión de múltiples líneas mediante una sola instrucción printf */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { printf( "Bienvenido\na\nC!\n" ); return 0; /* indica que el programa terminó con éxito */ } /* fin de la función main */ Ejercicio 4: /* Ejercicio 4.c Programa de suma */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { int entero1; /* primer número introducido por el usuario */ int entero2; /* segundo número introducido por el usuario */ int suma; /* variable en la cual se almacena la suma */ printf( "Introduzca el primer entero\n" ); /* indicador */ scanf( "%d", &entero1 ); /* lee un entero */ printf( "Introduzca el segundo entero\n" ); /* indicador */ scanf( "%d", &entero2 ); /* lee un entero */ suma = entero1 + entero2; /* asigna el total a suma */ printf( "La suma es %d\n", suma ); /* imprime la suma */ return 0; /* indica que el programa terminó con éxito */ } /* fin de la función main */ 116
Algoritmo y Estructura de Datos I Ejercicio 5: /* Ejercicio 5.c Uso de instrucciones if, operadores de relación, y operadores de igualdad */ #include <stdio.h> /* la función main inicia la ejecución del programa */ main() { int num1; /* primer número que lee el usuario */ int num2; /* segundo número que lee el usuario */ printf( "Introduzca dos enteros, y le dire\n" ); printf( "las relaciones que satisfacen: " ); scanf( "%d%d", &num1, &num2 ); /* lectura de los enteros */ if ( num1 == num2 ) { printf( "%d es igual que %d\n", num1, num2 ); } /* fin de if */ if ( num1 != num2 ) { printf( "%d no es igual que %d\n", num1, num2 ); } /* fin de if */ if ( num1 < num2 ) { printf( "%d es menor que %d\n", num1, num2 ); } /* fin de if */ if ( num1 > num2 ) { printf( "%d es mayor que %d\n", num1, num2 ); } /* fin de if */ if ( num1 <= num2 ) { printf( "%d es menor o igual que %d\n", num1, num2 ); } /* end if */ if ( num1 >= num2 ) { printf( "%d es mayor o igual que %d\n", num1, num2 ); } /* fin de if */ return 0; /* indica que el programa terminó con éxito */ } /* fin de la función main */ 117
Algoritmo y Estructura de Datos I Ejercicio 6: /* eleva x a la potencia y */ #include <stdio.h> int main() { int x, y, i, potencia; /* definición de las variables */ i = 1; potencia = 1; /* inicializa la potencia */ scanf( "%d", &x ); /* lectura de x del usuario */ scanf( "%d", &y ); /* lectura de y del usuario */ while ( i <= y ) { /* repetirá el ciclo while mientras i sea menor o igual a y */ potencia *= x; /* multiplica potencia por x */ ++i; /* incrementa i */ } /* fin del while */ printf( "%d\n", potencia ); /* despliega la potencia */ return 0; } /* fin de la función main */ Ejercicio 7: #include <stdio.h> int main() { int x = 1, total = 0, y; while ( x <= 10 ) { y = x * x; printf( "%d\n", y ); total += y; ++x; } printf( "El total es: %d\n", total ); return 0; } 118
Algoritmo y Estructura de Datos I Ejercicio 8: /* Ejemplo 8.c Programa para obtener el promedio de calificaciones de una clase mediante una repetición controlada por contador */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { int contador; /* número de la calificación siguiente */ int calificación; /* valor de la calificación */ int total; /* suma de las calificaciones introducidas por el usuario */ int promedio; /* promedio de las calificaciones */ /* fase de inicialización */ total = 0; /* inicializa total */ contador = 1; /* inicializa el contador del ciclo */ /* fase de proceso */ while ( contador <= 10 ) { /* repite 10 veces el ciclo */ printf( "Introduzca la calificación: " ); /* indicador para la entrada */ scanf( "%d", &calificación ); /* lee la calificación del usuario */ total = total + calificación; /* suma la calificación al total */ contador = contador + 1; /* incrementa el contador */ } /* fin de while */ /* fase de terminación */ promedio = total / 10; /* división entera */ printf( "El promedio de la clase es %d\n", promedio ); /* despliega el resultado */ return 0; /* indica que el programa terminó con exito */ } /* fin de la función main */ 119
Algoritmo y Estructura de Datos I Ejercicio 9: main() { float cm, pul, valor; char unidad; printf(“Introduce número y unidad (p=pulg. o c=cm: “); scanf(“%f %c”,&valor, &unidad); if (unidad==’p’) { cm=valor*2.54; printf(“Las %f pulgadas son %f centímetros\n”,valor,cm); } if (unidad==’c’) { pul=valor/2.54; printf(“Los %f centímetros son %f pulgadas\n”,valor,pul); } if (unidad!=’p’ && unidad!=’c’) printf(“No está puesta correctamente la unidad\n”); } Ejercicio 10: /* Ejemplo 10.c Programa para obtener el promedio de calificaciones de una clase mediante una repetición controlada por centinela */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { int contador; /* número de calificaciones introducidas */ int calificación; /* valor de la calificación */ int total; /* suma de las calificaciones */ float promedio; /* número con punto decimal para el promedio */ /* fase de inicialización */ total = 0; /* inicializa el total */ contador = 0; /* inicializa el contador del ciclo */ /* fase de proceso */ 120
Algoritmo y Estructura de Datos I /* obtiene la primera calificación del usuario */ printf( "Introduzca la calificación, ‐1 para terminar: " ); /* indicador para la entrada */ scanf( "%d", &calificación ); /* lee la calificación del usuario */ /* realiza el ciclo mientras no se introduzca el valor centinela */ while ( calificación != ‐1 ) { total = total + calificación; /* suma calificación a total */ contador = contador + 1; /* incrementa el contador */ /* obtiene la siguiente calificación del usuario */ printf( "Introduzca la calificación, ‐1 para terminar: " ); /* indicador para la entrada */ scanf("%d", &calificación); /* lee la siguiente calificación */ } /* fin de while */ /* fase de terminación */ /* si el usuario introduce al menos una calificación */ if ( contador != 0 ) { /* calcula el promedio de todas las calificaciones introducidas */ promedio = ( float ) total / contador; /* evita la truncación */ /* despliega el promedio con dos dígitos de precisión */ printf( " El promedio de la clase es: %.2f\n", promedio ); } /* fin de if*/ else { /* si no se introduce calificación alguna , despliega el mensaje */ printf( "No se introdujeron calificaciones\n" ); } /* fin de else */ return 0; /* indica que el programa terminó con exito */ } /* fin de la función main */ Ejercicio 11: /* Ejemplo 11.c Análisis de los resultados de un examen */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { 121
Algoritmo y Estructura de Datos I /* inicializa las variables en las definiciones */ int aprobados = 0; /* número de aprobados */ int reprobados = 0; /* número de reprobados*/ int estudiante = 1; /* contador de estudiantes */ int resultado; /* resultado de un examen */ /* procesa las calificaciones de 10 estudiantes mediante el uso de un ciclo controlado por un contador */ while ( estudiante <= 10 ) { /* indica al usuario la introducción del valor del usuario */ printf( "Introduzca el resultado ( 1=aprobado,2=reprobado ): " ); scanf( "%d", &resultado ); /* si el resultado es igual a 1, incrementa aprobados */ if ( resultado == 1 ) { aprobados = aprobados + 1; } /* fin de if */ else { /* de lo contrario, incrementa reprobados */ reprobados = reprobados + 1; } /* fin de else */ estudiante = estudiante + 1; /* incrementa el contador de estudiante */ } /* fin de while */ /* fase de terminación; despliega el número de aprobados y reprobados */ printf( "Aprobados %d\n", aprobados ); printf( "Reprobados %d\n", reprobados ); /* si aprobaron más de ocho estudiantes , imprime "objetivo alcanzado" */ if ( aprobados > 8 ) { printf( "Objetivo alcanzado\n" ); } /* fin de if */ return 0; /* indica que el programa terminó con exito */ } /* fin de la función main */ 122
Algoritmo y Estructura de Datos I Ejercicio 12: /* Ejemplo12.c Preincremeno y postincremento */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { int c; /* define la variable */ /* demuestra el postincremento */ c = 5; /* le asigna 5 a c */ printf( "%d\n", c ); /* imprime 5 */ printf( "%d\n", c++ ); /* imprime 5 y hace el postincremento */ printf( "%d\n\n", c ); /* imprime 6 */ /* demuestra el preincremento */ c = 5; /* le asigna 5 a c */ printf( "%d\n", c ); /* imprime 5 */ printf( "%d\n", ++c ); /* preincrementa e imprime 6 */ printf( "%d\n", c ); /* imprime 6 */ return 0; /* indica que el programa terminó con exito */ } /* fin de la función main */ Ejercicio 13: /* Ejemplo 13.c Repetición controlada por contador */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int contador = 1; /* inicialización */ while ( contador <= 10 ) { /* condición de repetición */ printf ( "%d\n", contador ); /* despliega el contador */ contador++; /* incremento */ } /* fin del while */ 123
Algoritmo y Estructura de Datos I return 0; /* indica terminación exitosa */ } /* fin de la función main */ Ejercicio 14: /* Ejemplo 14.c Repetición controlada por contador mediante la instrucción for */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int contador; /* definición del contador */ /* la inicialización, condición de repetición, e incremento se incluyen en el encabezado de la instrucción for. */ for ( contador = 1; contador <= 10; contador++ ) { printf( "%d\n", contador ); } /* fin del for */ return 0; /* indica terminación exitosa del programa */ } /* fin de la función main */ Ejercicio 15: /* Ejemplo 15.c Suma con for */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int suma = 0; /* inicializa la suma */ int numero; /* número a adicionar a suma */ for ( numero = 2; numero <= 100; numero += 2 ) { suma += numero; /* suma el número a suma */ } /* fin de for */ 124
Algoritmo y Estructura de Datos I printf( "La suma es %d\n", suma ); /* muestra la suma */ return 0; /* indica terminación exitosa del programa */ } /* fin de la función main */ Ejercicio 16: /* Ejemplo 16.c Cálculo del interés compuesto */ #include <stdio.h> #include <math.h> /* la función main comienza la ejecución del programa */ int main() { double monto; /* monto del depósito */ double principal = 1000.0; /* monto principal */ double tasa = .05; /* interés compuesto anual */ int anio; /* contador de años */ /* muestra el encabezado de salida de la tabla */ printf( "%4s%21s\n", "Anio", "Monto del deposito" ); /* calcula el monto del depósito para cada uno de los diez años */ for ( anio = 1; anio <= 10; anio++ ) { /* calcula el nuevo monto para el año especificado */ monto = principal * pow( 1.0 + tasa, anio ); /* muestra una línea de la tabla */ printf( "%4d%21.2f\n", anio, monto ); } /* fin de for */ return 0; /* indica terminación exitosa del programa */ } /* fin de la función main */ 125
Algoritmo y Estructura de Datos I Ejercicio 17: /* Ejemplo 17.c Cuenta las calificaciones con letras */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int calificación; /* una calificación */ int cuentaA = 0; /* número de As */ int cuentaB = 0; /* número de Bs */ int cuentaC = 0; /* número de Cs */ int cuentaD = 0; /* número de Ds */ int cuentaF = 0; /* número de Es */ printf( "Introduzca la letra de la calificación.\n" ); printf( "Introduzca el caracter EOF para finalizar la entrada de datos.\n" ); /* repite hasta que el usuario digita la secuencia de teclas de fin‐de‐archivo */ while ( ( calificación = getchar() ) != EOF ) { /* determina cual calificación se introdujo */ switch ( calificación ) { /* switch anidado dentro del while */ case 'A': /* la calificación es A */ case 'a': /* o a */ ++cuentaA; /* incrementa cuentaA */ break; /* necesario para salir de switch */ case 'B': /* la calificación es B */ case 'b': /* o b */ ++cuentaB; /* incrementa cuentaB */ break; /* sale de switch */ case 'C': /* la calificación es C */ case 'c': /* o c */ ++cuentaC; /* incrementa cuentaC */ break; /* sale de switch */ case 'D': /* la calificación es D */ case 'd': /* o d */ ++cuentaD; /* incrementa cuentaD */ 126
Algoritmo y Estructura de Datos I break; /* sale de switch */ case 'F': /* la calificación es F */ case 'f': /* o f */ ++cuentaF; /* incrementa cuentaF */ break; /* sale de switch */ case '\n': /* ignora nuevas líneas, */ case '\t': /* tabuladores, */ case ' ': /* y espacios en la entrada */ break; /* fin de switch */ default: /* atrapa todos los demás caracteres */ printf( "Introdujo una letra incorrecta." ); printf( " Introduzca una nueva calificación.\n" ); break; /* opcional; de todas maneras saldrá del switch */ } /* fin de switch */ } /* fin de while */ /* muestra el resumen de los resultados */ printf( "\nLos totales por calificación son:\n" ); printf( "A: %d\n", cuentaA ); /* despliega el número de calificaciones A */ printf( "B: %d\n", cuentaB ); /* despliega el número de calificaciones B */ printf( "C: %d\n", cuentaC ); /* despliega el número de calificaciones C */ printf( "D: %d\n", cuentaD ); /* despliega el número de calificaciones D */ printf( "F: %d\n", cuentaF ); /* despliega el número de calificaciones F */ return 0; /* indica terminación exitosa del programa */ } /* fin de la función main */ Ejercicio 18: /* Ejemplo 18.c Uso de la instrucción de repetición do/while */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int contador = 1; /* inicializa el contador */ 127
Algoritmo y Estructura de Datos I do { printf( "%d ", contador ); /* despliega el contador */ } while ( ++contador <= 10 ); /* fin del do...while */ return 0; /* indica la terminación exitosa del programa */ } /* fin de la función main */ Ejercicio 19: /* Ejemplo 19.c Uso de la instrucción break dentro de la instrucción for */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int x; /* contador */ /* repite 10 veces el ciclo */ for ( x = 1; x <= 10; x++ ) { /* si x es 5, termina el ciclo */ if ( x == 5 ) { break; /* rompe el ciclo sólo si x es 5 */ } /* fin de if */ printf( "%d ", x ); /* despliega el valor de x */ } /* fin de for */ printf( "\nRompe el ciclo en x == %d\n", x ); return 0; /* indica la terminación exitosa del programa */ } /* fin de la función main */ 128
Algoritmo y Estructura de Datos I Ejercicio 20: /* Ejemplo 20.c Uso de la instrucción continue dentro de una instrucción for */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int x; /* contador */ /* repite el ciclo 10 veces */ for ( x = 1; x <= 10; x++ ) { /* si x es 5, continua con la siguiente iteración del ciclo */ if ( x == 5 ) { continue; /* ignora el resto del código en el cuerpo del ciclo */ } /* fin de if */ printf( "%d ", x ); /* despliega el valor de x */ } /* fin de for */ printf( "\nUtiliza continue para ignorar la impresión del valor 5\n" ); return 0; /* indica la terminación exitosa del programa */ } /* fin de la función main */ Ejercicio 21: /* Ejemplo 21.c */ /* Verificación de las funciones matemáticas de la biblioteca */ #include <stdio.h> #include <math.h> /* la función main inicia la ejecución del programa */ int main() { /* calcula y despliega la raiz cuadrada */ printf( "sqrt(%.1f) = %.1f\n", 900.0, sqrt( 900.0 ) ); printf( "sqrt(%.1f) = %.1f\n", 9.0, sqrt( 9.0 ) ); 129
Algoritmo y Estructura de Datos I /* calcula y despliega la función exponencial e a la x */ printf( "exp(%.1f) = %f\n", 1.0, exp( 1.0 ) ); printf( "exp(%.1f) = %f\n", 2.0, exp( 2.0 ) ); /* calcula y despliega el logaritmo the logorithm (base e) */ printf( "log(%f) = %.1f\n", 2.718282, log( 2.718282 ) ); printf( "log(%f) = %.1f\n", 7.389056, log( 7.389056 ) ); /* calcula y despliega el logaritmo (base 10) */ printf( "log10(%.1f) = %.1f\n", 1.0, log10( 1.0 ) ); printf( "log10(%.1f) = %.1f\n", 10.0, log10( 10.0 ) ); printf( "log10(%.1f) = %.1f\n", 100.0, log10( 100.0 ) ); /* calcula y despliega el valor absoluto */ printf( "fabs(%.1f) = %.1f\n", 13.5, fabs( 13.5 ) ); printf( "fabs(%.1f) = %.1f\n", 0.0, fabs( 0.0 ) ); printf( "fabs(%.1f) = %.1f\n", ‐13.5, fabs( ‐13.5 ) ); /* calcula y despliega ceil( x ) */ printf( "ceil(%.1f) = %.1f\n", 9.2, ceil( 9.2 ) ); printf( "ceil(%.1f) = %.1f\n", ‐9.8, ceil( ‐9.8 ) ); /* calcula y despliega floor( x ) */ printf( "floor(%.1f) = %.1f\n", 9.2, floor( 9.2 ) ); printf( "floor(%.1f) = %.1f\n", ‐9.8, floor( ‐9.8 ) ); /* calcula y despliega pow( x, y ) */ printf( "pow(%.1f, %.1f) = %.1f\n", 2.0, 7.0, pow( 2.0, 7.0 ) ); printf( "pow(%.1f, %.1f) = %.1f\n", 9.0, 0.5, pow( 9.0, 0.5 ) ); /* calcula y despliega fmod( x, y ) */ printf( "fmod(%.3f/%.3f) = %.3f\n", 13.675, 2.333, fmod( 13.675, 2.333 ) ); /* calcula y despliega sin( x ) */ printf( "sin(%.1f) = %.1f\n", 0.0, sin( 0.0 ) ); /* calcula y despliega cos( x ) */ printf( "cos(%.1f) = %.1f\n", 0.0, cos( 0.0 ) ); /* calcula y despliega tan( x ) */ printf( "tan(%.1f) = %.1f\n", 0.0, tan( 0.0 ) ); 130
Algoritmo y Estructura de Datos I return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 22: /* Ejemplo 22.c Creación y uso de una función definida por el usuario */ #include <stdio.h> int cuadrado( int y ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { int x; /* contador */ /* repite 10 veces el ciclo y calcula e imprime cada vez el cuadrado de x */ for ( x = 1; x <= 10; x++ ) { printf( "%d ", cuadrado( x ) ); /* llamada a la función */ } /* fin de for */ printf( "\n" ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* definición de la función cuadrado, devuelve el cuadrado del parámetro */ int cuadrado( int y ) /* y es una copia del argumento para la función */ { return y * y; /* devuelve el cuadrado de y como un int */ } /* fin de la función cuadrado */ 131
Algoritmo y Estructura de Datos I Ejercicio 23: /* Ejemplo 23.c Encuentra el máximo de tres enteros */ #include <stdio.h> int maximo( int x, int y, int z ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { int numero1; /* primer entero */ int numero2; /* segundo entero */ int numero3; /* tercer entero */ printf( "Introduzca tres enteros: " ); scanf( "%d%d%d", &numero1, &numero2, &numero3 ); /* numero1, numero2 y numero3 son argumento para la llamada a la función maximo */ printf( "El maximo es: %d\n", maximo( numero1, numero2, numero3 ) ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* Definición de la función máximo */ /* x, y, y z son parámetros */ int maximo( int x, int y, int z ) { int max = x; /* asume que x es el mayor */ if ( y > max ) { /* si y es mayor que max, asigna y a max */ max = y; } /* fin de if */ if ( z > max ) { /* si z es mayor que max, asigna z a max */ max = z; } /* fin de if */ return max; /* max es el valor más grande */ } /* fin de la función máximo */ 132
Algoritmo y Estructura de Datos I Ejercicio 24: /* Ejemplo 24.c Escala y cambio de enteros producidos por 1 + rand() % 6. */ #include <stdio.h> #include <stdlib.h> /* la función main comienza la ejecución del programa */ int main() { int i; /* contador */ /* repite 20 veces */ for ( i = 1; i <= 20; i++ ) { /* obtiene un número aleatorio entre 1 y 6 y lo despliega */ printf( "%10d", 1 + ( rand() % 6 ) ); /* si el contador es divisible entre 5, comienza una nueva línea de salida */ if ( i % 5 == 0 ) { printf( "\n" ); } /* fin de if */ } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 25: /* Ejemplo 25.c Tiro de un dado de seis lados 6000 veces */ #include <stdio.h> #include <stdlib.h> /* la función main comienza la ejecución del programa */ int main() { int frecuencia1 = 0; /* contador del tiro 1 */ int frecuencia2 = 0; /* contador del tiro 2 */ int frecuencia3 = 0; /* contador del tiro 3 */ 133
Algoritmo y Estructura de Datos I int frecuencia4 = 0; /* contador del tiro 4 */ int frecuencia5 = 0; /* contador del tiro 5 */ int frecuencia6 = 0; /* contador del tiro 6 */ int tiro; /* contador de tiros, valores de 1 a 6000 */ int cara; /* representa un tiro del dado, valores de 1 a 6 */ /* repite 6000 veces y resume los resultados */ for ( tiro = 1; tiro <= 6000; tiro++ ) { cara = 1 + rand() % 6; /* número aleatorio de 1 a 6 */ /* determina el valor de la cara e incrementa el contador apropiado */ switch ( cara ) { case 1: /* tiro 1 */ ++frecuencia1; break; case 2: /* tiro 2 */ ++frecuencia2; break; case 3: /* tiro 3 */ ++frecuencia3; break; case 4: /* tiro 4 */ ++frecuencia4; break; case 5: /* tiro 5 */ ++frecuencia5; break; case 6: /* tiro 6 */ ++frecuencia6; break; /* opcional */ } /* fin de switch */ } /* fin de for */ /* despliega los resultados en forma tabular */ printf( "%s%13s\n", "Cara", "Frecuencia" ); 134
Algoritmo y Estructura de Datos I printf( " 1%13d\n", frecuencia1 ); printf( " 2%13d\n", frecuencia2 ); printf( " 3%13d\n", frecuencia3 ); printf( " 4%13d\n", frecuencia4 ); printf( " 5%13d\n", frecuencia5 ); printf( " 6%13d\n", frecuencia6 ); return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 26: /* Ejemplo 26.c Randomización del programa de dados */ #include <stdlib.h> #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { int i; /* contador */ unsigned semilla; /* número que se utiliza para establecer la semilla del generador de números aleatorios */ printf( "Introduzca la semilla: " ); scanf( "%u", &semilla ); /* observe %u para un unsigned */ srand( semilla ); /* establece la semilla del generador de números aleatorios */ /* repite 10 veces */ for ( i = 1; i <= 10; i++ ) { /* toma un número aleatorio de 1 a 6 y lo muestra */ printf( "%10d", 1 + ( rand() % 6 ) ); /* si contador es divisible entre 5, comienza una nueva línea de salida */ if ( i % 5 == 0 ) { printf( "\n" ); } /* fin de if */ } /* fin de for */ 135
Algoritmo y Estructura de Datos I return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 27: /* Ejemplo 27.c Craps */ #include <stdio.h> #include <stdlib.h> #include <time.h> /* contiene el prototipo de la función time */ /* constantes de enumeración que representan es estatus del juego */ enum Estatus { CONTINUA, GANA, PIERDE }; int tiraDados( void ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { int suma; /* suma del tiro de datos */ int miPunto; /* punto ganado */ enum Estatus estatusJuego; /* puede contener CONTINUA, GANA o PIERDE */ /* randomiza el generador de números aleatorios mediante el uso de la función time */ srand( time( NULL ) ); suma = tiraDados(); /* primer tiro de los dados */ /* determina el estatus del juego basado en la suma de los dados */ switch( suma ) { /* gana en el primer tiro */ case 7: case 11: estatusJuego = GANA; break; /* pierde en el primer tiro */ 136
Algoritmo y Estructura de Datos I case 2: case 3: case 12: estatusJuego = PIERDE; break; /* recuerda el punto */ default: estatusJuego = CONTINUA; miPunto = suma; printf( "Su punto es %d\n", miPunto ); break; /* opcional */ } /* fin de switch */ /* mientras el juego no se complete */ while ( estatusJuego == CONTINUA ) { suma = tiraDados(); /* tira de nuevo los dados */ /* determina el estatus del juego */ if ( suma == miPunto ) { /* gana por punto */ estatusJuego = GANA; /* fin del juego, gana el jugador */ } /* fin de if */ else { if ( suma == 7 ) { /* pierde al tirar 7 */ estatusJuego = PIERDE; /* termina el juego, pierde el jugador */ } /* fin de if */ } /* fin de else */ } /* fin de while */ /* despliega el mensaje del ganador o perdedor */ if ( estatusJuego == GANA ) { /* ¿Ganó el jugador? */ printf( "Gana el jugador\n" ); } /* fin de if */ else { /* pierde el jugador */ printf( "Pierde el jugador\n" ); } /* fin de else */ return 0; /* indica terminación exitosa */ } /* fin de main */ 137
Algoritmo y Estructura de Datos I /* tiro de dados, calcula la suma y despliega los resultados */ int tiraDados( void ) { int dado1; /* primer dado */ int dado2; /* segundo dado */ int sumaTemp; /* suma de los dados */ dado1 = 1 + ( rand() % 6 ); /* toma el aleatorio para el dado1 */ dado2 = 1 + ( rand() % 6 ); /* toma el aleatorio para el dado2 */ sumaTemp = dado1 + dado2; /* suma el dado1 y el dado2 */ /* despliega los resultados de este tiro */ printf( "El jugador tiro %d + %d = %d\n", dado1, dado2, sumaTemp ); return sumaTemp; /* devuelve la suma de los dados */ } /* fin de la función tiraDados */ Ejercicio 28: /* Ejemplo 28.c Ejemplo de alcance */ #include <stdio.h> void usoLocal( void ); /* prototipo de función */ void usoStaticLocal( void ); /* prototipo de función */ void usoGlobal( void ); /* prototipo de función */ int x = 1; /* variable global */ /* la función main comienza la ejecución del programa */ int main() { int x = 5; /* variable local a main */ printf("x local fuera del alcance de main es %d\n", x ); { /* comienza el nuevo alcance */ int x = 7; /* variable local con nuevo alcance */ printf( "x local en el alcance interno de main es %d\n", x ); 138
Algoritmo y Estructura de Datos I } /* fin de nuevo alcance */ printf( "x local en el alcance externo de main es %d\n", x ); usoLocal(); /* usoLocal contiene a automatic local x */ usoStaticLocal(); /* usoStaticLocal contiene a static local x */ usoGlobal(); /* usoGlobal utiliza global x */ usoLocal(); /* usoLocal reinicializa automatic local x */ usoStaticLocal(); /* static local x retiene su valor previo */ usoGlobal(); /* x global también retiene su valor */ printf( "\nx local en main es %d\n", x ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* usoLocal reinicializa a la variable local x durante cada llamada */ void usoLocal( void ) { int x = 25; /* se inicializa cada vez que se llama usoLocal */ printf( "\nx local en usoLocal es %d después de entrar a usoLocal\n", x ); x++; printf( "x local en usoLocal es %d antes de salir de usoLocal\n", x ); } /* fin de la función usoLocal */ /* usoStaticLocal initializa la variable static local x sólo la primera vez que se invoca a la función; el valor de x se guarda entre las llamadas a esta función */ void usoStaticLocal( void ) { /* se inicializa sólo la primera vez que se invoca usoStaticLocal */ static int x = 50; printf( "\nlocal static x es %d al entrar a usoStaticLocal\n", x ); x++; printf( "local static x es %d al salir de usoStaticLocal\n", x ); } /* fin de la función usoStaticLocal */ /* la función usoGlobal modifica la variable global x durante cada llamada */ void usoGlobal( void ) { 139
Algoritmo y Estructura de Datos I printf( "\nx global es %d al entrar a usoGlobal\n", x ); x *= 10; printf( "x global es %d al salir de usoGlobal\n", x ); } /* fin de la función usoGlobal */ Ejercicio 29: /* Ejemplo 29.c Función recursiva del factorial */ #include <stdio.h> long factorial( long numero ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { int i; /* contador */ /* repite 11 veces; durante cada iteración, calcula el factorial( i ) y despliega el resultado */ for ( i = 0; i <= 10; i++ ) { printf( "%2d! = %ld\n", i, factorial( i ) ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ /* definición recursiva de la función factorial */ long factorial( long número ) { /* caso base */ if ( número <= 1 ) { return 1; } /* fin de if */ else { /* paso recursivo */ return ( numero * factorial( numero ‐ 1 ) ); } /* fin de else */ } /* fin de la función factorial */ 140
Algoritmo y Estructura de Datos I Ejercicio 30: /* Ejemplo 30.c Función recursiva de fibonacci */ #include <stdio.h> long fibonacci( long n ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { long resultado; /* valor fibonacci */ long numero; /* numero a introducir por el usuario */ /* obtiene un entero del usuario */ printf( "Introduzca un entero: " ); scanf( "%ld", &numero); /* calcula el valor fibonacci del número introducido por el usuario */ resultado = fibonacci( numero ); /* despliega el resultado */ printf( "Fibonacci( %ld ) = %ld\n", numero, resultado ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* definición de la función recursiva fibonacci */ long fibonacci( long n ) { /* caso base */ if ( n == 0 || n == 1 ) { return n; } /* fin de if */ else { /* paso recursivo */ return fibonacci( n ‐ 1 ) + fibonacci( n ‐ 2 ); } /* fin de else */ } /* fin de la función fibonacci */ 141
Algoritmo y Estructura de Datos I Ejercicio 31: /* Ejemplo 31.c inicializar un arreglo */ #include <stdio.h> /* la función main inicia la ejecución del programa */ int main() { int n[ 10 ]; /* n es un arreglo de 10 enteros */ int i; /* contador */ /* inicializa los elementos n a 0 del arreglo */ for ( i = 0; i < 10; i++ ) { n[ i ] = 0; /* establece el elemento i a 0 */ } /* fin de for */ printf( "%s%13s\n", "Elemento", "Valor" ); /* muestra el contenido del arreglo n en forma tabular */ for ( i = 0; i < 10; i++ ) { printf( "%7d%13d\n", i, n[ i ] ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 32: /* Ejemplo 32.c Inicializa un arreglo mediante una lista de inicialización */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { /* utiliza la lista de inicialización para inicializar el arreglo n */ int n[ 10 ] = { 32, 27, 64, 18, 95, 14, 90, 70, 60, 37 }; int i; /* contador */ printf( "%s%13s\n", "Elemento", "Valor" ); 142
Algoritmo y Estructura de Datos I /* muestra el contenido del arreglo en forma tabular */ for ( i = 0; i < 10; i++ ) { printf( "%7d%13d\n", i, n[ i ] ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 33: /* Ejemplo 33.c Inicializa los elementos del arreglo s a los enteros pares de 2 a 20 */ #include <stdio.h> #define TAMANIO 10 /* la función main comienza la ejecución del programa */ int main() { /* se puede utilizar la constante simbólica TAMANIO para especificar el tamaño del arreglo */ int s[ TAMANIO ]; /* el arreglo s contiene 10 elementos */ int j; /* conntador */ for ( j = 0; j < TAMANIO; j++ ) { /* establece los valores */ s[ j ] = 2 + 2 * j; } /* fin de for */ printf( "%s%13s\n", "Elemento", "Valor" ); /* muestra el contenido del arreglo s en forma tabular */ for ( j = 0; j < TAMANIO; j++ ) { printf( "%7d%13d\n", j, s[ j ] ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ 143
Algoritmo y Estructura de Datos I Ejercicio 34: /* Ejemplo 34.c Calcula la suma de los elementos del arreglo */ #include <stdio.h> #define TAMANIO 12 /* la función main comienza la ejecución del programa */ int main() { /* utiliza una lista de inicialización para inicializar el arreglo */ int a[ TAMANIO ] = { 1, 3, 5, 4, 7, 2, 99, 16, 45, 67, 89, 45 }; int i; /* contadorr */ int total = 0; /* suma del arreglo */ /* suma el contenido del arreglo a */ for ( i = 0; i < TAMANIO; i++ ) { total += a[ i ]; } /* fin de for */ printf( "El total de los elementos del arreglo es %d\n", total ); return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 35: /* Ejemplo 35.c Programa de respuestas de examen */ #include <stdio.h> #define TAMANIO_RESPUESTA 40 /* define los tamaños de los arreglos */ #define TAMANIO_FRECUENCIA 11 /* la función main comienza la ejecución del programa */ int main() { int respuesta; /* contador a través de las 40 respuestas */ int rango; /* contador de rangoes de 1 a 10 */ /* inicializa los contadores de frecuancia a 0 */ int frecuencia[ TAMANIO_FRECUENCIA ] = { 0 }; 144
Algoritmo y Estructura de Datos I /* coloca las respuestas del exámen dentro del arreglo respuestas */ int respuestas[ TAMANIO_RESPUESTA ] = { 1, 2, 6, 4, 8, 5, 9, 7, 8, 10, 1, 6, 3, 8, 6, 10, 3, 8, 2, 7, 6, 5, 7, 6, 8, 6, 7, 5, 6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10 }; /* por cada respuesta, seleciona el valor de un elemento del arreglo respuestas y utiliza dicho valor como subíndice en el arreglo frecuencia para determinar el elemento a incrementar */ for ( respuesta = 0; respuesta < TAMANIO_RESPUESTA; respuesta++ ) { ++frecuencia[ respuestas [ respuesta ] ]; } /* fin de for */ /* despliega los resultados */ printf( "%s%17s\n", "Rango", "Frecuencia" ); /* muestra las frecuencias en forma tabular */ for ( rango = 1; rango < TAMANIO_FRECUENCIA; rango++ ) { printf( "%6d%17d\n", rango, frecuencia[ rango ] ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 36: /* Ejemplo 36.c Programa de impresión de un Histograma */ #include <stdio.h> #define TAMANIO 10 /* la función main comienza la ejecución del programa */ int main() { /* utiliza una lista de inicialización para inicializar el arreglon */ int n[ TAMANIO ] = { 19, 3, 15, 7, 11, 9, 13, 5, 17, 1 }; int i; /* contador for externo para el arreglo elementos */ int j; /* contador for interno cuenta *s en cada barra del histograma */ printf( "%s%13s%17s\n", "Elemento", "Valor", "Histograma" ); 145
Algoritmo y Estructura de Datos I /* para cada elemento del arreglo n, muestra una barra en el histograma */ for ( i = 0; i < TAMANIO; i++ ) { printf( "%7d%13d ", i, n[ i ]) ; for ( j = 1; j <= n[ i ]; j++ ) { /* imprime una barra */ printf( "%c", '*' ); } /* fin del for interno */ printf( "\n" ); /* fin de una barra del histograma */ } /* fin del for externo */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 37: /* Ejemplo 37.c Lanza un dado de seis lados 6000 veces */ #include <stdio.h> #include <stdlib.h> #include <time.h> #define TAMANIO 7 /* la función main comienza la ejecución del programa */ int main() { int cara; /* valor aleatorio del dado entre 1 y 6 */ int tiro; /* contador de tiros */ int frecuencia[ TAMANIO ] = { 0 }; /* inicializa la cuenta */ srand( time( NULL ) ); /* generador de la semilla de números aleatorios */ /* tira el dado 6000 veces */ for ( tiro = 1; tiro <= 6000; tiro++ ) { cara = 1 + rand() % 6; ++frecuencia[ cara ]; /* remplaza la instrucción switch de la línea 26 de la figura 5.8 */ } /* fin de for */ printf( "%s%17s\n", "Cara", "Frecuencia" ); 146
Algoritmo y Estructura de Datos I /* muestra los elementos 1‐6 de frecuencia en forma tabular */ for ( cara = 1; cara < TAMANIO; cara++ ) { printf( "%4d%17d\n", cara, frecuencia[ cara ] ); } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 38: /* Figura 6.10: fig06_10.c Manipulación de arreglos de caracteres como cadenas */ #include <stdio.h> /* la función main comienza la ejecución del programa */ int main() { char cadena1[ 20 ]; /* reserva 20 caracteres */ char cadena2[] = "literal de cadena"; /* reserva 18 caracteres */ int i; /* contador */ /* lee la cadena del usuario y la introduce en el arreglo cadena1 */ printf("Introduce una cadena: "); scanf( "%s", cadena1 ); /* entrada que finaliza con un espacio en blanco */ /* muestra las cadenas */ printf( "La cadena1 es: %s\ncadena2 es: %s\n" "La cadena1 con espacios entre caracteres es:\n", cadena1, cadena2 ); /* muestra los caracteres hasta que encuentra el caracter nulo */ for ( i = 0; cadena1[ i ] != '\0'; i++ ) { printf( "%c ", cadena1[ i ] ); } /* fin de for */ printf( "\n" ); return 0; /* indica terminación exitosa */ } /* fin de main */ 147
Algoritmo y Estructura de Datos I Ejercicio 39: /* Ejemplo 39.c Arreglos estáticos que se inicializan en cero */ #include <stdio.h> void iniciaArregloEstatico( void ); /* prototipo de la función */ void iniciaArregloAutomatico( void ); /* prototipo de la función */ /* la función main comienza le ejecución del programa */ int main() { printf( "Primera llamada a cada función:\n" ); iniciaArregloEstatico(); iniciaArregloAutomatico(); printf( "\n\nSegunda llamada a cada función:\n" ); iniciaArregloEstatico(); iniciaArregloAutomatico(); return 0; /* indica terminación exitosa */ } /* fin de main */ /* función para demostrar un arreglo estático local */ void iniciaArregloEstatico( void ) { /* inicializ los elementos a 0 la primera vez que se llama a la función */ static int arreglo1[ 3 ]; int i; /* contador */ printf( "\nValores al entrar a iniciaArregloEstatico:\n" ); /* muestra el contenido del arreglo1 */ for ( i = 0; i <= 2; i++ ) { printf( "arreglo1[ %d ] = %d ", i, arreglo1[ i ] ); } /* fin de for */ printf( "\nValores al salir de iniciaArregloEstatico:\n" ); /* modifica y muestra el contenido de arreglo1 */ for ( i = 0; i <= 2; i++ ) { printf( "arreglo1[ %d ] = %d ", i, arreglo1[ i ] += 5 ); 148
Algoritmo y Estructura de Datos I } /* fin de for */ } /* fin de la función iniciaArregloEstatico */ /* función para demostrar un arreglo local automático */ void iniciaArregloAutomatico( void ) { /* inicializa loe elementos cada vez que se llama a la función */ int arreglo2[ 3 ] = { 1, 2, 3 }; int i; /* contador */ printf( "\n\nValores al entrar a iniciaArregloAutomatico:\n" ); /* muestra el contenido de arreglo2 */ for ( i = 0; i <= 2; i++ ) { printf("arreglo2[ %d ] = %d ", i, arreglo2[ i ] ); } /* fin de for */ printf( "\nValores al salir de iniciaArregloAutomatico:\n" ); /* modifica y muestra el contenido de arreglo2 */ for ( i = 0; i <= 2; i++ ) { printf( "arreglo2[ %d ] = %d ", i, arreglo2[ i ] += 5 ); } /* fin de for */ } /* fin de la función iniciaArregloAutomatico */ Ejercicio 40: /* Ejemplo 40.c Paso de arreglos y de elementos de un arreglo a funciones */ #include <stdio.h> #define TAMANIO 5 /* prototipos de las funciones */ void modificaArreglo( int b[], int tamanio ); void modificaElemento( int e ); /* la función main comienza la ejecución del programa */ int main() { int a[ TAMANIO ] = { 0, 1, 2, 3, 4 }; /* inicializa a */ 149
Algoritmo y Estructura de Datos I int i; /* contador */ printf( "Efectos de pasar arreglos completos por referencia:\n\nThe " "los valores del arreglo original son:\n" ); /* muestra el arreglo original */ for ( i = 0; i < TAMANIO; i++ ) { printf( "%3d", a[ i ] ); } /* fin de for */ printf( "\n" ); /* pasa el arreglo a modificaArreglo por referencia */ modificaArreglo( a, TAMANIO ); printf( "Los valores del arreglo modificado son:\n" ); /* muestra el arreglo modificado */ for ( i = 0; i < TAMANIO; i++ ) { printf( "%3d", a[ i ] ); } /* fin de for */ /* muestra el valor de a[ 3 ] */ printf( "\n\n\nEfectos de pasar un elemento del arreglo " "por valor:\n\nEl valor de a[3] es %d\n", a[ 3 ] ); modificaElemento( a[ 3 ] ); /* pasa el elemento a[ 3 ] del arreglo por valor */ /* muestra el valor a[ 3 ] */ printf( "El valor de a[ 3 ] es %d\n", a[ 3 ] ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* en la función modificaArreglo, "b" apunta al arreglo original "a" e memoria */ void modificaArreglo( int b[], int tamanio ) { int j; /* contador */ /* multiplica cada elemento del arreglo por 2 */ for ( j = 0; j < tamanio; j++ ) { 150
Algoritmo y Estructura de Datos I b[ j ] *= 2; } /* fin de for */ } /* fin de la función modificaArreglo */ /* en la función modificaElemento, "e" es una copia local del elemento a[ 3 ] del arreglo se pasó desde main */ void modificaElemento( int e ) { /* multiplica el parámetro por 2 */ printf( "El valor en modificaElemento es %d\n", e *= 2 ); } /* fin de la función modificaElemento */ Ejercicio 41: /* Ejemplo 41.c Demostración del calificador de tipo const con arreglos */ #include <stdio.h> void intentaModifElArreglo( const int b[] ); /* prototipo de la función */ /* la función main comienza la ejecución del programa */ int main() { int a[] = { 10, 20, 30 }; /* inicializa a */ intentaModifElArreglo( a ); printf("%d %d %d\n", a[ 0 ], a[ 1 ], a[ 2 ] ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* en la función intentaModifElArreglo, el arreglo b es const, por lo tanto no puede ser utilizado para modificar el arreglo original a en main. */ void intentaModifElArreglo( const int b[] ) { b[ 0 ] /= 2; /* error */ b[ 1 ] /= 2; /* error */ b[ 2 ] /= 2; /* error */ } /* fin de la función intentaModifElArreglo */ 151
Algoritmo y Estructura de Datos I Ejercicio 42: /* Ejemplo 42.c Este programa introduce el tema del análisis de datos. Calcula la media, la mediana y la moda de los datos */ #include <stdio.h> #define TAMANIO 99 /* prototipos de las funciones */ void media( const int resp[] ); void mediana( int resp[] ); void moda( int frec[], const int resp[] ) ; void ordenamBurbuja( int a[] ); void imprimeArreglo( const int a[] ); /* la función main comienza la ejecución del programa */ int main() { int frecuencia[ 10 ] = { 0 }; /* inicializa el arreglo frecuencia */ /* inicializa el arreglo respuestas */ int respuesta[ TAMANIO ] = { 6, 7, 8, 9, 8, 7, 8, 9, 8, 9, 7, 8, 9, 5, 9, 8, 7, 8, 7, 8, 6, 7, 8, 9, 3, 9, 8, 7, 8, 7, 7, 8, 9, 8, 9, 8, 9, 7, 8, 9, 6, 7, 8, 7, 8, 7, 9, 8, 9, 2, 7, 8, 9, 8, 9, 8, 9, 7, 5, 3, 5, 6, 7, 2, 5, 3, 9, 4, 6, 4, 7, 8, 9, 6, 8, 7, 8, 9, 7, 8, 7, 4, 4, 2, 5, 3, 8, 7, 5, 6, 4, 5, 6, 1, 6, 5, 7, 8, 7 }; /* procesa las respuestas */ media( respuesta ); mediana( respuesta ); moda( frecuencia, respuesta ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* calcula el promedio de todos los valores de las respuestas */ 152
Algoritmo y Estructura de Datos I void media( const int resp[] ) { int j; /* contador del total de elementos del arreglo */ int total = 0; /* variable para mantener la suma de los elementos del arreglo */ printf( "%s\n%s\n%s\n", "********", " Media", "********" ); /* total de los valores de las respuestas */ for ( j = 0; j < TAMANIO; j++ ) { total += resp[ j ]; } /* fin de for */ printf( "La media es el valor promedio de los datos.\n" "La media es igual al total de\n" "todos los elementos de datos divididos por\n" "el numero de elementos de datos ( %d ). La media\n" "en esta ejecución es: %d / %d = %.4f\n\n", TAMANIO, total, TAMANIO, ( double ) total / TAMANIO ); } /* fin de la función media */ /* ordena el arreglo y determina el valor de la mediana */ void mediana( int resp[] ) { printf( "\n%s\n%s\n%s\n%s", "********", " Mediana", "********", "El arreglo de respuestas desordenado es" ); imprimeArreglo( resp ); /* muestra el arreglo desordenado */ ordenamBurbuja( resp ); /* ordena el arreglo */ printf( "\n\nEl arreglo ordenado es " ); imprimeArreglo( resp ); /* muestra el arreglo ordenado */ /* muestra la mediana */ printf( "\n\nLa mediana es el elemento %d del\n" "arreglo ordenado de elementos %d.\n" "Para esta ejecución la mediana es %d\n\n", TAMANIO / 2, TAMANIO, resp[ TAMANIO / 2 ] ); } /* fin de la función mediana */ /* determina las respuestas más frecuentes */ void moda( int frec[], const int resp[] ) 153
Algoritmo y Estructura de Datos I { int rango; /* contador para acceder a los elementos de 1 a 9 del arreglo frec */ int j; /* contador para sumar los elementos de 0 a 98 des arreglo respuesta */ int h; /* contador para desplegar histogramas de los elementos en el arreglo frec */ int masGrande = 0; /* representa la frecuencia más grande */ int valorModa = 0; /* respresenta la respuesta más frecuente */ printf( "\n%s\n%s\n%s\n", "********", " Moda", "********" ); /* inicializa las frecuencias a 0 */ for ( rango = 1; rango <= 9; rango++ ) { frec[ rango ] = 0; } /* fin de for */ /* suma las frecuencias */ for ( j = 0; j < TAMANIO; j++ ) { ++frec[ resp[ j ] ]; } /* fin de for */ /* muestra los encabezados de las columnast columns */ printf( "%s%11s%19s\n\n%54s\n%54s\n\n", "Respuesta", "Frecuencia", "Histograma", "1 1 2 2", "5 0 5 0 5" ); /* muestra los resultados */ for ( rango = 1; rango <= 9; rango++ ) { printf( "%8d%11d ", rango, frec[ rango ] ); /* sigue la pista del valor de la moda y del valor de la frecuencia más grande */ if ( frec[ rango ] > masGrande ) { masGrande = frec[ rango ]; valorModa = rango; } /* fin de if */ /* muestra los histogramas de barras que representan el valor de la frecuencia */ for ( h = 1; h <= frec[ rango ]; h++ ) { printf( "*" ); } /* fin del for interno */ printf( "\n" ); /* nueva línea de salida */ } /* fin del for externo */ 154
Algoritmo y Estructura de Datos I /* despliega el valor de la moda */ printf( "La moda es el valor mas frecuente.\n" "Para esta ejecución la moda es %d el cual ocurrio" " %d veces.\n", valorModa, masGrande ); } /* fin de la función moda */ /* función que ordena un arreglo mediante el algoritmo del método de la burbuja algorithm */ void ordenamBurbuja( int a[] ) { int pasada; /* contador de pasadas */ int j; /* contaodr de pasadas */ int almacena; /* ubicación temporal utilizada para intercambiar los elementos */ /* ciclo para controlar el número de pasadas */ for ( pasada = 1; pasada < TAMANIO; pasada++ ) { /* ciclo para controlar el número de comparaciones por pasada */ for ( j = 0; j < TAMANIO ‐ 1; j++ ) { /* intercambia los elementos si no se encuentran en orden */ if ( a[ j ] > a[ j + 1 ] ) { almacena = a[ j ]; a[ j ] = a[ j + 1 ]; a[ j + 1 ] = almacena; } /* fin de if */ } /* fin del for interno */ } /* fin del for externo */ } /* fin de ordenamBurbuja */ /* muestra el contenido del arreglo (20 valores por línea) */ void imprimeArreglo( const int a[] ) { int j; /* contador */ /* muestra el contenido del arreglo */ for ( j = 0; j < TAMANIO; j++ ) { if ( j % 20 == 0 ) { /* comienza una nueva línea cada 20 valores */ printf( "\n" ); 155
Algoritmo y Estructura de Datos I } /* fin de ifend if */ printf( "%2d", a[ j ] ); } /* fin de for */ } /* fin de la función imprimeArreglo */ Ejercicio 43: /* Ejemplo 43.c Búsqueda lineal en un arreglo */ #include <stdio.h> #define TAMANIO 100 /* prototipo de la función */ int busquedaLineal( const int arreglo[], int llave, int tamanio ); /* la función main comienza la ejecución del programa */ int main() { int a[ TAMANIO ]; /* crea el arreglo a */ int x; /* contador para inicializar los elementos de 0 a 99 del arreglo a */ int llaveBusqueda; /* valor para localizar en el arreglo a */ int elemento; /* variable para almacenar la ubicación de llaveBusqueda o ‐1 */ /* crea los datos */ for ( x = 0; x < TAMANIO; x++ ) { a[ x ] = 2 * x; } /* fin de for */ printf( "Introduzca la llave de busqueda entera:\n" ); scanf( "%d", &llaveBusqueda ); /* intenta localizar llaveBusqueda en el arreglo a */ elemento = busquedaLineal( a, llaveBusqueda, TAMANIO ); /* despliega los resultados */ if ( elemento != ‐1 ) { printf( "Encontre el valor en el elemento %d\n", elemento ); } /* fin de if */ else { printf( "Valor no encontrado\n" ); 156
Algoritmo y Estructura de Datos I } /* fin de else */ return 0; /* indica terminación exitosa */ } /* fin de main */ /* compara la llave con cada elemento del arreglo hasta que localiza el elemento o hasta que alcanza el final del arreglo; devuelve el subíndice del elemento si lo encontró o ‐1 si no lo encontró */ int busquedaLineal( const int arreglo[], int llave, int tamanio ) { int n; /* contador */ /* ciclo a través del arreglo */ for ( n = 0; n < tamanio; ++n ) { if ( arreglo[ n ] == llave ) { return n; /* devuelve la ubicación de la llave */ } /* fin de if */ } /* fin de for */ return ‐1; /* llave no encontrada */ } /* fin de la función busquedaLineal */ Ejercicio 44: /* Ejemplo.c Búsqueda binaria dentro de un arreglo */ #include <stdio.h> #define TAMANIO 15 /* prototipos de las funciones */ int busquedaBinaria( const int b[], int claveDeBusqueda, int bajo, int alto ); void despliegaEncabezado( void ); void despliegaLinea( const int b[], int bajo, int medio, int alto ); /* la función main comienza la ejecución del programa */ int main() { int a[ TAMANIO ]; /* crea el arreglo a */ 157
Algoritmo y Estructura de Datos I int i; /* contador para inicializar los elementos de 0 a 14 del arreglo a */ int llave; /* valor a localizar en el arreglo a */ int resultado; /* variable para almacenar la ubicación de la llave o ‐1 */ /* crea los datos */ for ( i = 0; i < TAMANIO; i++ ) { a[ i ] = 2 * i; } /* fin de for */ printf( "Introduzca un numero entre 0 y 28: " ); scanf( "%d", &llave ); despliegaEncabezado(); /* busca la llave en el arreglo a */ resultado = busquedaBinaria( a, llave, 0, TAMANIO ‐ 1 ); /* despliega los resultados */ if ( resultado != ‐1 ) { printf( "\n%d se encuentra en el elemento %d del arreglo\n", llave, resultado ); } /* fin de if */ else { printf( "\n%d no se encuentra\n", llave ); } /* fin de else */ return 0; /* indica terminación exitosa */ } /* fin de main */ /* función para realizar la búsqueda binaria en un arreglo */ int busquedaBinaria( const int b[], int claveDeBusqueda, int bajo, int alto ) { int central; /* variable para mantener el elemento central del arreglo */ /* realiza el ciclo hasta que el subínice bajo es mayor que el subíndice alto */ while ( bajo <= alto ) { /* determina el elemento central del subarreglo en el que se busca */ central = ( bajo + alto ) / 2; /* despliega el subarreglo utilizado en este ciclo */ despliegaLinea( b, bajo, central, alto ); 158
Algoritmo y Estructura de Datos I /* si claveDeBusqueda coincide con el elemento central, devuelve central */ if ( claveDeBusqueda == b[ central ] ) { return central; } /* fin de if */ /* si claveDeBusqueda es menor que el elemento central, establece el nuevo valor de alto */ else if ( claveDeBusqueda < b[ central ] ) { alto = central ‐ 1; /* busca en la mitad inferior del arreglosearch low end of array */ } /* fin de else if */ /* si claveDeBusqueda es mayor que el elemento central, establece el nuevo valor para bajo */ else { bajo = central + 1; /* busca en la mitad superior del arreglo */ } /* fin de else */ } /* fin de while */ return ‐1; /* no se encontró claveDeBusqueda */ } /* fin de la funcipon busquedaBinaria */ /* Imprime un encabezado para la salida */ void despliegaEncabezado( void ) { int i; /* contador */ printf( "\nSubindices:\n" ); /* muestra el encabezado de la columna */ for ( i = 0; i < TAMANIO; i++ ) { printf( "%3d ", i ); } /* fin de for */ printf( "\n" ); /* comienza la nueva línea de salida */ /* muestra una línea de caracteres ‐ */ for ( i = 1; i <= 4 * TAMANIO; i++ ) { printf( "‐" ); } /* fin de for */ 159
Algoritmo y Estructura de Datos I printf( "\n" ); /* inicia una nueva línea de salida */ } /* fin de la función despliegaEncabezado */ /* Imprime una línea de salida que muestra la parte actual del arreglo que se esta procesando. */ void despliegaLinea( const int b[], int baj, int cen, int alt ) { int i; /* contador para la iteración a través del arreglo b */ /* ciclo a través del arreglo completo */ for ( i = 0; i < TAMANIO; i++ ) { /* despliega espacios si se encuentra fuera del rango actual del subarreglo */ if ( i < baj || i > alt ) { printf( " " ); } /* fin de if */ else if ( i == cen ) { /* despliega el elemento central */ printf( "%3d*", b[ i ] ); /* marca el valor central */ } /* fin de else if */ else { /* despliega otros elementos en el subarreglo */ printf( "%3d ", b[ i ] ); } /* fin de else */ } /* fin de for */ printf( "\n" ); /* inicia la nueva línea de salida */ } /* fin de la función despliegaLinea */ Ejercicio 45: /* Figura 6.22: fig06_22.c Ejemplo de un arreglo de doble subíndice */ #include <stdio.h> #define ESTUDIANTES 3 #define EXAMENES 4 /* prototipos de las funciones */ int minimo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ); int maximo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ); double promedio( const int estableceCalif[], int examenes ); void despliegaArreglo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ); 160
); Algoritmo y Estructura de Datos I /* la función main comienza la ejecución del programa */ int main() { int estudiante; /* contador de estudiantes */ /* inicializa las calificaciones para tres estudiantes (filas) */ const int calificacionesEstudiantes[ ESTUDIANTES ][ EXAMENES ] = { { 77, 68, 86, 73 }, { 96, 87, 89, 78 }, { 70, 90, 86, 81 } }; /* muestra el arreglo calificacionesEstudiantes */ printf( "El arreglo es:\n" ); despliegaArreglo( calificacionesEstudiantes, ESTUDIANTES, EXAMENES ); /* determina el valor más pequeño y el valor más grande de las calificaciones */ printf( "\n\nCalificacion mas baja: %d\nCalificacion mas alta: %d\n", minimo( calificacionesEstudiantes, ESTUDIANTES, EXAMENES ), maximo( calificacionesEstudiantes, ESTUDIANTES, EXAMENES ) ); /* calcula el promedio de calificaciones de cada estudiante */ for ( estudiante = 0; estudiante < ESTUDIANTES; estudiante++ ) { printf( "El promedio de calificacion del estudiante %d es %.2f\n", estudiante, promedio( calificacionesEstudiantes[ estudiante ], EXAMENES ) } /* fin de for */ return 0; /* indica terminación exitosa */ } /* fin de main */ /* Encuentra la calificación mínima */ int minimo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ) { int i; /* contador de estudiantes */ int j; /* contador de examenes */ int califBaja = 100; /* inicializa a la calificación más alta posible */ /* ciclo a través de las filas de calificaciones */ for ( i = 0; i < alumnos; i++ ) { /* ciclo a través de las columnas de calificaciones */ 161
Algoritmo y Estructura de Datos I for ( j = 0; j < examenes; j++ ) { } /* fin del for interno */ if ( calificaciones[ i ][ j ] < califBaja ) { califBaja = calificaciones[ i ][ j ]; } /* fin de if */ } /* fin del for externo */ return califBaja; /* devuelve la calificación mínima */ } /* fin de la función main */ /* Encuentra la calificación más alta */ int maximo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ) { int i; /* contador de estudiantes */ int j; /* contador de examenes */ int califAlta = 0; /* inicializa a la calificación más baja posible */ /* ciclo a través de las filas de calificaciones */ for ( i = 0; i < alumnos; i++ ) { /* ciclo a través de las columnas de calificaciones */ for ( j = 0; j < examenes; j++ ) { } /* fin del for interno */ if ( calificaciones[ i ][ j ] > califAlta ) { califAlta = calificaciones[ i ][ j ]; } /* fin de if */ } /* fin del for externo */ return califAlta; /* devuelve la calificación máxima */ } /* fin de la función maximo */ /* Determina la calificación promedio para un estudiante en especial */ double promedio( const int conjuntoDeCalificaciones[], int examenes ) { int i; /* contador de exáenes */ 162
Algoritmo y Estructura de Datos I int total = 0; /* suma de las calificaciones del examen */ /* total de calificaciones de un estudiante */ for ( i = 0; i < examenes; i++ ) { total += conjuntoDeCalificaciones[ i ]; } /* fin de for */ return ( double ) total / examenes; /* promedio */ } /* fin de la función promedio */ /* Imprime el arreglo */ void despliegaArreglo( const int calificaciones[][ EXAMENES ], int alumnos, int examenes ) { int i; /* contador de estudiantes */ int j; /* contador de examenes */ /* muestra el encabezado de las columnas */ printf( " [0] [1] [2] [3]" ); /* muestra las calificaciones en forma tabular */ for ( i = 0; i < alumnos; i++ ) { /* muestra la etiqueta de la fila */ printf( "\ncalificacionesEstudiantes[%d] ", i ); /* muestra las calificaciones de un estudiante */ for ( j = 0; j < examenes; j++ ) { printf( "%‐5d", calificaciones[ i ][ j ] ); } /* fin del for interno */ } /* fin del for externo */ } /* fin de la función despliegaArreglo */ Ejercicio 46: /* Ejemplo 46.c Uso de los operadores & y * */ #include <stdio.h> int main() 163
Algoritmo y Estructura de Datos I { int a; /* a es un entero */ int *ptrA; /* ptrA es un apuntador a un entero */ a = 7; ptrA = &a; /* ptrA toma la dirección de a */ printf( "La direccion de a es %p" "\nEl valor de ptrA es %p", &a, ptrA ); printf( "\n\nEl valor de a es %d" "\nEl valor de *ptrA es %d", a, *ptrA ); printf( "\n\nMuestra de que * y & son complementos " "uno del otro\n&*ptrA = %p" "\n*&ptrA = %p\n", &*ptrA, *&ptrA ); return 0; /* indica terminación exitosa */ } /* fin de main */ Ejercicio 47: /* Figura 7.6: fig07_06.c Eleva al cubo una variable mediante una llamada por valor */ #include <stdio.h> int cuboPorValor( int n ); /* prototipo */ int main() { int numero = 5; /* inicializa numero */ printf( "El valor original de numero es %d", numero ); /* pasa numero por valor a cuboPorValor */ numero = cuboPorValor( numero ); printf( "\nEl nuevo valor de numero es %d\n", numero ); return 0; /* indica terminación exitosa */ 164
Algoritmo y Estructura de Datos I } /* fin de main */ /* calcula y devuelve el cubo de un argumento entero */ int cuboPorValor( int n ) { return n * n * n; /* eleva al cubo la variable local n y devuelve el resultado */ } /* fin de la función cuboPorValor */ Ejercicio 48: /* Figura 7.7: fig07_07.c Eleva al cubo una variable mediante el uso de una llamada por referencia con un apuntador como argumento */ #include <stdio.h> void cuboPorReferencia( int *ptrN ); /* prototipo */ int main() { int numero = 5; /* inicializa numero */ printf( "El valor original de numero es %d", numero ); /* pasa la dirección de numera a cuboPorReferencia */ cuboPorReferencia( &numero ); printf( "\nEl nuevo valor de numero es %d\n", numero ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* calcula el cubo de *ptrN; modifica la variable numero en main */ void cuboPorReferencia( int *ptrN ) { *ptrN = *ptrN * *ptrN * *ptrN; /* cubo de *ptrN */ } /* fin de la función cuboPorReferencia */ 165
Algoritmo y Estructura de Datos I Ejercicio 49: /* Ejemplo 49.c Conversión de letras minúsculas a letras mayúsculas mediante el uso de un apuntador no constante a un dato no constante */ #include <stdio.h> #include <ctype.h> void convierteAmayusculas( char *ptrS ); /* prototipo */ int main() { char cadena[] = "caracteres y $32.98"; /* inicializa char arreglo */ printf( "La cadena antes de la conversion es : %s", cadena ); convierteAmayusculas( cadena ); printf( "\nLa cadena despues de la conversion es: %s\n", cadena ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* convierte una cadena a letras mayúsculas */ void convierteAmayusculas( char *ptrS ) { while ( *ptrS != '\0' ) { /* el caracter actual no es '\0' */ if ( islower( *ptrS ) ) { /* si el caracter es minúscula, */ *ptrS = toupper( *ptrS ); /* Lo convierte a mayúscula */ } /* fin de if */ ++ptrS; /* mueve ptrS al siguiente caracter */ } /* fin del while */ } /* fin de la función convierteAmayusculas */ 166
Algoritmo y Estructura de Datos I Ejercicio 50: /* Figura 7.11: fig07_11.c Impresión de una cadena caracter por caracter mediante el uso de un apuntador no constante a un dato constante */ #include <stdio.h> void imprimeCaracteres( const char *ptrS ); int main() { /* inicializa el arreglo de caracteres */ char cadena[] = "imprime los caracteres de una cadena"; printf( "La cadena es:\n" ); imprimeCaracteres( cadena ); printf( "\n" ); return 0; /* indica terminación exitosa */ } /* fin de main */ /* ptrS no puede modificar el caracter al cual apunta, es decir, ptrS es un apuntador de "solo lectura" */ void imprimeCaracteres( const char *ptrS ) { /* repite el ciclo para toda la cadena */ for ( ; *ptrS != '\0'; ptrS++ ) { /* sin inicialización */ printf( "%c", *ptrS ); } /* fin de for */ } /* fin de la función imprimeCaracteres */ 167
Algoritmo y Estructura de Datos I 168
Algoritmo y Estructura de Datos I Bibliografía •
BORES Rosario, ROSALES Roman; "Computación. Metodología, lógica computacional y programación" Mc Graw Hill 2006 •
CORREA URIBE Guillermo; "Desarrollo de algoritmos y sus aplicaciones en Basic, Pascal y C (3ª. Edición)" Mc Graw Hill 2005 •
JEAN Paul Tremblay, B. Bunt Richard; "Introducción a la ciencias de las computadoras (enfoque algoritmico)" Mc Graw Hill 2005 •
JOYANES AGUILAR Luis; "Metodología de la programación" Mc Graw Hill 2006 •
JOYANES AGUILAR Luis; "Problemas de metodología de la programación" Mc Graw Hill 2006 •
JOYANES AGUILAR Luis; "Fundamentos de programación, algoritmos y estructura de datos". Mc Graw Hill 2006 •
JOYANES AGUILAR Luis, Luis Rodríguez Baena y Matilde Fernández Azuela; "Fundamentos de programación, libro de problemas" Mc graw Hill 2005 •
LEVINE Guillermo; "Introducción a la computación y a la programación estructurada" Mc Graw Hill 2006 •
LOZANO Letvin; "Diagramación y programación estructurada y libre" Mc Graw Hill 2006 169
Descargar