FUNDAMENTOS DE PROGRAMACIÓN FUNDAMENTOS DE PROGRAMACIÓN ................................................................................................................ 0 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS ................................................................................................................. 7 FACULTAD DE CIENCIA Y TECNOLOGÍA .......................................................................................................................... 7 SEDE: ORO VERDE ................................................................................................................................................................ 7 FUNDAMENTOS DE PROGRAMACIÓN ................................................................................................................ 7 UNIDAD 1 ................................................................................................................................................................ 7 NOCIÓN DE ALGORITMO .................................................................................................................................... 7 RESOLUCIÓN DE PROBLEMAS COMPUTACIONALES .............................................................................. 8 ETAPAS PARA LA RESOLUCIÓN DE PROBLEMAS ................................................................................... 8 ESTRATEGIA ......................................................................................................................................................................... 9 ALGORITMO ....................................................................................................................................................................... 10 FORMALIZACIÓN ............................................................................................................................................................ 13 PROGRAMACIÓN MODULAR ................................................................................................................................. 14 Objetivos de la programación modular ................................................................................................................. 14 FACULTAD DE CIENCIA Y TECNOLOGÍA - UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .................................................................................................................................................................................. 15 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 19 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 19 SEDE: ORO VERDE ............................................................................................................................................................. 19 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 19 UNIDAD 2 .............................................................................................................................................................. 19 FORMALIZACIÓN DE ALGORITMOS ............................................................................................................. 19 UADER-‐ FCYT -‐-‐ UNIDAD 2 ............................................................................................................................. 20 ALGORITMOS COMPUTACIONALES .................................................................................................................. 20 CONSTANTES, VARIABLES Y EXPRESIONES ............................................................................................. 21 TIPOS DE DATOS ............................................................................................................................................................ 22 Tipo Numérico ..................................................................................................................................................................... 22 Tipo Caracter ....................................................................................................................................................................... 24 Tipo Lógico ............................................................................................................................................................................ 25 PRIMITIVAS ......................................................................................................................................................................... 27 ASIGNACIÓN ........................................................................................................................................................................... 27 ENTRADA Y SALIDA ............................................................................................................................................................. 28 DIAGRAMAS DE FLUJO ............................................................................................................................................... 29 MODELO PARA LA RESOLUCION DE PROBLEMAS ................................................................................. 30 CONCLUSIÓN .................................................................................................................................................................... 32 FACULTAD DE CIENCIA Y TECNOLOGÍA - UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .................................................................................................................................................................................. 33 FACULTAD DE CIENCIA Y TECNOLOGÍA - UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .................................................................................................................................................................................. 37 FACULTAD DE CIENCIA Y TECNOLOGÍA - UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .................................................................................................................................................................................. 41 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 45 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 45
SEDE: ORO VERDE ............................................................................................................................................................. 45 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 45 UNIDAD 4 .............................................................................................................................................................. 45 ESTRUCTURAS DE DATOS ............................................................................................................................... 45 PARTE I .................................................................................................................................................................. 45 UADER-‐ FCYT -‐-‐ UNIDAD 4 ............................................................................................................................. 46 ANÁLISIS DE LA DEFINICIÓN ............................................................................................................................................. 47 ARREGLO LINEAL, VECTOR O TABLA UNIDIMENSIONAL. .................................................................. 47 TODO ARREGLO TIENE ASOCIADO: ............................................................................................................................... 48 REPRESENTACIÓN GRÁFICA ............................................................................................................................................ 48 DIMENSIONAMIENTO ........................................................................................................................................................... 48 CÓMO INDICAR LA DIMENSIÓN DE UN ARREGLO ...................................................................................................... 49 OPERACIONES CON ARREGLOS ..................................................................................................................................... 50 ESTRUCTURA PARA ................................................................................................................................................... 54 ANIDAMIENTO DE ESTRUCTURAS PARA .................................................................................................................... 56 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 58 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 58 SEDE: ORO VERDE ............................................................................................................................................................. 58 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 58 UNIDAD 4 .............................................................................................................................................................. 58 ESTRUCTURAS DE DATOS ............................................................................................................................... 58 PARTE II ................................................................................................................................................................ 58 UADER-‐ FCYT -‐-‐ UNIDAD 4 ............................................................................................................................. 59 ARREGLOS BIDIMENSIONALES ........................................................................................................................... 59 ARREGLO BIDIMENSIONAL O MATRIZ ............................................................................................................. 59 OPERACIONES CON MATRICES .......................................................................................................................... 61 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 66 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 66 SEDE: ORO VERDE ............................................................................................................................................................. 66 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 66 UNIDAD 5 .............................................................................................................................................................. 66 INTRODUCCIÓN A LA ........................................................................................................................................ 66 PROGRAMACIÓN ................................................................................................................................................ 66 INTRODUCCIÓN ................................................................................................................................................... 67 REVISIÓN DE CONCEPTOS ................................................................................................................................. 67 CÓDIGO EJECUTABLE ......................................................................................................................................... 69 DEPURACIÓN DE PROGRAMAS ........................................................................................................................ 70 LENGUAJES DE PROGRAMACIÓN ..................................................................................................................... 70 PRINCIPALES IDEAS ............................................................................................................................................ 75 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 77 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 77 SEDE: ORO VERDE ............................................................................................................................................................. 77 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 77 UNIDAD 6 .............................................................................................................................................................. 77 INTRODUCCIÓN AL ............................................................................................................................................ 77 LENGUAJE C++ ..................................................................................................................................................... 77 1
BREVE HISTORIA DE C++ ................................................................................................................................... 78 ESTRUCTURA DE UN PROGRAMA C++ ............................................................................................................ 79 COMO AGREGAR COMENTARIOS Y DOCUMENTACIÓN INTERNA ........................................................................ 79 ELEMENTOS (TOKENS) DE UN PROGRAMA C++ .......................................................................................... 79 TIPOS DE DATOS ESTÁNDAR DE C++ ............................................................................................................. 80 NOTACIÓN Y DEFINICIÓN DE CONSTANTES EN C++ .................................................................................. 81 DECLARACIÓN E INICIALIZACIÓN DE VARIABLES ...................................................................................... 83 ENTRADA Y SALIDA ............................................................................................................................................ 85 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS .............................................................................................................. 88 FACULTAD DE CIENCIA Y TECNOLOGÍA ....................................................................................................................... 88 SEDE: ORO VERDE ............................................................................................................................................................. 88 FUNDAMENTOS DE PROGRAMACIÓN ............................................................................................................. 88 UNIDAD 7 .............................................................................................................................................................. 88 OPERADORES Y ................................................................................................................................................... 88 ESTRUCTURAS DE CONTROL EN C++ ........................................................................................................... 88 INTRODUCCIÓN ................................................................................................................................................... 89 EXPRESIONES ....................................................................................................................................................... 89 OPERADORES ....................................................................................................................................................... 89 SENTENCIA COMPUESTA O BLOQUE .............................................................................................................. 94 ESTRUCTURAS DE CONTROL ............................................................................................................................ 95 WHILE .................................................................................................................................................................... 95 DO-‐WHILE ............................................................................................................................................................ 95 FOR ......................................................................................................................................................................... 95 IF-‐ELSE ................................................................................................................................................................... 95 SWITCH ................................................................................................................................................................. 95 BREAK .................................................................................................................................................................... 95 CONTINUE ............................................................................................................................................................. 95 WHILE (EXPRESIÓN LÓGICA ) ....................................................................................................................... 95 { ................................................................................................................................................................................ 95 ACCIONES .............................................................................................................................................................. 95 } ................................................................................................................................................................................ 95 INT A=0; ................................................................................................................................................................ 95 WHILE ( A<100 ) ................................................................................................................................................ 95 { ................................................................................................................................................................................ 95 COUT << A<< “\N”; ............................................................................................................................................. 95 A++; ........................................................................................................................................................................ 95 } ................................................................................................................................................................................ 95 DO ........................................................................................................................................................................... 95 { ................................................................................................................................................................................ 95
2
ACCIONES .............................................................................................................................................................. 95 } WHILE (EXPRESIÓN LÓGICA ); .................................................................................................................... 95 INT B=0; ................................................................................................................................................................ 95 DO ........................................................................................................................................................................... 95 { ................................................................................................................................................................................ 95 B++ ; ....................................................................................................................................................................... 95 COUT << B<< “\N” ; ............................................................................................................................................ 95 } WHILE ( B<100 ); ............................................................................................................................................ 95 FOR (EXP1; EXP2; EXP3) ................................................................................................................................ 96 { ................................................................................................................................................................................ 96 ACCIONES .............................................................................................................................................................. 96 } ................................................................................................................................................................................ 96 INT A=0; ................................................................................................................................................................ 96 FOR ( A=0 ; A<100 ; A++ ) ................................................................................................................................ 96 COUT << A<< “\N” ; ............................................................................................................................................ 96 INT I, J; ................................................................................................................................................................... 96 FOR (I=0, J=10; I < 10 ; I++, J-‐-‐) ...................................................................................................................... 96 COUT << I << “ “ << J << ENDL; ....................................................................................................................... 96 IF (EXPRESIÓN LÓGICA) .................................................................................................................................. 96 ACCIÓN1; ELSE ............................................................................................................................................... 96 ACCIÓN 2; .............................................................................................................................................................. 96 INT C=0; ................................................................................................................................................................. 96 IF ( C==200 ) ........................................................................................................................................................ 96 C = C/2; .................................................................................................................................................................. 96 ELSE C = 2*C; ....................................................................................................................................................... 96 SWITCH (EXPRESIÓN ) ..................................................................................................................................... 97 { ................................................................................................................................................................................ 97 CASE VALOR1: ACCIÓN_1; ................................................................................................................................ 97 BREAK; .................................................................................................................................................................. 97 CASE VALOR2: ACCIÓN_2; ................................................................................................................................ 97 BREAK; .................................................................................................................................................................. 97 CASE VALOR3: ACCIÓN_3; ................................................................................................................................ 97 BREAK; .................................................................................................................................................................. 97 .................... .............................................................................................................................................................. 97 DEFAULT: ACCIÓN_M; ..................................................................................................................................... 97 } ................................................................................................................................................................................ 97 SWITCH ( M ) ....................................................................................................................................................... 97 { ................................................................................................................................................................................ 97 3
CASE 1: M++; ........................................................................................................................................................ 97 BREAK; .................................................................................................................................................................. 97 CASE 2: M=2*M; .................................................................................................................................................. 97 BREAK; .................................................................................................................................................................. 97 CASE 3: M = M / 2; .............................................................................................................................................. 97 BREAK; .................................................................................................................................................................. 97 DEFAULT : M = 100; ........................................................................................................................................... 97 BREAK; .................................................................................................................................................................. 97 } ................................................................................................................................................................................ 97 INT A=0; ............................................................................................................................................................... 97 WHILE (A<5) ........................................................................................................................................................ 97 { ................................................................................................................................................................................ 97 A++; ........................................................................................................................................................................ 97 IF A == 4 BREAK; .............................................................................................................................................. 97 COUT << A; ........................................................................................................................................................... 97 } ................................................................................................................................................................................ 97 INT A=0; ............................................................................................................................................................... 97 WHILE (A<5) ........................................................................................................................................................ 97 { ................................................................................................................................................................................ 97 A++; ........................................................................................................................................................................ 97 IF A == 4 CONTINUE; ....................................................................................................................................... 97 COUT << A; ........................................................................................................................................................... 97 } ................................................................................................................................................................................ 97 COUT<<“DESEA CONTINUAR OPERANDO CON EL PROGRAMA (S/N)?”; .......................................... 98 CIN >> RESP ; ....................................................................................................................................................... 98 RESP = TOUPPER( RESP ); // PASA A MAYÚSCULAS .............................................................................. 98 IF (RESP==´S´) EXIT(0); ................................................................................................................................... 98 ANIDAMIENTO DE ESTRUCTURAS DE CONTROL ................................................................................................ 99 FUNCIONES DE BIBLIOTECA DE C++ ........................................................................................................... 100 #INCLUDE <IOSTREAM.H> ........................................................................................................................... 100 #INCLUDE <MATH.H> // ARCHIVO CON EL PROTOTIPO DE SIN(X)Y M_PI ................................ 100 INT MAIN ( ) { .................................................................................................................................................. 100 INT ANG; ............................................................................................................................................................. 100 COUT << “INGRESE UN ÁNGULO EN GRADOS:”; ..................................................................................... 100 CIN >> ANG; ....................................................................................................................................................... 100 FLOAT ANGR = ANG*M_PI/180; // PASA A RADIANES EL ÁNGULO ................................................. 100 COUT << “EL SENO DEL ÁNGULO ES:”<< SIN(ANGR); .......................................................................... 100 RETURN 0; } ...................................................................................................................................................... 100
4
UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS ........................................................................................................... 101 FACULTAD DE CIENCIA Y TECNOLOGÍA .................................................................................................................... 101 SEDE: ORO VERDE .......................................................................................................................................................... 101 FUNDAMENTOS DE PROGRAMACIÓN .......................................................................................................... 101 UNIDAD 8 ........................................................................................................................................................... 101 FUNCIONES ........................................................................................................................................................ 101 INTRODUCCIÓN ................................................................................................................................................ 102 FUNCIONES EN C++ .......................................................................................................................................... 105 RETURN(W); ..................................................................................................................................................... 105 } ............................................................................................................................................................................. 105 DECLARANDO Y DEFINIENDO FUNCIONES EN C++. ................................................................................ 106 RESULTADOS DE UNA FUNCIÓN C++ ........................................................................................................... 106 RETURN W; ....................................................................................................................................................... 106 } ............................................................................................................................................................................. 106 } ............................................................................................................................................................................. 106 COUT << “EL PROMEDIO ES:” << W << ENDL; ........................................................................................ 106 } ............................................................................................................................................................................. 106 INTERCAMBIO DE INFORMACIÓN DESDE FUNCIONES C++ ................................................................... 107 SOBRECARGA DE FUNCIONES ....................................................................................................................... 110 OPERACIONES DE ENTRADA Y SALIDA EN FUNCIONES ......................................................................... 111 RECURSIVIDAD .................................................................................................................................................. 111 SÍNTESIS ............................................................................................................................................................. 113 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS ........................................................................................................... 114 FACULTAD DE CIENCIA Y TECNOLOGÍA .................................................................................................................... 114 SEDE: ORO VERDE .......................................................................................................................................................... 114 FUNDAMENTOS DE PROGRAMACIÓN .......................................................................................................... 114 UNIDAD 9 ........................................................................................................................................................... 114 ARRAYS Y STRUCTS ........................................................................................................................................ 114 INTRODUCCIÓN ................................................................................................................................................ 115 DEFINICIÓN DE ARREGLO .............................................................................................................................. 115 DECLARACIÓN E INICIALIZACIÓN DE UN ARREGLO ................................................................................ 116 RETURN 0; ......................................................................................................................................................... 118 } ............................................................................................................................................................................. 118 ARREGLOS COMO PARÁMETROS DE FUNCIONES .................................................................................... 120 ESTRUCTURAS. EL TIPO STRUCT. ................................................................................................................. 122 PROCESAMIENTO DE UNA VARIABLE STRUCT ......................................................................................... 125 TIPOS DEFINIDOS POR EL USUARIO: TYPEDEF ........................................................................................ 126 SÍNTESIS ............................................................................................................................................................. 127 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS ........................................................................................................... 128 FACULTAD DE CIENCIA Y TECNOLOGÍA .................................................................................................................... 128 SEDE: ORO VERDE .......................................................................................................................................................... 128
5
FUNDAMENTOS DE PROGRAMACIÓN .......................................................................................................... 128 UNIDAD 10 ........................................................................................................................................................ 128 BÚSQUEDA Y ORDENAMIENTO .................................................................................................................. 128 INTRODUCCIÓN ........................................................................................................................................................... 129 BÚSQUEDA ...................................................................................................................................................................... 129 ORDENAMIENTO .......................................................................................................................................................... 134 MÉTODOS DIRECTOS DE ORDENAMIENTO ........................................................................................... 134 METODOS DE ORDENAMIENTO AVANZADOS ...................................................................................... 139 UNIVERSIDAD AUTÓNOMA DE ENTRE RÍOS ........................................................................................................... 143 FACULTAD DE CIENCIA Y TECNOLOGÍA .................................................................................................................... 143 SEDE: ORO VERDE .......................................................................................................................................................... 143 FUNDAMENTOS DE PROGRAMACIÓN .......................................................................................................... 143 UNIDAD 11 ........................................................................................................................................................ 143 ARCHIVOS .......................................................................................................................................................... 143
6
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 1 Noción de Algoritmo
7
UADER- FCyT -- UNIDAD 1 Noción de Algoritmo RESOLUCIÓN DE PROBLEMAS COMPUTACIONALES En la vida diaria nos enfrentamos continuamente a problemas que debemos resolver en lo posible felizmente. Así como cada individuo tiene formas de encarar un problema y su propia manera de solucionarlo, computacionalmente hablando podemos hacer un paralelo. Ante la presentación de un problema encarar la mejor forma de resolverlo para arribar al resultado esperado y correcto es un desafío. Para ello debemos comprender exactamente qué se pide, qué resultados se pretenden y que restricciones y/o condiciones existen. Para realizar lo antes dicho dividiremos la resolución de un problema en etapas, las cuales enunciamos y definimos a continuación.
ETAPAS PARA LA RESOLUCIÓN DE PROBLEMAS a. Definición del problema Está dada por la formulación del problema en forma correcta y completa. Esta enunciación de lo que se desea es primordial para el éxito de la resolución. b. Análisis del problema A partir del estudio del problema se deberá identificar y conocer las partes principales del mismo y de esa manera determinar los siguientes conjuntos: • de DATOS : es la información con que contamos para resolver el problema. • de RESULTADOS : es lo que se desea obtener. • de CONDICIONES: una o más relaciones que vinculan los dos conjuntos anteriores y que permitirán plantear la solución del problema. c. Programación Esta etapa consiste en obtener la solución del problema dado. Se divide en dos subetapas: c.1. Elección y creación del método Se trata de buscar un procedimiento o método general que permita resolver el problema planteado utilizando una computadora. Es muy factible que se encuentren varios métodos para hacerlo, lo importante es determinar la “mejor alternativa”, de acuerdo a distintos parámetros que se establezcan para esta selección. Esta puede ser la que produzca los resultados esperados en el menor tiempo y al menor costo o sólo en el menor tiempo u otras. c.2. Codificación Consiste en expresar el método elegido en un lenguaje, llamado lenguaje de programación, que pueda ser interpretado por la computadora. Esta subetapa será objeto de estudio en años superiores. d. Prueba Esta etapa consiste en la ejecución del código del método elegido, es decir, suministrar los datos al computador, y obtener los resultados. Luego se analizarán los mismos determinando si son realmente los esperados. Caso contrario, deberán analizarse las etapas previas, comenzando por la última hacia atrás, y realizar las modificaciones necesarias, repitiendo este proceso hasta obtener los resultados esperados. Observemos gráficamente las etapas descriptas
8
Resolución de problemas
Definición del problema
Programación
Análisis del problema Elección y creación del método
Prueba
Codificación
La etapa de elección y creación del método se puede dividir a su vez en el diseño de la estrategia y la definición del algoritmo, y puede graficarse de la siguiente manera:
Elección y creación del método
Definición del algoritmo
Diseño de la estrategia
Ahora definamos el concepto de estrategia y de algoritmo.
ESTRATEGIA El diseño de la estrategia consiste en encontrar un método que nos permita llegar a resolver el problema planteado. Como primer paso de esta etapa, debemos preparar un plan o esquema general de las tareas que deben realizarse para llegar a la solución. Este esquema se denomina estrategia y debe ser una lista de QUÉ hacer. ¿Cómo se diseña una estrategia? Por lo dicho, diseñar una estrategia consiste en dividir o descomponer el problema original en una sucesión de problemas más simples, de tamaño suficientemente pequeño como para que cada uno de ellos pueda ser comprendido en su totalidad. Ésto, permitirá atacar la solución de cada problema simple por separado e independientemente de los demás, volviendo a aplicar este enfoque a cada uno de los subproblemas hasta llegar a subproblemas de solución simple. Una vez que todos ellos han sido resueltos, se puede decir que el problema original ha sido resuelto. Este proceso de descomposición de un problema partiendo de la formulación completa del problema hasta llegar a problemas elementales de simple solución, se llama diseño descendente, también conocido como top-down, método de refinamiento sucesivo o diseño compuesto.
9
Gráficamente, dado el problema P lo dividiremos en subproblemas Pi. Cada subdivisión implica un descenso de nivel.
nivel 0
P
P1
P2
P3 P31
P4
P32
P33
nivel 1
nivel 2
Cada Pi representa un enunciado o subproblema. Para cada uno existen 2 posibilidades: Ø que Pi sea un subproblema o una tarea simple, dando por finalizada la descomposición Ø que Pi sea un subproblema o una tarea compuesta y por lo tanto sea posible su descomposición en una nueva secuencia de subproblemas Las características generales de este tipo de diseño se basan en: Ø ir de lo general a lo particular Ø no existe una única descomposición de subproblemas Ø en cada nivel puede verificarse que el esquema sea el correcto Finalmente se realiza un trabajo de recomposición del esquema completo, resolviendo cada subproblema hasta lograr la solución del problema. El diseño de una estrategia y su posterior refinamiento, constituyen las etapas más creativas y quizás más dificultosas de todo el proceso de resolución de un problema.
ALGORITMO Planteada una estrategia indicando QUÉ tareas hacer, debemos especificar una lista detallada de CÓMO hacerlas, llegando así a definir una solución paso a paso del problema llamada algoritmo. La descripción de la solución detallada por medio de un algoritmo constituye el segundo paso en la etapa de elección del método. La palabra algoritmo se utiliza, en general, como sinónimo de procedimiento, método o técnica. Pero en el área de computación tiene un significado más específico. Un algoritmo es un conjunto finito de operaciones (instrucciones - pasos) que seguidos en un determinado orden permiten resolver un tipo de problema. Las características principales de un algoritmo son: Ø Finito: permite arribar a la solución de un problema después de la ejecución de un número finito de pasos. Ø Definido: cada paso debe ser enunciado en forma clara y precisa, y no debe dar lugar a ambigüedades. Para los mismos datos el algoritmo debe dar siempre los mismos resultados Ø General: la solución debe ser aplicable a un tipo de problemas y no a un problema particular.
10
Teniendo en cuenta las características mencionadas previamente podemos decir que: un algoritmo es una secuencia ordenada y finita de pasos que constituyen un método general para resolver un tipo de problemas. Es de notar que esta definición, se refiere a ‘...resolver un tipo de problemas .....’ y no hace hincapié en el uso del computador como herramienta para su resolución. Esto se debe a que el concepto de algoritmo se aplica a problemas computacionales que van a ser resueltos por medio de un computador y a problemas no computacionales, en cuya resolución no interviene esta herramienta. En ambos casos el lenguaje usado en la descripción del algoritmo debe ser comprensible para el destinatario o para quien lo va a ejecutar. Por lo visto, para cualquier problema para el que pueda especificarse un método finito de solución puede definirse un algoritmo. Ejemplos que se pueden presentar en la vida diaria: •
una receta de cocina
•
las instrucciones para utilizar un aparato electrónico
•
el camino para llegar a un lugar determinado desde un punto de partida
Ejemplos de algoritmos computacionales: •
Calcular los sueldos de los empleados de una empresa
•
Actualizar el stock de un comercio
•
Calcular las raíces de una ecuación
Desarrollemos el siguiente ejemplo de la vida diaria Problema: Preparar un taza de café instantáneo El grado de detalle que deberemos usar en la definición del método, dependerá de la persona que sea la ejecutante de la solución. Si el ejecutante es un ama de casa, probablemente con el enunciado sea suficiente, pero si se trata de alguien que nunca preparó un café podríamos detallar los siguientes pasos: PROCESO Cafe1 − Calentar una taza de agua sin llegar al punto del hervor; − Poner en un taza tres cucharaditas de azúcar, dos de café instantáneo y media cucharadita de soda; − Batir hasta que la mezcla se torne marrón claro; − Llenar con el agua caliente la taza; − Revolver para disolver la mezcla en el agua FINPROCESO
Obsérvese que para indicar el inicio y el fin del algoritmo se han utilizado las palabras PROCESO Y FINPROCESO respectivamente y que los pasos han sido lo suficientemente simples para un principiante en el arte de preparar café.
11
Otro aspecto que es importante considerar es que contamos con una serie de elementos para poder preparar el café como por ejemplo: recipiente para calentar el agua, azúcar, café, cucharita, taza, soda. Supongamos que no se tiene la certeza de que en el momento de hacer el café se tenga soda, por ende, este elemento se podrá reemplazar con agua, con lo cual el algoritmo será: PROCESO Cafe2 −
Calentar una taza de agua sin llegar al punto del hervor;
−
Poner en un taza tres cucharaditas de azúcar , dos de café instantáneo
−
SI se tiene soda
−
ENTONCES agregar en la taza media cucharadita de soda SINO agregar en la taza media cucharadita de agua fría FINSI
−
Batir hasta que la mezcla se torne marrón claro;
−
Llenar con el agua caliente la taza;
−
Revolver para disolver la mezcla en el agua
FINPROCESO
Las dos primeras instrucciones se ejecutan una a continuación de otra, luego se presentan dos alternativas: o se agrega media cucharadita de soda o se agrega media cucharadita de agua fría. Para describirlas se ha usado las palabras SI ENTONCES SINO FINSI que se analizarán en detalle más adelante. En este caso el algoritmo cubre ya mayor cantidad de posibilidades, no previstas en la versión anterior. A partir de esto se pueden realizar las siguientes observaciones: Ø El algoritmo debe estar compuesto por acciones tales que el ejecutante sea capaz de realizar Ø El algoritmo debe ser enunciado en un lenguaje comprensible para el ejecutante, hombre o computador. En este último caso, estará restringido a un juego de instrucciones perfectamente determinado. Ø El algoritmo deberá representar todo el conjunto de posibles resultados del problema, inclusive el caso de que no tenga solución Ø Para un mismo problema se pueda describir más de un algoritmo y con cualquiera de ellos se deberá llegar a la/s misma/s solución/es; un algoritmo será más eficaz que otro. La eficacia del algoritmo depende de los recursos con que se cuente y los factores que se consideren: costos, tiempo, etc. Ejemplo de resolución de problemas de la vida cotidiana Ejemplo: Preparar un licuado de frutas Recursos: Licuadora. Fruta con cáscara. Taza con leche. Taza con azúcar. Cuchillo. Plato. Todos los elementos están sobre la mesada. Se cuenta con las medidas necesarias de todos los ingredientes.
12
Algoritmo: PROCESO Licuado − Tomar el vaso de la licuadora
−
Tomar la taza con el azúcar
− Colocar el vaso en la base
−
Colocar el azúcar en el vaso
− SI la licuadora no está enchufada
−
Dejar la taza del azúcar sobre la mesada
−
Tapar el vaso
−
Mover la perilla de encendido hacia la derecha
−
REPETIR
ENTONCES enchufarla − FINSI − Tomar el cuchillo − REPETIR tomar la fruta pelarla cortarla sobre el plato colocar la fruta cortada en el vaso
esperar
− HASTAQUE no haya más frutas − Dejar el cuchillo
−
HASTAQUE la mezcla esté licuada
−
Mover la perilla de encendido hacia la izquierda
FINPROCESO
− Tomar la taza con la leche − Echar la leche en el vaso − Dejar la taza de la leche sobre la mesada
En este caso ciertas acciones como la de Tomar la fruta, pelarla, cortarla, colocar..... se repiten mientras se tiene fruta para hacerlo. Aparecen aquí las palabras REPETIR y HASTAQUE, que veremos en capítulos posteriores.
FORMALIZACIÓN Formalizaremos algunos conceptos vistos anteriormente. Hemos mencionado que la forma de enunciar la solución a un problema planteado depende del ejecutante o también llamado procesador. Por lo tanto llamaremos así a toda entidad capaz de entender un enunciado y ejecutar los pasos descriptos en un algoritmo. Si bien en los ejemplos vistos el ejecutante se trataba de una persona en la resolución de problemas computacionales debemos pensar que el procesador será la computadora. También hemos notado que para poder realizar su tarea el ejecutante debe contar con los recursos adecuados. El conjunto de estos recursos existentes en el momento de la ejecución de un trabajo constituye el ambiente del problema. El método que se elija para proponer la solución de un tipo de problema depende del ejecutante y de los recursos o elementos con que se cuenta (ambiente). Cuando definimos algoritmo hemos hablado de un conjunto de pasos o acciones. Una acción es un evento que modifica el ambiente y puede ser: Ø Primitiva Ø No-primitiva Una acción es primitiva cuando para un ejecutante dado su enunciado es suficiente para que pueda ser ejecutada sin información adicional. Una acción no-primitiva es aquella que puede ser descompuesta en acciones primitivas para un ejecutante dado. También hemos visto que en los ejemplos se nos presentan situaciones que indican alternativas: “SI se tiene soda ...”, esta no es una acción porque no modifica el ambiente, pero
13
son elementos que el ejecutante debe saber interpretar. A estos enunciados se los denomina condición. Por lo tanto: Una condición es una afirmación lógica sobre el estado de algún recurso del ambiente, que puede tomar valor verdadero o falso en el momento de la observación. El ejecutante determina en el momento de la ejecución del algoritmo las acciones a seguir, dependiendo de que la condición sea satisfecha o no.
PROGRAMACIÓN MODULAR Es un método de diseño y tiende a dividir el problema en partes perfectamente diferenciadas que puedan ser analizadas, resueltas y puestas a punto por separado. Para atacar el análisis de un problema, y siguiendo el diseño Top-Down, se pueden utilizar criterios de programación modular para dividirlos en partes independientes, probando cada uno por separado y realizando su recomposición ascendente. Cada una de las partes independientes se llama Módulo y para su determinación se deben tener en cuenta los siguientes criterios: Ø un módulo debe corresponder a una función lógica perfectamente bien definida. Ø los módulos deben ser pequeños para que sean claros y de poca complejidad. Ø un módulo debe tener una estructura de caja negra, es decir la salida debe ser exclusivamente función de la entrada. Ø cada módulo deber tener una única entrada y una única salida. Objetivos de la programación modular La programación modular tiende a: Ø disminuir complejidad: disminuye la complejidad del problema original, dividiendo un problema en partes más simples. Ø aumentar la claridad: el problema original es planteado ahora como una sucesión de módulos que resulta más fácil de comprender inclusive para terceras personas. Ø aumentar la fiabilidad: como consecuencia de los dos puntos anteriores, aumenta la confiabilidad en todo proceso de resolución. Ø facilitar modificaciones y conexiones: cada módulo puede realizarse y probarse por separado, minimizándose los problemas de puesta a punto al final.
14
Facultad de Ciencia y Tecnología - Universidad Autónoma de Entre Ríos Cátedra:
Fundamentos de Programación
GUÍA DE TRABAJOS PRÁCTICOS NRO. 1 Temas:
Constantes, Variables, Expresiones, Asignaciones, Leer y Escribir.
1. Analice el valor de verdad de cada una de las siguientes expresiones. Justifique su respuesta. a) La constante mantiene siempre su valor a lo largo del algoritmo. b) Una variable es un lugar de memoria. c) El nombre de una variable debe estar relacionado con su contenido. d) El tipo de variable se define por su contenido. Si el contenido se modifica en el transcurso del algoritmo, puede cambiar el tipo. e) Una variable puede almacenar una expresión. f) El nombre de una variable será correcto siempre que el mismo comience con un número o una letra. g) Resultado y RESULTADO son variables distintas. h) ´JUAN´ y JUAN son variables distintas. i) En una expresión las sumas y restas se resuelven primero. j) Una función no puede participar en el argumento de otra función. k) Las palabras reservadas se escriben siempre con mayúsculas. l) Una cadena de caracteres hay que encerrarlas entre apóstrofos. 2. Complete con una de las opciones propuestas entre paréntesis: Las siguientes ...........................(variables / constantes) son .................... (iguales / diferentes). - ALTO - AlTo - AltO Las siguientes ...........................(variables / constantes) son .................... (iguales / diferentes). - ‘ALTO’ - ‘AlTo’ - ‘AltO’ 3. Dados los siguientes contenidos para las variables A, B, C, D, E, F; analice las expresiones en que intervienen y encuentre en la lista de opciones el resultado correcto de la expresión. A 3
B ‘ÁBC’
C ‘JOSE’
D V
E 97.9
F ‘87’
a) ( A + C ) ↑ 2
b) TRUNC( E ) >= REDON( E )
c) 'ER' < A
e) ( B < C ) ^ F
f) ( C <> 'F' ) ^ ( A < 4 )
g) ( E < F ) h) TRUNC( ( A + E ) / 2 )+5
Resultados posibles:
V
|
F
|
Expresión Inválida
15
|
55
d) ( B = ‘XA’ ) v ( A = E )
|
4. Escribir las expresiones algorítmicas correspondientes a las siguientes expresiones algebraicas.
5. Decir si las siguientes proposiciones son correctas. Diga qué representan y justifique su respuesta Area – 2 ← TRUNC( B * H ) / 2
Redon ← ( LM * 10 + LME * 10 ) * H
ABC ← 980 < '980'
X ← ( ABS ( A – B ) ) < ( X – 3 )
AB12 ← AB12 + 1
‘AREA’ ← 3.14 * Radio * RADio
TAM ← ( Tam*10 )*H / 2
MUL ← (5 x 9) + N ↑ 4
6. Analice el valor de verdad de cada una de las siguientes expresiones. Justifique su respuesta. a) A la izquierda del símbolo de asignación puede ir una variable. b) La asignación X ← X + 2 carece de sentido porque no existe ningún número que incrementado en dos unidades sea igual a sí mismo. c) La acción de escritura destruye el contenido de las variables que utiliza. d) En una única acción de lectura se pueden leer dos o más datos. e) En una acción de lectura el primer valor ingresado se almacena en la variable que sigue a la palabra LEER. 7. Ordene la serie de acciones siguientes para obtener un algoritmo que permita resolver una ecuación de segundo grado, suponiendo que sólo admite raíces reales. Leer a, b, c T ← 2*a Escribir ‘Las raíces de la ecuación son’ S1 ← (-1 * b + W) / T S2 ← (-1 * b – W) / T
Escribir S1, S2 W ← RC(b ↑ 2 – 4 * a * c) Proceso Raíces FinProceso Escribir ‘ Ingrese los coeficientes de la ecuación’
8. Dado el siguiente algoritmo realizar el seguimiento del mismo. a) Con los datos: 26, 5, 2007, ‘Jorge Gómez’, 500, 150, 120. b) Con los datos: 15, 10, 2008, ‘Carlos Oviedo’, 850, 600, 250.
16
Proceso Liquidación Leer DIAACT, MESACT, ANIOACT; Leer NOM, DEUDA, PAGO1, PAGO2; PAGO ← PAGO1 + PAGO2; SALDO ← DEUDA – PAGO; DESC ← SALDO * 0.10; SALDO ← SALDO – DESC; Escribir ‘Fecha: ‘, DIAACT, ‘/’, MESACT, ‘/’, ANIOACT; Escribir ‘Cliente: ‘, NOM, ‘Deuda Total: $ ‘, DEUDA; Escribir ‘Pagos realizados: $ ‘, PAGO; Escribir ‘Descuento 10%: $ ‘, DESC; Escribir ‘Saldo a pagar: $ ‘, SALDO FinProceso 9. Realizar ambiente y algoritmo de cada uno de los siguientes enunciados: a) Calcular e informar el perímetro de un cuadrado conociendo el valor del lado. b) Una remisera desea liquidar el sueldo de los choferes de una de sus unidades para ello se ingresan los datos de los 2 choferes de la misma: nombre y apellido, sueldo básico y km. recorridos en el mes a liquidar. Primero se ingresan los datos del chofer 1, y luego los datos del chofer 2. Se desea generar un informe como el siguiente: LIQUIDACION MENSUAL CHOFERES NOMBRE DEL CHOFER 1.............................. NOMBRE DEL CHOFER 2.............................. TOTAL GRAL $......................
TOTAL A COBRAR $.................. TOTAL A COBRAR $..................
Observación: Tener en cuenta que por cada km. se le paga $7.5 y que el total a cobrar se calcula como: Sueldo básico + monto por kms. 10. Completar pseudocódigo y ambiente. Una empresa periodística desea facturar cada aviso clasificado que se publica en el día. Por cada aviso publicado se conoce la cantidad de palabras que contiene. El importe del aviso se cobra por palabra. El importe de cada palabra publicada es de $ 0,50. AMBIENTE Variable
Num.
Carac.
Lóg.
Clase
Significado
Proceso AVISO Leer CANTPAL; TOTAL ← …………………………………………; Escribir ‘Diario de la Provincia’; Escribir ‘Cantidad de palabras: ‘, …………………………….; Escribir ‘Total a abonar: $ ‘, …………………………… FinProceso
17
Dados los siguientes enunciados realizar ambiente y pseudocódigo. 11. En un recital se vendieron dos tipos de entradas, a saber: popular y platea. El éxito del recital se ocasionó porque se lograron vender la totalidad de las plateas y de las populares, 1000 y 3000 respectivamente. El precio de la popular fue un 50 % más barato que el de la platea. Hallar la recaudación total del recital, sabiendo que se ingresa como primer dato el precio de la platea. 12. Una empresa que comercializa artefactos electrodomésticos posee 2 sucursales. De cada una de ellas se conocen los montos de ventas semestrales realizadas durante el año 2009. Estos datos se ingresan ordenados por sucursal y por semestre. Cada sucursal destinó el 20% del total de sus ventas para pagar una bonificación a sus empleados; monto que se repartió en partes iguales entre ellos. Se ingresan también, la cantidad de empleados que tenían las sucursales en el 2009. Determinar e informar: a. El total de ventas de cada sucursal. b. La bonificación que pagó cada sucursal a cada empleado. 13. Un avión realiza su recorrido partiendo del aeropuerto A, luego se dirige al B, y de allí al C y culmina su recorrido nuevamente en A. Se conocen como datos las coordenadas de los puntos A (Xa,Ya), B(Xb,Yb) y C(Xc,Yc). Se pide: a. Calcular la distancia que existe entre A y B, entre B y C y entre C y A. b. Calcular e informar la distancia total que debe recorrer el avión. La distancia se debe calcular en base a la siguiente fórmula: D= (X2-X1)2 + (Y2-Y1)2 14. Una línea de colectivos presta los siguientes servicios: Común, Estudiante y Trabajador. Los estudiantes y los trabajadores abonan el 50 % y el 40 % del costo de un boleto común, respectivamente. Se desea obtener cantidad de boletos vendidos según el servicio y total recaudado. Para resolver el problema se dispone de las numeraciones iniciales y finales de los boletos de cada uno de los servicios, además se conoce al inicio el precio del boleto estudiante. 15. La liquidación del consumo telefónico de una línea familiar tiene en cuenta un abono fijo con el cual el usuario puede utilizar 600 pulsos. El exceso de pulsos se liquida a razón de $0,035 por cada pulso de más. Se conocen como datos: el monto del abono fijo, la cantidad de pulsos consumidos totales (mayor de 600) y la cantidad de pulsos utilizados en Internet. Estos últimos se liquidan a tarifa reducida del 40 % del costo del pulso normal. Como primer dato, se conoce el número de teléfono. Se desea obtener un informe como el siguiente: NÚMERO DE TELÉFONO: ……………............. ABONO FIJO: $ ....................... RECARGO: $ ........................... CANTIDAD DE PULSOS EXCEDENTES: .............. INTERNET: $............................ TOTAL: $ ................................
18
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 2 Formalización de Algoritmos
19
UADER-‐ FCyT -‐-‐ UNIDAD 2 Formalización de Algoritmos ALGORITMOS COMPUTACIONALES Los problemas desarrollados hasta el momento, se resolvieron empleando instrucciones coloquiales y se basaban en situaciones de la vida diaria. Los algoritmos así desarrollados son fáciles de entender para cualquier persona o ejecutante. Pero nuestro objetivo es llegar a desarrollar algoritmos que puedan ser interpretados por una computadora. Para ello, es necesaria una descripción clara y carente de ambigüedades de cada una de las acciones que llevan a la solución del problema, por medio de órdenes comprensibles para la computadora. En este capítulo nos ocuparemos de describir la formalización necesaria para el desarrollo de Algoritmos Computacionales. De aquí en más cuando mencionemos al ejecutante de un algoritmo, nos estaremos refiriendo concretamente a una computadora. En el siguiente ejemplo planteamos un algoritmo completo de acuerdo a la formalización que propondremos posteriormente. Ejemplo: Plantear un algoritmo computacional que calcule la hipotenusa de un triángulo rectángulo. Se conocen las longitudes de los catetos. Análisis del problema: Ø Datos: Longitudes de los catetos Ø Resultados: Hipotenusa Ø Relación: Teorema de Pitágoras Algoritmo:
PROCESO: Hipotenusa Leer A, B; H ß RC( A ↑ 2 + B ↑ 2); Escribir ‘Hipotenusa = ‘; Escribir H FINPROCESO
En este ejemplo A, B y H constituyen variables; 2 e 'Hipotenusa = ' son constantes; LEER, ESCRIBIR y ß son las acciones primitivas de lectura, escritura y asignación respectivamente; RC (A ↑ 2 + B ↑ 2) es una expresión numérica y RC ( ) es la función raíz cuadrada. El signo ; (punto y coma) es el separador de acciones. En esta unidad iremos desarrollando todos estos elementos, que conforman un lenguaje algorítmico que llamaremos PSEUDOCODIGO. La forma general de un algoritmo escrito en pseudocódigo es la siguiente:
20
PROCESO <nombre del proceso> acción 1; acción 2; acción 3; : acción n-1; acción n FINPROCESO
Donde las acciones van separadas por el signo punto y coma (;) y pueden ir varias acciones en una misma línea.
CONSTANTES, VARIABLES Y EXPRESIONES Definimos constante, como un elemento cuyo valor no puede alterarse en el transcurso de la ejecución de un algoritmo. Por ejemplo: 123, 'López', 3.14459 Pero además en un algoritmo existen otros elementos cuyo valor cambia durante la ejecución del mismo, llamados variables. En el ejemplo inicial A, B y H son variables -correspondientes a los catetos y a la hipotenusa del triángulo, respectivamente- que adquieren un valor en el momento de la ejecución del algoritmo. Una variable es un elemento o lugar asociado a un valor que puede variar conforme se ejecuta el algoritmo, se representa por un nombre que identifica a una posición de memoria donde puede asignarse o almacenarse un único valor por vez. Para proponer el nombre de una variable observaremos tres reglas simples: 1) Utilizar sólo letras y/o dígitos, comenzando siempre con una letra. 2) No utilizar las palabras claves o reservadas en el pseudocódigo, como: LEER, ESCRIBIR, PROCESO, FINPROCESO, etc.; o para las funciones internas: RC, SEN, TRUNC, LN, etc. 3) No hacer distinción entre mayúsculas y minúsculas. Esto implica que VENTA, venta y Venta, constituyen en el algoritmo la misma variable. Esta sintaxis y sus restricciones no presentan inconvenientes para proponer nombres de variables, pues disponemos de un sinnúmero de combinaciones diferentes de letras y dígitos. Por ejemplo: NOMBRE, DIRECCION, Res1, MONTO. Ejercicio: En los siguientes ejemplos de variables, indique si son válidas; caso contrario especifique la causa: a) venta
b) x12
c) (total)
d) resultado
e) *PRODU
f) promedio
El diseñador del algoritmo tiene total libertad para proponer nombres a sus variables, aunque como consejo, es conveniente proponer identificadores que tengan alguna relación con el dato que representan. En nuestro ejemplo inicial, podríamos haber empleado CATETO1, CATETO2, HIPOT, en lugar de A, B, H.
21
Por último: Definimos expresión a un conjunto de operandos ligados por operadores, que describen una operación o cálculo arrojando un único resultado. En nuestro primer ejemplo RC (A ↑ 2 + B ↑ 2) es una expresión que permite obtener el valor de la hipotenusa. Algunos ejemplos de expresiones: 1) 2+a-x*5,
2) A < B,
3) TRUNC( R ) + 1
TIPOS DE DATOS Un algoritmo computacional puede emplear los siguientes tipos de datos: Ø Numérico Ø Caracter Ø Lógico Esta clasificación nos define los tipos primitivos de datos. Estudiaremos a cada uno de ellos y su modo de empleo.
Tipo Numérico Es el conjunto formado por los valores numéricos que pueden incluir un punto decimal y pueden estar precedidos por los signos '+' o '-'. La ausencia de signo implica un valor positivo. Se clasifican a su vez en tipo entero o tipo real, pero no haremos distinciones en su empleo. Los datos de tipo numérico pueden representarse como constantes, variables y /o expresiones. Constantes numéricas Una constante numérica es un valor formado por algún elemento del conjunto numérico. Veamos algunos ejemplos de constantes numéricas que puedan emplearse en un algoritmo computacional: 12
-25000
+1.2345
-2345
-23576.998
0.45E+02
En el último ejemplo se indica una constante numérica con notación científica, donde E+02 indica la potencia de base diez, es decir: 0.45E+02 = 0.45 * 10 2 = 45 Variables numéricas Cualquier identificador o variable que represente a un dato numérico se denomina variable numérica. Si una variable se define en un algoritmo como numérica, no podrá adoptar valores de tipo no numérico. Expresiones numéricas Una expresión numérica es aquella que combina operandos numéricos (constantes numéricas, variables numéricas u otras expresiones numéricas) con los operadores algebraicos. Los operadores algebraicos y su función son:
22
Operador
Función
+
Suma
-
Resta
*
Producto
/
Cociente
↑
Potencia
La jerarquía de estos operadores es la misma que plantea el álgebra de los números, y podrá ser alterada con la intercalación de niveles de paréntesis. Ejemplos:
2 + a * 10 ↑ 2 - 800 / C 1 - (2 * TOT - 30) ↑ P) 4 * (VENTA / 5 ↑ 2 - 25)
donde a, C, TOT, P, VENTA son todas variables numéricas. En cada caso, al evaluar la expresión se obtiene un único resultado. El operador de radicación no existe, ya que esta operación puede plantearse a través de la potenciación de exponente fraccionario. De todas maneras utilizaremos una función para el cálculo de la raíz cuadrada, como se indica en el ejemplo inicial. Supondremos además, que el ejecutante de nuestro algoritmo (la computadora) conoce y puede resolver ciertas funciones numéricas. A estas funciones las llamaremos "funciones internas" y, tienen la propiedad de devolver un valor o resultado al ser aplicadas sobre un argumento indicado entre paréntesis.
Función
Significado
RC( )
Raíz cuadrada
ABS( )
Valor absoluto
EXP( )
Exponenciación
SEN( )
Seno
COS( )
Coseno
TAN( )
Tangente
ATAN( )
Arco tangente
TRUNC( )
Parte entera
LN( )
Logaritmo natural
REDON( )
Redondeo
Con ésto podemos ampliar el uso de las expresiones numéricas antes mencionadas. Ejemplos:
TRUNC(2/3) - ABS(A) * 3 SEN(X) + 1 - TAN(C/2) 12/ RC(TAN(3.1416 / 4)) 23
Tipo Caracter El tipo caracter incluye al conjunto formado por todos los caracteres o símbolos de código ASCII (Código Estándar Americano para el Intercambio de Información). La mayoría de ellos se generan en el teclado de una computadora, es decir, las letras de nuestro alfabeto en mayúscula, en minúscula, los dígitos, los operadores relacionales '<', '>', '=', el espacio en blanco ' ',los operadores aritméticos '+', '-', '*', '/', los caracteres de puntuación y otros especiales '!', '@', '%', '(', etc. Este conjunto de 256 caracteres es un conjunto ordenado, y por lo tanto, existe una relación de precedencia u orden entre sus elementos (de menor a mayor) determinado por su número de código. El orden lo establece el código ASCII (ver la tabla con algunos de los códigos). Tener en cuenta que en el orden de precedencia del código ASCII, los siguientes grupos se hallan propuestos de menor a mayor: Ø Ø Ø Ø
El espacio en blanco Los dígitos '0', '1', '2',.........'9'. Las letras mayúsculas 'A', 'B',......'Z'. Las letras minúsculas 'a', 'b',......'z'.
Algunos caracteres del código ASCII con su número de orden correspondiente 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
'' '!' '"' '#' '$' '%' '&' ''' '(' ')' '*' '+' ',' '-' '.' '/'
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
'0' '1' '2' '3' '4' '5' '6' '7' '8' '9' ':' ';' '<' '=' '>' '?'
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
'@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O'
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' '[' '\' ']' '^' '_'
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
'`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' '{' '|' '}' '~' ' '
Constantes caracter Una constante tipo caracter es una constante cuyo valor pertenece al conjunto mencionado anteriormente delimitada por apóstrofos (‘ ‘). De acuerdo a la relación de orden establecida, podemos afirmar que son verdaderas las siguientes proposiciones: La letra 'a' es mayor que la letra 'B'. El caracter '5' es menor que la letra 'A'.
24
Dentro de este tipo incluiremos a las cadenas de caracteres secuencia finita de caracteres encerrados entre apóstrofos y por lo tanto, tienen una longitud que está dada por la cantidad de caracteres que la forman. Por ejemplo, los nombres, apellidos y direcciones, constituyen información formada con sucesiones o cadenas finitas de los caracteres mencionados anteriormente. Ejemplos: 'Jorge Fernández' 'Resultado=' 'San Martín 2377 - Dpto. 5' '043-234558' 'HIPOTENUSA' '*************' Aquí también es válido establecer una relación de orden basada en la precedencia entre caracteres ya señalada. Para establecer dicho orden entre dos cadenas, se compara caracter por caracter hasta encontrar una desigualdad. Entonces son válidas las proposiciones: 'Mario' '043-553456' 'mesa'
es mayor que es menor que es menor que
'Mariana' 'TE:043-553456' 'mesas'
Observemos que en nuestra formalización algorítmica, los datos de tipo caracter o las cadenas de caracteres se indican siempre entre apóstrofos. Esto es para evitar confusiones con otros elementos algorítmicos que desarrollaremos más adelante. Variables caracter Una variable o identificador que represente a un caracter o a una cadena de caracteres es una variable de tipo caracter.
Tipo Lógico El tipo lógico nos permite expresar un valor de verdad en un algoritmo a través de constantes, variables y/o expresiones. Constantes Lógicas Las constantes lógicas son sólo 2 y están representadas por los valores Verdadero y Falso. Representaremos a las constantes lógicas con los símbolos V y F. El subrayado es para evitar ambigüedades con las variables V y F. Esta información se produce como resultado de cualquier expresión lógica. Variables Lógicas Una variable lógica será una variable que representa a alguno de los dos valores lógicos: V o F.
25
Expresiones lógicas Las expresiones lógicas más sencillas se plantean con la combinación de operandos del mismo tipo y los operadores relacionales matemáticos.
Operador
Significado
<
Menor que
>
Mayor que
=
Igual que
>=
Mayor o igual que
<=
Menor o igual que
<>
Distinto
Ejemplos:
Expresión Lógica
Resultado
45 > 12
V
56 <= 30
F
´Andrea' > 'Mariana'
F
'Andrea' > 'Ana'
V
60 < '23'
expresión no válida
Las expresiones lógicas simples mostradas en el ejemplo, también son conocidas como expresiones relacionales pues permiten comparar o relacionar a dos operandos del mismo tipo. Justamente, la última expresión del ejemplo anterior no es válida pues compara a una constante numérica con una constante de tipo caracter. La algorítmica computacional, permite también formar expresiones lógicas más complejas, a través de operandos lógicos y los operadores que emplea la lógica proposicional:
Conector Lógico
Significado
∧
Conjunción
∨
Disyunción
~
Negación
Observemos entonces el valor de verdad de las siguientes expresiones lógicas:
26
Expresión Lógica
Resultado
(7 < 10) ∧ ('a' < 'c')
V
('Ana' < 'Angel') ∨ (12 > 19)
V
~ (37 > 18)
F
(VENTA > X) ∨ (SEN(X) <= 1)
V
PRIMITIVAS En la unidad anterior definimos a primitiva como la acción algorítmica cuyo enunciado es suficiente para que el ejecutante pueda realizarla sin ningún tipo de información adicional. En un lenguaje algorítmico como lo son los lenguajes de programación, las primitivas se identifican con palabras claves o reservadas. Nosotros empleamos bloques gráficos en el diagrama de flujo para representar acciones primitivas. En algorítmica computacional las acciones primitivas se clasifican en: Ø Ø Ø
Secuenciales Condicionales Repetitivas
Desarrollaremos a continuación algunas acciones primitivas fundamentales de tipo Secuencial.
Asignación Esta acción permite a un identificador o variable, representar o memorizar cierto valor. Para describirla utilizaremos la notación siguiente: V ß E Donde V es la variable a la cual el ejecutante debe asignar el valor de E. El símbolo '←' puede leerse 'toma el valor'. Según sean los tipos de V y E una asignación puede ser: Ø Ø Ø
aritmética caracter lógica
Asignación aritmética La asignación Vß E es aritmética si V es una variable numérica y E es una constante numérica, una variable numérica o cualquier expresión de tipo numérico. Ejemplos: A ß 43; (A toma el valor 43) X ß A; (X toma el valor contenido en la variable A) NUM ß 3*X+2; (NUM toma el valor que resulta de evaluar la expresión 3*X+2) Notemos que para poder realizar una asignación aritmética debemos evaluar la expresión de la derecha y luego ese resultado se almacena en la variable que figura a la izquierda. Por lo tanto es perfectamente válida la acción: Nß N+1; que equivale a: tomar el valor actual de N, sumarle
27
1 y asignarle ese resultado a la variable N. Por ejemplo, si antes de la acción N contenía el valor 8, luego de dicha acción contendrá 9. Observemos que esta acción algorítmica no tiene nada que ver con los conceptos asimilados en matemática, donde N = N+1 es una expresión incompatible. Asignación tipo caracter La asignación Vß E es una asignación de tipo caracter si V es una variable tipo caracter y E es un constante caracter o una variable tipo caracter Ejemplos: A ß '7'; (A toma el valor '7') X3 ß A; (X3 toma el valor contenido almacenado en la variable A) APELLIDOß 'López'; (APELLIDO toma el valor 'López') Asignación lógica La asignación Vß E es una asignación lógica si V es una variable de tipo lógico y E es una constante lógica (Verdadero o Falso), una variable lógica o una expresión lógica. Ejemplos: M ß F ; TRUE ß 34 <= 78; Gß (A < 2) ∧ (C = 10)
(M toma el valor F) (TRUE toma el valor lógico V) (G toma el valor lógico resultante de la expresión (A<2) ∧ (C=10))
Entrada y Salida Todo algoritmo tiene por objetivo principal producir resultados, pudiendo o no incorporar información del medio externo (datos), al ambiente o sistema que observa. Esta incorporación de valores desde el exterior al ambiente del algoritmo, nos lleva a definir una acción primitiva de lectura o entrada. Usaremos para ello la palabra clave LEER que permitirá al ejecutante identificar esta acción. El formato de la acción de lectura es: LEER V LEER lista-variables
donde V es una variable o donde lista-variables es una lista de variables separadas por el signo coma (,).
De esta manera, la acción LEER nos permite ingresar, desde el medio externo, uno o más valores los cuales son asignados a la variable V o a las variables que figuran a continuación de LEER. Ejemplos: LEER DAT LEER NOMBRE, APELLIDO, DNI Esta acción tiene el mismo efecto que una asignación, sólo que ésta utiliza valores del ambiente del algoritmo; en cambio la lectura asigna valores desde el medio exterior. Esta acción contribuye a hacer a los algoritmos de uso general, pues permite incorporar datos nuevos para producir nuevos resultados. Sin esta acción, la ejecución de un algoritmo producirá siempre la misma respuesta.
28
La acción primitiva que permite a un algoritmo comunicar resultados o salida de información al medio exterior, la describiremos con la palabra clave ESCRIBIR; y a continuación una variable, una constante, o una lista de variables y/o constantes. Su formato general es: ESCRIBIR C ESCRIBIR V ESCRIBIR lista-variables-constantes donde C representa una constante, V, una variable del ambiente y lista-variable-constante es una secuencia de variables y/o constantes. En esta acción el valor almacenado en una variable o el de una constante es comunicado al mundo exterior. Ejemplos: ESCRIBIR APELLIDO ESCRIBIR DAT, NOMBRE ESCRIBIR '23' ESCRIBIR 'Total =', X Destaquemos algunas diferencias entre las acciones de lectura y escritura. La lectura se realiza solamente a través de variables y, por lo tanto, si se lee una variable que ya fue definida en el algoritmo, implicará un acceso destructivo, esto es, la variable perderá su valor para tomar el del nuevo dato que se ingresa. En cambio, si se escriben resultados a través de variables, el ejecutante realizará un acceso no destructivo a dichas variables, pues sólo necesita conocer su contenido para ejecutar la escritura. Aquí las variables conservan sus valores después de la acción. Las acciones de lectura y escritura son conocidas como acciones de entrada/salida o abreviadamente E/S.
DIAGRAMAS DE FLUJO Las acciones antes descriptas corresponden a un lenguaje algorítmico que llamaremos pseudocódigo. Además, diseñaremos algoritmos en forma gráfica a través de los llamados diagramas de flujo. En un diagrama de flujo, las estructuras de las primitivas del pseudocódigo se identifican con una forma geométrica identificatoria o bloque. Estos bloques se unen con flechas que nos indican la secuencia u orden en que deben ejecutarse las instrucciones, es decir el flujo o recorrido que ha de seguirse en el diagrama. Ø Para las acciones de lectura y escritura emplearemos un paralelogramo con una pequeña flecha que apunta hacia adentro o hacia afuera del bloque respectivamente. Ø Para la acción de asignación usaremos un rectángulo. Cada bloque se corresponde con una única acción. Una de las ventajas del empleo de diagramas de flujo, es la visualización plana de las acciones que forman el algoritmo, permitiendo seguir fácilmente su lógica. Estas ventajas se apreciarán más adelante, cuando desarrollemos primitivas de estructura condicional y repetitiva. Veamos ahora algunas de las formas geométricas que usaremos como bloques que identifican acciones en un diagrama de flujo:
29
Bloque
Significado o Uso Inicio o fin de proceso Asignación Lectura o ingreso de datos Escritura o salida Expresión lógica con una salida por V y otra por F Subalgoritmo
Conectores
MODELO PARA LA RESOLUCION DE PROBLEMAS Propondremos ahora para este curso, un modelo para la presentación del planteo y diseño de un algoritmo, que permita resolver un problema dado. Para ello, y habiendo abordado las etapas de Definición del problema y del Análisis del problema - vistas en la unidad anterior - nos centraremos en la etapa de Elección y creación del método, en la cual debemos considerar tres elementos: Ø Estrategia y refinamiento de la misma Ø Ambiente Ø Algoritmo Hemos desarrollado en la unidad anterior el objetivo de la estrategia. En el ambiente se definen y describen las variables que se emplearán, indicando por cada una su nombre, su tipo, su clase (por el momento solamente: simples) y su significado. Y por último, se define el algoritmo escrito en un lenguaje algorítmico. En el curso emplearemos como lenguajes algorítmicos el PSEUDOCODIGO y los DIAGRAMAS DE FLUJO. En estos primeros capítulos, en la resolución de problemas no incluiremos la estrategia y su posterior refinamiento. Veamos en un ejemplo como aplicamos el modelo de resolución de problemas.
30
Problema: intercambiar los valores de dos variables numéricas que se leen como datos. Ambiente: Variable
Numérica
A
Carácter
Lógica
Clase
Significado
X
Simple
Dato
B
X
Simple
Dato
Aux
X
Simple
Auxiliar
Algoritmo: (en pseudocódigo) PROCESO Intercambio LEER A, B; AUX ß A; A ß B; B ß AUX; ESCRIBIR A, B FINPROCESO Algoritmo: (en diagrama de flujo) Intercambio
A, B
AUXß A
Aß B
Bß AUX
A, B
Finproceso
(Inicio) (Leer A y B) (Asignar el valor de A a AUX)
(Asignar el valor de B a A)
(Asignar el valor de AUX a B ) (Informar los contenidos de A y B) (Bloque de finalización)
31
CONCLUSIÓN Los conceptos tratados hasta aquí, contribuyen a formalizar la metodología de la definición de algoritmos. Quien los diseñe dispone ahora de reglas claras y formales, eliminando acciones ambiguas o carentes de precisión. Esto no quiere decir que, planteado un problema, el algoritmo que describe la solución del mismo sea único. Al contrario, el diseño de los algoritmos requiere una gran dosis de creatividad y, es común, hallar varios caminos para la obtención de un resultado. Sólo se trata de establecer pautas claras y precisas para que distintos ejecutantes que interpreten dichas pautas, puedan realizar la secuencia de acciones que conforman el algoritmo.
32
Facultad de Ciencia y Tecnología - Universidad Autónoma de Entre Ríos Cátedra:
Fundamentos de Programación
GUÍA DE TRABAJOS PRÁCTICOS NRO. 2 Temas:
Estructuras Condicionales: SI - FINSI, SEGÚN - FINSEGÚN.
1. Dado el siguiente algoritmo, realizar el seguimiento con el juego de datos propuestos e indicar la información que se obtendrá. Datos: 24, 32, 4 Proceso EJE1A Leer A, B, C Si C > A Entonces Si A < B Entonces R ← (A - B) * C Sino R ← (A + B) / C FinSi Sino R ← (A - B) * C FinSi Escribir ‘Resultado: ‘, R FinProceso 2. Para cada uno de los siguientes enunciados, realice ambiente y pseudocódigo. a) Dadas las longitudes de los lados de un triángulo, determinar el tipo de triángulo (equilátero, isósceles o escaleno) e informar su perímetro y su tipo. b) Un supermercado realiza descuentos por dos motivos: - Por productos en promoción: 15% de descuento sobre el total de venta de los productos en promoción si compra más de 5 artículos. - Por forma de pago: 10% de descuento sobre el total de la venta de todos los artículos, por pago Contado. Al realizarse una venta, se ingresan los siguientes datos: Cantidad de artículos en promoción, total de venta por artículos en promoción, total de venta de otros artículos, forma de pago (‘CONTADO’,’CREDITO’). Calcular e informar el total a cobrar al cliente.
33
3) Dado el siguiente algoritmo, realizar el seguimiento con el juego de datos propuestos e indicar la información que se obtendrá. Las notas que un alumno puede obtener en un examen varían entre 0 y 10 (enteros), y de acuerdo a ella, el alumno puede tener la siguiente situación en la materia. 0 – 4: recupera 5 – 7: regulariza 8 – 10: promociona Se conocen como datos: el nombre del alumno, la materia y la nota obtenida. Determinar la situación del alumno en la materia. Informar los datos ingresados y la situación del alumno. Datos: a) ‘Juan Pérez’, ‘Algebra’, 6 b) ‘Rosa Montero’, ‘Calculo I’, 9 c) ‘Inés García, ‘Inglés’, 3 Proceso EJER3 Leer NOM, MAT, NOTA; Segun NOTA hacer 1, 2, 3, 4: SIT ← ‘Recupera’ 5, 6, 7: SIT ← ‘Regulariza’ 8, 9, 10: SIT ← ‘Promociona’ DEOTROMODO: SIT ← ‘Recupera’ FinSegun Escribir ‘Alumno: ‘, NOM, ‘Materia: ‘, MAT; Escribir ‘Nota: ‘, NOTA, ‘Situación: ‘, SIT FinProceso 4) Realizar ambiente y algoritmo a) Se ingresan los datos de una fecha: día, mes (de 1 a 12) y año. Informar la misma en la forma: dd de nombre del mes de aaaa. b) Una empresa desea calcular el sueldo de un empleado sabiendo que, el sueldo básico depende de la categoría. Además, se le paga adicional por antigüedad. La determinación del básico se realiza según el siguiente detalle: Categoría Sueldo Básico 1 $ 2500 2 $ 2000 3 $ 1500 4 $ 1200 La antigüedad se calcula en base a la siguiente tabla: Antigüedad Porcentaje 0-10 años 20% 11-15 años 50% 16-20 años 80 % más de 20 100% Para ello se ingresan los datos de un empleado en el siguiente orden: Apellido y nombre , categoría (1 a 4) y antigüedad. Informar con el siguiente formato: APELLIDO Y NOMBRE: …………….......................................... CATEGORÍA: …… SUELDO BÁSICO: $ ..................... ANTIGÜEDAD: ........ AÑOS MONTO ANTIGÜEDAD: $................ SUELDO TOTAL: $ ................................
34
c) Un club cobra una cuota mensual a sus socios, a quienes divide en Activo, Familiar y Cadete. El socio activo paga el valor base, el familiar un 50 % más y el cadete paga un 20% menos. Se ingresa como primer dato el valor base de la cuota. Además se ingresa el nombre del club y los datos de un socio: número de socio, nombre y apellido y tipo (´activo´, ´familiar´, ´cadete´). Informar lo que debe pagar el socio ingresado, con el siguiente formato: NRO. DE SOCIO: ................. TIPO DE SOCIO: ...........................
CLUB: ................................ NOMBRE DEL SOCIO: ..................................................... TOTAL A PAGAR: $ .....................
d) Se necesita de un algoritmo para determinar el peso ideal de una persona. La fórmula que se aplica es la siguiente: a los centímetros que exceden el metro de altura se le suma 1 por cada década vivida. Al resultado obtenido, si la persona es de sexo femenino se le resta un 10%. Luego si es de raza amarilla se resta un 15% y si es de raza negra se le suma un 10%. Los datos que se ingresan son altura (en metros), edad, sexo (‘M’: masculino, ‘F’: femenino), raza (‘blanca’, ‘amarilla’, ‘negra’), peso actual. Informar el peso ideal, la diferencia con el peso actual y si esta es por sobrepeso o por bajo peso.
Ejercicios optativos: Realizar ambiente y algoritmo de los siguientes enunciados: i) Una inmobiliaria que alquila departamentos ha divido la ciudad en tres zonas: 1 - centro; 2 residencial; 3 - barrio. El importe mensual a pagar por el inquilino corresponde al precio base del departamento más el importe correspondiente a impuestos y comisiones, los cuales dependen de la zona de ubicación del inmueble, de acuerdo a las siguientes pautas: Zona Impuestos y comisiones 1 15% sobre el precio del alquiler 2 10% “ 3 8% “ Se desea calcular el monto total del alquiler de un departamento y para ello se ingresa el precio del alquiler y la zona donde se encuentra la vivienda (1, 2 ó 3). Informar el precio base del alquiler, el monto de impuestos y comisiones y el total a pagar por el inquilino con leyendas indicativas. ii) Una distribuidora de productos al por mayor vende sus productos por bultos cerrados. Tiene sus clientes divididos en categorías, a los cuales les aplica un descuento de acuerdo a la misma: Código de Categoría Categoría Descuento 1 Grandes clientes 10% 2 Revendedores 5% 3 Cliente Minorista 0% Según la cantidad de bultos y la forma de pago se realizan descuentos adicionales de acuerdo a las siguientes pautas: • Más de 300 bultos al contado, corresponde el 5% de descuento • Más de 500 bultos en cuenta corriente, el 3% • En otros casos no se aplica descuento
35
Se ingresan los siguientes datos correspondientes a una venta realizada: Nombre del cliente, código de categoría, cantidad de bultos, precio por bulto y forma de pago (‘C’: contado, ‘CC’: cuenta corriente). Realizar un informe con el siguiente formato: CLIENTE:.................................................. TOTAL DE LA COMPRA: $ ......................... TOTAL DE DESCUENTOS: $ ....................... TOTAL A PAGAR: $...................................
CATEGORÍA: ....................................
iii) Una fábrica distribuye sus productos en tres zonas distintas: 1, 2, y 3. Los productos los vende a través de vendedores a los cuales les paga una comisión por venta. Esta comisión varía según la zona, ya que los vendedores deben absorber ellos mismos todos los gastos de movilidad. Código de Zona Nombre Comisión 1 Paraná 5% 2 Paraná campaña 6% 3 Resto de la provincia 8% Al final de la semana cada vendedor informa el monto total de lo vendido para que se le calcule la comisión que le corresponde. Para ello se ingresa: Zona (1, 2 ó 3), Nombre y apellido del vendedor, monto vendido. Además la empresa les paga un adicional de un 2% si la venta semanal supera un monto mínimo que es igual para todas las zonas. Este monto mínimo es ingresado como primer dato. Se desea informar según el siguiente formato: NOMBRE DEL VENDEDOR: ............................................ ZONA: .......................................(*1) MONTO DE VENTA SEMANAL: $ ....................... MONTO MÍNIMO: $ .......................... COMISIÓN A COBRAR: $ ................................ ADICIONAL A COBRAR: $ ....... (*2) MONTO TOTAL COBRAR: $ ................................
Observaciones: (*1) En zona se debe informar el nombre de la zona. (*2) Informar el importe correspondiente ó 0 si no corresponde abonar adicional.
36
Facultad de Ciencia y Tecnología - Universidad Autónoma de Entre Ríos Cátedra:
Fundamentos de Programación
GUÍA DE TRABAJOS PRÁCTICOS NRO. 3 Temas:
Estructuras Iterativas: REPETIR – MIENTRAS.
Para cada uno de los siguientes enunciados, realice ambiente y pseudocódigo. 1. Realice un algoritmo que informe los múltiplos de 4 menores que 200. 2. Dado el siguiente algoritmo, indicar cual de las siguientes respuestas es la que corresponde: A
Proceso SUMA SUM ← 0; N←1 Repetir X ← N * 2; SUM ← SUM + X; Escribir N, SUM; N←N+1 Hastaque SUM > 100 Escribir N; FinProceso
1 2 3 4 5 6 7 8 9 10 11
2 4 6 8 10 12 14 16 18 20
B
1 2 3 4 5 6 7 8 9
2 6 12 20 30 42 56 72 90
1 2 3 4 5 6 7 8 9 10 110 10 11
C
2 6 12 20 30 42 56 72 90
D Ninguna de las anteriores
3. Un jardín de infantes tiene N alumnos y desea hacer un control de los mismos. Por cada alumno se ingresa Nombre y Apellido, peso y altura. Informar cuál es el alumno más alto y cuál es el de menor peso. El Valor N se ingresa como primer dato. 4. Se sabe que el impuesto automotor se calcula en base al valor del vehículo y a su categoría (1, 2, 3 ó 4). Por cada categoría se cobra un porcentaje distinto sobre el valor del vehículo. Dichos porcentajes se ingresan al principio. Luego, por cada vehículo se ingresa: patente, marca, valor y categoría. Se sabe que el parque automotor es de 5000 vehículos. Se desea calcular e informar: a) Por cada vehículo: patente, valor, y el total a pagar en concepto de impuesto. b) El total a recaudar por el impuesto automotor. 5. El colegio de médicos ha organizado un curso y desea saber cuántas mujeres y cuántos varones asistieron al mismo. Para ello, se ingresa por cada participante: Nombre y apellido, edad y sexo (M ó F). El ingreso de datos finaliza cuando se ingresa un nombre y apellido igual a ‘XXX’. Calcular e informar: • Cantidad de mujeres y de varones que asistieron al curso. • Cantidad de mujeres mayores de 25 años que asistieron. • Cantidad de hombres menores de 40 años que asistieron. • Cantidad total de participantes.
37
6. Dado el siguiente algoritmo: a) Efectuar un seguimiento con la siguiente lista de datos: 6, 120, 240, 300, 90, 280, 200 b) Hacer los cambios necesarios en el pseudocódigo para que la estructura Repetir pueda ser reemplazada por una estructura Mientras sin alterar el resultado. Proceso MAY200 Leer N; C ← 0; SUM ← 0; K←0 Repetir Leer X; C ← C + 1; Si X > 200 Entonces K ← K + 1; Finsi SUM ← SUM + X Hastaque C = N Escribir ‘Sumatoria: ‘, SUM; Escribir ‘Nros. mayores a 200: ‘, K FinProceso Para cada uno de los siguientes enunciados, realice ambiente y pseudocódigo. 7. Una empresa constructora tiene codificadas las obras que está realizando del 1 al 4. Durante el mes, cada obra retira materiales de un depósito a medida que los necesita. Dichos materiales pueden ser: 'L' - ladrillo, 'C' - cemento, 'O' - otros. Por cada retiro efectuado por una obra se ingresa: código de la obra, tipo de material ('L', 'C', 'O') y costo. Estos datos se ingresan sin orden alguno y finalizan al ingresar un código de obra = 9. Se desea informar: a) El costo total de cada obra en el mes. b) El porcentaje de pedidos de ladrillos sobre la cantidad total de pedidos. c) El código de la obra que realizó el pedido de mayor costo. 8. Luego de un examen de Computación, los docentes desean conocer los promedios obtenidos por cada comisión. Para ello, por cada comisión se conoce: el número de la misma y la cantidad de alumnos y, de cada uno de sus alumnos, la nota obtenida. Determinar e informar el promedio de cada comisión y el promedio total. Los datos finalizan con número de comisión = 999. 9. En una escuela se conoce el nombre y apellido de cada alumno, la cantidad de materias aprobadas y, por cada materia aprobada, el nombre de la misma y la nota obtenida. El ingreso de datos concluye al ingresar nombre y apellido = 'ZZZ' No se ingresan aquellos alumnos que no han aprobado ninguna materia. Se desea calcular e informar: a) El promedio general de cada alumno. b) Cuántos alumnos han aprobado más de 10 materias. c) El porcentaje de alumnos que aprobó 'INGLES'.
38
10. En una estación de servicio se vende Nafta Súper, Nafta Común y Gas Oil. Los precios por litro de cada uno de los combustibles, se ingresan como primeros datos. Por cada carga de combustible a un vehículo, se ingresa: patente, código del empleado, tipo de combustible (Súper, Común, Gas Oil) y cantidad de litros. El fin de datos se produce cuando se ingresa una patente igual a ‘xxx’. Se desea informar: • Cantidad de litros de Nafta Súper, Nafta Común y Gas Oil vendidos. • Monto Total recaudado por la Estación. 11. Se desean procesar los datos obtenidos por los nadadores de una competencia de aguas abiertas. El número de participantes y el mejor tiempo de la edición anterior se leen al principio. De cada participante se ingresa: Nombre y tiempo empleado. Si se ingresa un valor 0 para tiempo empleado, indica que el nadador abandonó la prueba. Se desea conocer: • El nombre del ganador. • Cuantos nadadores abandonaron la prueba. • Cuantos nadadores mejoraron el tiempo con respecto a la edición anterior.
Ejercicios optativos: Realizar ambiente y algoritmo de los siguientes enunciados: i. Una empresa de acopio de cereales recibe varios camiones durante el día. Por cada camión que descarga cereal se registran los siguientes datos: patente del camión, apellido y nombre del remitente, tipo de cereal (‘MAIZ’, ‘SOJA’, ‘GIRASOL’, etc.) y cantidad de toneladas. Los datos se ingresan sin orden alguno y el fin de datos ocurre cuando se ingresa una patente igual a ‘XYZ123’. Se desea informar: • Cuantos camiones descargaron cereal durante el día. • Cuantas toneladas de SOJA se acopiaron durante el día. • Total de toneladas acopiadas durante el día. ii. Una empresa de colectivos tiene varios coches que durante el día hacen varios recorridos y venden 3 tipos de boletos: estudiante, común y jubilado. El boleto estudiante es un 20 % más barato que el boleto común y el jubilado un 40 % más barato que el común. El precio del boleto común se lee como primer dato. Por cada recorrido se ingresa: Nro. de colectivo, cantidad de boletos estudiantes, cantidad de boletos comunes y cantidad de boletos jubilados vendidos. La carga de datos finaliza con nro. de colectivo = 99. Se desea saber: • Por cada recorrido, el total recaudado. • Cantidad de boletos estudiantes vendidos durante el día. • Total recaudado en todos los recorridos ingresados. • El nro de colectivo que menos recaudó y el monto recaudado por el mismo. iii. Una empresa deposita en un banco el sueldo de sus empleados, los cuales pueden retirar el dinero a través de cajeros automáticos. Cada empleado puede realizar diversas extracciones a lo largo del mes. Si la operación se realiza en cajeros de bancos en los que la empresa no ha hecho contrato, se le cobra en cada extracción 2% de recargo sobre el monto retirado.
39
Por cada empleado se ingresa: número de documento, nombre y apellido, monto del sueldo depositado por la empresa y cantidad de extracciones realizadas en el mes y luego, por cada extracción se ingresa: día, monto retirado y cajero (‘C’: Contratado, ‘NC’: No contratado). La cantidad de empleados a los que la empresa deposita el sueldo en el banco se lee al principio. Se desea informar: a)Por cada empleado: NOMBRE Y APELLIDO: ............................................ DNI: ....................................... MONTO TOTAL RETIRADO: $ ....................... (*1) SALDO DE LA CUENTA: $ ………………...... Observaciones: (*1) Considerar el recargo cuando corresponda b) La cantidad de empleados con saldo igual a cero. c) El monto total retenido en concepto de recargo por utilizar cajeros no contratados.
40
Facultad de Ciencia y Tecnología - Universidad Autónoma de Entre Ríos Cátedra:
Fundamentos de Programación
ANEXO Guía de TP Nro. 3 Temas:
Estructuras Iterativas: CICLOS ANIDADOS · CORTE DE CONTROL
1. Dado el siguiente enunciado, resolverlo según lo solicitado en los ítems A y B respectivamente. Se desea procesar los sueldos de los docentes en las escuelas de una ciudad en un mes determinado. Para ello se ingresan los datos de cada docente de la siguiente manera: Código de Escuela (desde 1 y consecutivo), Documento, Apellido y Nombre y Sueldo de cada docente. Los datos se ingresan ordenados por código de Escuela. No se sabe cuantos docentes se ingresan para cada colegio. El fin del ingreso de datos está dado por un Código de escuela igual = 999. El mes a liquidar se lee al principio de la carga de datos. A) Se desea obtener el siguiente informe: LIQUIDACIÓN DEL MES DE ……………… CANTIDAD DE DOCENTES PROCESADOS: XXXXX TOTAL A PAGAR EN TODAS LAS ESCUELAS: $ XXXXX CANTIDAD DE DOCENTES QUE COBRAN MÁS DE $1500: XXXX B) Se desea obtener el siguiente informe: LIQUIDACIÓN DEL MES DE ……………… ESCUELA: XXXXX DOCUMENTO APELLIDO Y NOMBRE SUELDO XXXXXX XXXXXXXXXXX XXXXX XXXXXX XXXXXXXXXXX XXXXX TOTAL A PAGAR EN LA ESCUELA: $ XXXXX
……………………………………… CANTIDAD DE DOCENTES PROCESADOS: XXXXX TOTAL A PAGAR EN TODAS LAS ESCUELAS: $ XXXXX
CANTIDAD DE DOCENTES QUE COBRAN MÁS DE $1500: XXX Para cada uno de los siguientes enunciados, realice ambiente y pseudocódigo. 2. En una mesa de entradas se necesita realizar un control de documentos ingresados y montos recaudados en un período de tiempo. Para ello se ingresan los datos de los documentos ingresados, de la siguiente manera: día de ingreso, nro. de entrada y monto por sellado. Estos datos se ingresan ordenados por día de ingreso, y no se sabe con seguridad cuantos documentos ingresaron por cada día. El fin del ingreso de datos está dado por día de ingreso = 99. Se desea obtener el siguiente informe: DÍA: XX NRO DE ENTRADA XXXXXX
MONTO SELLADO XXXXX
….. TOTAL RECAUDADO EN EL DÍA:
…. $ XXXX
............................ TOTAL RECAUDADO EN EL PERÍODO: $ XXXXX TOTAL DOCUMENTOS INGRESADOS: XXXXX CANTIDAD DE DÍAS EN QUE INGRESARON MENOS DE 20 DOCUMENTOS: XXX
41
3. En algunos barrios de la ciudad se ha implementado a través de 15 Centros Comunitarios (CC) un programa de asistencia alimentaria para familias de pocos recursos. Para llevar a cabo el programa, se provee a los CC, cada vez que lo solicitan, cajas de leche en polvo y botellas de aceite. Por cada pedido se ingresa, ordenado por cada CC: código (de 1 a 15), cantidad de cajas de leche en polvo, cantidad de botellas de aceite. Cada lista finaliza al ingresar los datos de un nuevo CC. Con CC = 0 terminan los datos. Como dato inicial se ingresan los precios unitarios de la leche y el aceite. a) Obtener por cada Centro Comunitario el siguiente informe: PROGRAMA ALIMENTARIO PARA CENTROS COMUNITARIOS CC CANT. CAJAS LECHE CANT. BOT. ACEITE MONTO TOTAL ($)
1 ... 15 TOTALES
......... ......... ......... .........
......... ......... ......... .........
.......... .......... .......... .........
b) Informar el código del CC que más cajas de leche recibió. c) Cuantos CC gastaron más de 30.000 pesos. 4. Una red de farmacias con distintas sucursales (codificadas de 1 en adelante), desea conocer la facturación total de un mes. Para ello, en primer lugar se ingresa el año y el nombre del mes correspondientes a los datos a procesar. Además, en el centro de procesamiento, se reciben los detalles de caja de las ventas realizadas en cada sucursal, en el cual se detallan: número de sucursal, día del detalle, moneda (‘Pesos’, ‘Tarjeta de crédito’), total vendido. Los datos se ingresan ordenados por número de sucursal y pueden venir varios juegos de datos para una misma sucursal. Un número de sucursal = 999 indica el fin de datos. Se desea: a) Obtener el siguiente listado: FARMACIA “ENTRE RÍOS” NRO DE SUCURSAL: XXX
AÑO: XXXX
TOTAL PESOS XXXXX
TOTAL TARJ. CR. XXXXX
…….
………
MES: XXXXXXX
TOTAL FACTURADO POR SUCURSAL NRO XXX: $ XXXXXXX
....................................... ........................................ b) Informar además: • Total facturado por todas las sucursales • El número de la sucursal que menos facturó en el mes. 5. En una Facultad se necesita realizar un control de materias que dicta cada docente. Para ello se ingresan los datos de las materias que dicta cada uno, de la siguiente manera: Nro de Legajo del docente, Nombre de la Materia, cantidad de horas cátedra. Estos datos se ingresan ordenados por Nro de legajo, y no se sabe con seguridad cuantas materias dicta cada docente. El fin del ingreso de datos está dado por un Nro. de legajo = 99999. Se desea obtener el siguiente informe: LEGAJO: XXXXXXXX MATERIA XXXXX
HS CÁTEDRA XXXXX
42
…….
………
TOTAL DE HORAS CÁTEDRA DEL DOCENTE: XXXX
............................ TOTAL DE HORAS CÁTEDRA DE LA FACULTAD: XXXXX TOTAL DE DOCENTES: XXXXX CANTIDAD DE DOCENTES CON MÁS DE 25 HORAS CÁTEDRA: XXXXXX
6. Una prestadora de servicios de Internet desea realizar un control sobre los clientes que tienen contratado el servicio de tarifa plana. Para ello se ingresa ordenado por número de cliente, los siguientes datos de un mes: número de cliente, cantidad de conexiones y, por cada conexión: total de minutos de la conexión, tipo de servicio (‘TR’:Tarifa Reducida, ‘TN’: Tarifa Normal). El ingreso de datos finaliza con un número de cliente igual a 9999. Por cada conexión, si el tipo de servicio es a Tarifa Reducida, al tiempo se lo debe reducir en un 20%. Desea realizar un listado de aquellos clientes que hayan estado conectados más de 3.600 minutos en el mes, con el siguiente formato: NRO CLIENTE: XXXXXXX TOTAL DE MINUTOS AL MES: XXXXXXX ..... Además informar: CANTIDAD DE CLIENTES QUE ESTUVIERON MENOS DE 900 MINUTOS: XXXXX CANTIDAD TOTAL DE MINUTOS DE CONEXIÓN: XXXXX
7. Un grupo de médicos atiende en un centro donde existen varios consultorios. Se ha producido una epidemia de gripe y varicela por lo que desean controlar la cantidad de pacientes con dichas dolencias. Cada médico atiende consultas particulares las que se cobran $20, y consultas con mutual que llevan un adicional de $5 . Los datos de los pacientes al final de la semana se ingresan ordenados por el nombre del médico que los atendió y, por supuesto, cada médico atendió a varios pacientes en esta semana. Por cada paciente atendido se ingresa: el nombre del médico, nombre del paciente, edad, diagnóstico (‘Gripe’, Varicela’, ‘Laringitis’,…) y atención ( ‘P’= si es particular o ‘M’= si es con mutual). Estos datos finalizan con un nombre de médico = ‘ZZZ’. Se desea informar: a) Por cada médico: el total de pacientes atendidos, la recaudación de dinero obtenida (por consultas particulares y adicionales por mutual) y el promedio de las edades de todos sus pacientes. b) El nombre del médico que más pacientes atendió. c) La recaudación total, la cantidad de pacientes con diagnóstico = ‘Gripe’ y la cantidad de pacientes con diagnóstico = ‘Varicela’. 8. Una compañía de comunicaciones necesita contar con un resumen sobre los cobros de tarifas por servicios de diferentes empresas de telefonía. Las empresas acerca de las cuales recibe información son: 1- CLARO; 2- PERSONAL; 3MOVISTAR y 4- NEXTEL. Los pagos de las tarifas en cada una de estas empresas puede hacerse de las siguientes maneras: Contado (‘C’), Débito automático (‘D’) y Tarjeta de Crédito (‘T’). Para emitir los resúmenes, se ingresan los siguientes datos de los pagos efectuados por los diferentes usuarios: Código de empresa (1, 2, 3, 4), Nombre del usuario, Fecha de pago, Importe y Forma de pago (‘C’, ‘D’, ‘T’). Los datos de cada pago vienen ordenados por código de empresa y
43
puede venir más de un pago para una misma empresa. El fin de datos está dado por Código de empresa = 99. Además, si el pago es al contado, existen diferentes lugares para abonar. Por ende, en este caso, se ingresa el lugar de pago, el cual puede ser: 1- PagoFácil, 2- RapiPago, 3- Banco, 4Otros. Se sabe que siempre existe al menos un pago al contado para cada empresa. El mes correspondiente al resumen se ingresa como primer dato. Se desea obtener un informe con el siguiente formato: RESUMEN DEL MES: XXXXX CÓDIGO DE EMPRESA: X FECHA USUARIO XXXXXXX XXXXXXXX XXXXXXX XXXXXXXX TOTAL DE LA EMPRESA: $ XXXX
IMPORTE XXXX XXXX
FORMA DE PAGO XXXXXXXX * XXXXXXXX
1
…. ..... TOTAL COBRADO DE TODAS LAS EMPRESAS: $ XXXXX CÓDIGO DE EMPRESA DE MENOR RECAUDACIÓN: X PERSONAL: TOTAL ABONADO EN RAPIPAGO: $ XXXX MOVISTAR: TOTAL ABONADO EN OTROS LUGARES DE PAGO: $ XXXX
Observaciones: I) Si la empresa es PERSONAL, calcular e informar el total abonado en centros RapiPago. II) Si la empresa es MOVISTAR, calcular e informar el total abonado en Otros. III) (*1) En forma de pago deben aparecer las descripciones correspondientes.
44
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 4 ESTRUCTURAS DE DATOS PARTE I
45
UADER-‐ FCyT -‐-‐ UNIDAD 4 ESTRUCTURAS DE DATOS ARREGLOS UNIDIMENSIONALES Hasta ahora hemos visto el uso de datos simples o elementales, o sea variables en las cuales podíamos alojar un único valor por vez, independientemente del tipo que fuera. Para poder diseñar ciertos algoritmos es necesario leer varias veces uno o más datos o bien reservar varios valores, con el consiguiente problema de uso reiterado de procesos de lectura/escritura que son las acciones más lentas de la algorítmica, en un caso, o bien el uso de demasiados nombres de variables, en el otro. Veamos el siguiente ejemplo: Ejemplo 1: Una empresa recibe información mensual sobre las ventas de cada una de sus 10 sucursales y desea obtener un listado de aquellas cuyas ventas superan el promedio de las mismas. Estrategia: VENTAS
Inicializar
Conocer ventas
Por venta *
Calcular Promedio
Por venta 1 *
Conocer ventas
Acumular ventas
Determinar si se debe informar
Algoritmo: (en pseudocódigo) PROCESO VENTAS X ß0; Sum ß0 REPETIR LEER Venta; X ß X+1; SumßSum + Venta HASTAQUE X = 10 Prom ß Sum/10; Tß0 REPETIR T ßT+1; LEER Venta SI Venta > Prom ENTONCES ESCRIBIR Venta FINSI HASTAQUE T = 10 FINPROCESO Este algoritmo es ineficiente por el hecho de leer dos veces el mismo conjunto de datos. Una forma alternativa de resolver el problema es definiendo 10 variables distintas cuyos valores
46
corresponden a las ventas de cada sucursal. Pero ¿cómo plantear el algoritmo para 100 sucursales? Estos problemas plantean la necesidad de extender el concepto de dato a un conjunto o grupo de ellos. Surge así la idea de Estructura de Datos. Una Estructura de Datos es un conjunto de datos homogéneos que se tratan como una sola unidad y bajo un mismo nombre colectivo. Existen distintas estructuras de datos que se diferencian por la forma en que se relacionan los datos primitivos, por el tipo de los mismos y por la manera de referenciar cada dato. Al tratar la solución de un problema en particular, debemos analizar la organización de sus datos y las relaciones entre ellos, que definen distintas estructuras de datos. En esta unidad analizaremos una estructura de datos llamada Arreglo Un Arreglo es una estructura de datos cuyos datos son del mismo tipo y se relacionan entre sí.
Análisis de la definición Ø Decimos que es una estructura de datos, significa que se trata de un conjunto de datos o valores, donde cada uno de ellos se almacena en un lugar de memoria diferente, uno a continuación del otro, pero todo el conjunto tiene un único nombre. Cada dato del arreglo se llama elemento. Ø Del mismo tipo: todos los datos del arreglo deben ser del mismo tipo: numérico, carácter o lógico. Ø Se relacionan entre sí: representan distintos valores de un mismo ente. Por ejemplo los datos de un arreglo que representan los legajos de los alumnos, o los nombres de los socios de un club, etc. Podemos distinguir arreglos unidimensionales, bidimensionales, y multidimensionales.
ARREGLO LINEAL, VECTOR O TABLA UNIDIMENSIONAL. Un arreglo es unidimensional cuando la referencia a uno de sus elementos se realiza a través de un único valor llamado índice, que determina la posición dentro del arreglo. A cada elemento del arreglo se puede acceder en forma directa indicando el nombre del vector seguido del índice entre corchetes Ø
A[5] representa el quinto elemento del vector a
Ø
A[1] representa el primer elemento del vector a
Ø
A[k] representa el k-ésimo elemento del vector a
En forma general diremos que un valor del arreglo se indica de la siguiente forma: A[I]
47
Donde: Ø
A nombre del arreglo
Ø I índice del arreglo, puede ser una constante o una variable numérica o una expresión aritmética; en todos los casos el valor de dicho índice debe ser un número natural (entero positivo). . Ejemplo: A[I+2]; A[2*I]; A[TRUNC(I*SIN(X))]; el resultado de la expresión determina la posición del elemento. La cantidad máxima de elementos que componen un vector se llama dimensión, y se indica al definir el vector al principio del algoritmo y permanece invariable durante el mismo.
Todo arreglo tiene asociado: Ø
nombre: para formar el nombre se siguen las mismas reglas que en los nombres de variables
Ø
tipo: está determinado por el tipo de los elementos que los componen (numérico, caracter o lógico)
Ø
dimensión: rango de valores numéricos que indican la cantidad máxima de elementos que componen el arreglo, por lo tanto el índice toma todos los valores dentro de ese rango.
Representación gráfica Consideremos un vector V de 5 elementos: 3, 6, 9, 12,15; gráficamente lo podemos representar como: V
3
6
9
12
15
1
2
3
4
5
Dato o elemento Ubicación
Ø
V[1] guarda el valor 3, es decir el elemento ubicado en la posición 1 del vector.
Ø
V[3] almacena el número 9, es decir el elemento ubicado en la posición 3 del vector.
Ø
Si en un algoritmo indicamos V[k] estaremos referenciando al elemento que ocupa la posición k dentro del vector y para ello la variable k debe tener valor.
Dimensionamiento Recordemos que Dimensión: es el número máximo de elementos que puede tener un arreglo. Dicho valor debe ser una constante numérica y por ende, no puede expresarse por medio de variables ni expresiones. Por cada vector que se utilice en un algoritmo se debe indicar su dimensión
48
Cómo indicar la dimensión de un arreglo Para indicar o asignarle una dimensión a un arreglo utilizaremos la siguiente acción en el algoritmo siempre antes de ser usado dicho arreglo:
DIMENSION nombre[N]
DIMENSION nombre[N]; Donde: Ø nombre: es el nombre del vector.
Ø N: es la constante numérica que indica la máxima cantidad de elementos que tendrá el vector. Si se utilizan varios vectores en el algoritmo se indica:
DIMENSION V1[N1], V2[N2], V3[N3]
DIMENSION V1[N1], V2[N2], V3[N3];
Donde N1, N2, N3 son constantes numéricas. Analicemos un vector como el siguiente: ALUMNOS
LUIS
JUAN RITA JOSE
MARI A
INES
PEDRO
1
2
5
6
7
3
4
Ø
Nombre del Vector: ALUMNOS
Ø
Dimensión: 7 (siete)
Ø
Tipo: CARACTER
Ø
Elementos: LUIS, JUAN, RITA etc.
Ø
Índices: los números 1,2,3......7La acción Dimensión se incorpora en los algoritmos
DIMENSION Alumnos[7]
…….. ……. Dimension Alumnos[7]; Iß0 Repetir IßI+1; Leer Alumnos[I] Hastaque I=7 ……. ……..
I ß 0 I ß I +1 Alumnos [I]
F
I=7 V
de la siguiente manera:
49
Ambiente En el ambiente, en la columna donde se indica la clase de datos, se indicará ahora variable “Simple” o “Vector”, según corresponda. Ejemplo: Variable I Alumnos
Num X
Carac. Lóg X
Clase Simple Vector
Significado Contador Vector de Nombres de Alumnos
Observación: un vector se diferencia de otro por el nombre, "no por su índice".
Operaciones con arreglos Las operaciones que podemos realizar con arreglos son: Ø
Asignación
Ø
Lectura
Ø
Escritura
Ø
En expresiones aritméticas y/o lógicas
Asignación En general podemos asignar valores a los elementos de un arreglo siempre que indiquemos el nombre y la posición del elemento al cual queremos asignar el valor. En general:
H[j] ß n
Donde: Ø
H es el nombre del arreglo
Ø
j indica la posición
Ø
n indica el valor que deseamos asignar
Consideremos un arreglo H de dimensión 3 al que queremos asignar el número 15 en la posición 3; lo haremos: En Diagrama:
H[3] ß 15
En Pseudocódigo:
H[3] ß 15
Lectura Si queremos asignar un valor leído como elemento de un arreglo, podemos hacerlo: En Diagrama:
A [I]
50
En Pseudocódigo:
LEER A[I]
Donde la variable I deberá tener valor entero positivo. Se asigna el valor leído al elemento del arreglo en la posición I Observación: la asignación de valores a un vector se hace elemento por elemento. Así por ejemplo para guardar en un vector 3 números naturales leídos, necesitamos un vector de 3 posiciones sea por ejemplo el vector B donde: en B[1] colocaremos el 1er valor leído en B[2] colocaremos el 2do valor leído en B[3] colocaremos el 3er valor leído FORMA 1
FORMA 2
Proceso Vector1 Dimension B[3]; I ß 0 Repetir I ß I + 1; Leer A; B[I] ß A Hastaque I = 3 Finproceso
Proceso Vector1bis Dimension B[3]; I ß 0 Repetir I ß I + 1; Leer B[I] Hastaque I = 3 Finproceso
Si los valores leídos son 150, 320, y 15 el resultado final en ambos casos será: 150
320
15
1
2
3
En adelante, usaremos directamente la FORMA 2. Escritura Si queremos escribir los valores de los elementos de un vector, debemos hacerlo uno a uno, indicando el nombre del arreglo y la posición del elemento que queremos mostrar. En Diagrama:
A [I]
En Pseudocódigo:
ESCRIBIR A[I]
Para mostrar los valores de cada uno de los elementos del vector B del ejemplo anterior, haríamos:
51
Proceso Vector2 Dimension B[3]; I ß 0 Repetir I ß I + 1; Leer B[I] Hastaque I = 3 I ß 0 Repetir I ß I + 1; Escribir B[I] Hastaque I = 3 Finproceso
En expresiones El tipo de arreglo y en consecuencia el tipo de sus elementos determina qué operaciones se pueden realizar con ellos. Las operaciones que se pueden realizar son las mismas que con variables vistas hasta el momento, teniendo en cuenta su tipo. Siguiendo el ejemplo anterior con el vector B, supongamos que ahora queremos hallar la suma de los elementos mayores que 100 e informarla, haremos: Proceso Vector Dimension B[3]; I ß 0 Repetir I ß I + 1; Leer B[I] Hastaque I = 3 I ß 0; Suma ß 0 Repetir I ß I + 1; SI B[I] > 100 Entonces Suma ß Suma + B[I] FinSi Hastaque I = 3 Escribir ‘La suma es: ‘, Suma Finproceso
Ejemplo 2: Leer las 10 calificaciones obtenidas por un alumno en cada una de las materias que cursa y asignarlas a un vector Z, luego escribir su promedio.
52
Estrategia: Alumnos
Inicializar Contador y Acumulador
Notas *
Actualizar contador
Inicializar Contador
Conocer Nota
Sumar * Elementos
Actualizar contador
Calcular Promedio
Actualizar Acumulador
Ambiente: Variable Not X Sum J Prom
Num X X X X X
Carac. Lóg
Algoritmo (en diagrama) Alumnos Dimension Not[10] X ß 0 Sum ß 0 X ß X+1 Not [X] F
X = 10 V
Clase Vector Simple Simple Simple Simple
Significado Vector de Notas Contador Acumulador Contador Promedio Algoritmo (en pseudocódigo) Proceso Alumnos Dimension Not[10]; Xß0; Sumß0 Repetir Xß X+1; Leer Not[x] Hastaque X = 10 Jß0 Repetir Jß J+1; Sumß Sum+Not[J] Hastaque J = 10 Promß Sum/10; Escribir ‘Promedio: ‘, Prom Finproceso
J ß 0 J ß J+1 Sum ß Sum + Not [J]
F
J = 10 V Prom ß Sum / 10
‘Promedio: ‘, Prom Finproceso
53
Informar Promedio
Observación: un vector se diferencia de otro por el nombre, "no por su índice", así por ejemplo VEC[i] es distinto de V[i]. Notar que para el manejo del índice del vector Not en el proceso de lectura anterior se uso X como índice y, en el de escritura J, sin embargo se trata del mismo vector.
ESTRUCTURA PARA La estructura de repetición llamada PARA nos permite ejecutar un conjunto de acciones un número determinado de veces. Formato general
Acción 1
Acción 2
Acción 3
V VI VF P
Para V desde VI hasta VF con Paso P Hacer Acción 1; Acción 2; Acción 3; …… …… Acción n Finpara
Acción n
Donde: Ø V : es una variable numérica llamada variable de control Ø VI: es una constante, variable o expresión numérica, que indica el valor inicial que toma V Ø VF: es una constante, variable o expresión numérica, que indica el valor final que toma V Ø P : es una variable o constante numérica que representa el paso o incremento de la variable V. El valor de P puede ser positivo o negativo pero no puede ser cero. A diferencia de las estructuras REPETIR y MIENTRAS, en esta estructura iterativa el procesador tiene a su cargo la variación de la variable de control ya que se incrementa su valor automáticamente de acuerdo a P, hasta llegar a VF. El procesador ejecutará las acciones en el siguiente orden: 1)
A la variable V le asigna el valor de VI.
2)
Ejecuta las acciones previstas (acción 1 hasta acción n).
3)
Incrementa la variable V sumándole P.
4)
Evalúa si el valor de la variable V de control es menor o igual a VF en ese caso continúa a partir de 2.
5)
Si la variable V es mayor a VF finaliza la ejecución de la estructura y continúa con la ejecución del algoritmo.
Cuando P = 1 el formato se reduce a:
54
Acción 1
Acción 2
V VI
Acción 3
VF
Para V desde VI hasta VF Hacer Acción 1; Acción 2; Acción 3; …… …… Acción n Finpara
Acción n
Debemos notar que: 1)
Cuando P > 0 el valor de VF debe ser mayor o igual a VI.
2)
Cuando P < 0 el valor de VF debe ser menor o igual a VI
3)
Las acciones 1 a n se ejecutan siempre al menos una vez
Observación: no se coloca punto y coma (;): Ø
en la acción que precede a la estructura de iteración
Ø
después de la palabra clave FINPARA
Ø
en la acción que precede a la palabra clave FINPARA
Ejemplo 3: informar los primeros veinte números pares, a partir del número 2.
Pares
Nro
Nro 2 40 2
Proceso Pares Para Nro desde 2 hasta 40 con Paso 2 Hacer Escribir Nro Finpara Finproceso
Finproceso
Vamos a resolver el Ejemplo 2 utilizando la estructura Para. Los contadores “X” y “J” que llevan el control del número de iteraciones, serán las variables de control de las estructuras Para.
55
Observar el siguiente algoritmo: Alumnos
Proceso Alumnos Dimensión Not[10]; Sumß0 Para X desde 1 hasta 10 Hacer Leer Not[x] Finpara: Para J desde 1 hasta 10 Hacer Sumß Sum+Not[J] Finpara: Promß Sum/10; Escribir ‘Promedio: ‘, Prom Finproceso
Dimension Not [10] Sum ß 0 X
Not [X] 1
10
J
Sum ß Sum + Not [J]
1 10
Prom ß Sum / 10 ‘Promedio: ‘, Prom Finproceso
Anidamiento de estructuras PARA El anidamiento de estas estructuras es una forma más de ciclos anidados, por lo tanto se siguen las mismas reglas, es decir la estructura interna debe estar completamente incluida dentro de la estructura externa, no permitiéndose el cruce de estructuras. Además es posible anidar distintas estructuras iterativas, estructuras Repetir, Mientras y Para, siempre y cuando se respeten las reglas antes indicadas. Observemos algunos ejemplos: a.-)
A
I 1
B C
J 1
5
10
Para I desde 1 hasta 10 hacer A Para J desde 1 hasta 5 hacer B; C Finpara Finpara
b.-)
56
Repetir M Para S desde 1 hasta n hacer P; Q; R Finpara Hastaque Condic
M
P
S
Q
1
n
R
F
Condic
V
c.-)
D E N Condic 1 V
F
1
50
Repetir Para N desde 1 hasta 50 hacer D; E Mientras Condic 1 Hacer R Finmientras Finpara Hastaque Condic 2
R
F
Condic 2 V
57
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 4 ESTRUCTURAS DE DATOS PARTE II
58
UADER-‐ FCyT -‐-‐ UNIDAD 4 ESTRUCTURAS DE DATOS ARREGLOS BIDIMENSIONALES ARREGLOS BIDIMENSIONALES Los arreglos unidimensionales son estructuras de datos que nos permiten almacenar información del mismo tipo, pero a veces, resultan ineficientes para resolver ciertos problemas. Podemos ahora, dentro de la estructura de datos que hemos llamado arreglo, estudiar el caso de los arreglos bidimensionales, que nos permitirán organizar los datos de otra manera, y así resolver los problemas mediante algoritmos más eficientes y simples.
ARREGLO BIDIMENSIONAL O MATRIZ Un arreglo es bidimensional cuando sus elementos están dispuestos en filas y columnas y la referencia a cada uno de sus elementos se realiza a través de 2(dos) índices, que determinan la posición del mismo dentro del arreglo. Los arreglos bidimensionales cumplen las mismas características que las vistas para vectores. Así, todo arreglo bidimensional o matriz tiene un nombre, un tipo (caracter, numérico o lógico según el tipo de sus datos), una dimensión y en el ambiente figurará como clase de variable matriz. En un arreglo bidimensional, cada elemento se identifica con el nombre del arreglo seguido entre corchetes de los 2 índices, separados por coma. El primer índice indica la fila y el segundo la columna. En forma general, un elemento de la matriz se define como:
A[I,J] Donde: Ø
A ⇒ es el nombre del arreglo
Ø
I ⇒ es el índice que indica la fila donde está ubicado ese elemento
Ø
J ⇒ es el índice que indica la columna donde está ubicado ese elemento
Los índices pueden ser: Ø
constantes numéricas
Ø
variables numéricas
Ø
expresiones aritméticas
En cualquiera de los 3 casos deben tener un valor entero positivo distinto de cero. Representación Gráfica Consideremos una matriz MAT compuesta de 5 filas y 3 columnas, es decir que contiene 15 datos: 2, 6, 9, 15, 27, 7, -2, 13, 3, 35, 3, 52, 0, 4, 85. Gráficamente la podemos representar como:
59
2
6
9
15
27
7
-2
13
3
35
3
52
0
4
85
FILAS
COLUMNAS
Ø MAT[2,3] es el elemento ubicado en la intersección de la fila 2 y la columna 3 y su contenido es el valor 7. Ø MAT[4,1] es el elemento ubicado en la intersección de la fila 4 y la columna 1 y su contenido es el valor 35. Ø En general: MAT[f,c] indica el elemento ubicado en la intersección de la fila f y la columna c; por lo tanto f y c deben representar un valor determinado. Dimensión de una Matriz La definición dada para el caso de un vector es válida para un arreglo bidimensional: es la máxima cantidad de elementos que puede tener. Esta dimensión se calcula como el producto entre el número máximo de filas y el número máximo de columnas. En el ejemplo dado, la dimensión de la matriz MAT es 15. Asignación de la dimensión a una matriz Por cada arreglo bidimensional que se utilice en un algoritmo se debe indicar su dimensión, por medio de la siguiente acción:
DIMENSION nombre [p, q]
DIMENSION nombre[p ,q]
Donde: Ø nombre ⇒ es el nombre de la matriz Ø p ⇒ es la constante numérica que indica la máxima cantidad de filas del arreglo Ø q ⇒ es la constante numérica que indica la máxima cantidad de columnas del arreglo Si se utilizan varias matrices en el algoritmo se indica:
DIMENSION A[p1,q1], B[p2,q2], C[p3,q3]
DIMENSION A [p1, q1], B [p2, q2], C [p3, q3]
60
Donde: Ø A, B y C representan matrices Ø p1, q1, p2, q2, p3, q3 son constantes numéricas. Ejemplo: si queremos definir en un algoritmo una matriz de 5 filas y 3 columnas, nos quedaría: a.-) En pseudocódigo
b.-) En diagrama de flujo
DIMENSION B[5, 3]
DIMENSION B [5, 3]
OPERACIONES CON MATRICES Las operaciones que se pueden realizar con los elementos de una matriz son las mismas que las vistas para arreglos unidimensionales o vectores: Ø
Asignación
Ø
Lectura
Ø
Escritura
Ø
En expresiones aritméticas y/o lógicas
En cada una de ellas debemos tener en cuenta que un elemento de una matriz queda definido indicando el nombre de la matriz, acompañado de la fila y la columna a la que pertenece.
Asignación Consideremos una matriz B formada por 5 filas y 2 columnas. Si se quiere asignar el valor 17 a la fila 3 y columna 2, se indica mediante la siguiente acción de asignación: En Pseudocódigo: B[3, 2] ß 17;
En Diagrama:
B[3, 2] ß 17
En general A[I,J] ß K es una acción de asignación que nos permitirá guardar el valor k en la posición definida por la fila I y la columna J de la matriz A. (Tanto I como J deben tener asignados previamente un valor)
Lectura A través de la acción de LEER podemos ingresar un dato y guardarlo en una determinada ubicación dentro de una matriz. Veremos distintas posibilidades.
61
Si queremos asignar un valor leído como un elemento determinado de una matriz, podemos hacerlo: En Pseudocódigo: En Diagrama: LEER A[I, J];
A [I, J]
Donde las variables I y J deberán tener valor. Se asigna el valor leído al elemento del arreglo en la fila I, columna J. Otros Casos de Lectura: a.-) Ingresar los datos de una matriz de 3 filas y 4 columnas de manera tal que los primeros 4 datos formen la primer fila, los siguientes 4 la segunda y los demás la tercera. Podemos hacerlo de 2 maneras diferentes: I.-)
En Pseudocódigo
En Diagrama
Para I desde 1 hasta 3 hacer Leer M[I, 1]; Leer M[I, 2]; Leer M[I, 3]; Leer M[I, 4] Finpara
M [I, 1] I M [I, 2]
1
3
M [I, 3]
M [I, 4]
II.-)
En Pseudocódigo
Para I desde 1 hasta 3 hacer Para J desde 1 hasta 4 hacer Leer M[I, J] Finpara Finpara
En Diagrama
M [I, J] I
J 1
4
1
3
Tanto en I.-) como en II.-), la forma de ingresar los datos se denomina 'lectura por filas', ya que vamos almacenando los datos de la matriz fila a fila.
62
b.-) Supongamos el mismo enunciado anterior pero ingresando los datos de manera tal que los primeros 3 datos formen la primer columna, los siguientes 3 la segunda y así sucesivamente hasta completar las 4 columnas. En este caso también podemos hacerlo de 2 maneras diferentes: I.-)
En Pseudocódigo
En Diagrama
Para j desde 1 hasta 4 hacer Leer M[1, J]; Leer M[2, J]; Leer M[3, J]; Finpara
M [1, J] J M [2, J]
1
4
M [3, J]
II.-)
En Pseudocódigo
En Diagrama
Para J desde 1 hasta 4 hacer Para I desde 1 hasta 3 hacer Leer M[I, J] Finpara Finpara
M [I, J] J
I 1
3
1
4
Tanto en I.-) como en II.-), la forma de ingresar los datos se denomina 'lectura por columnas', ya que vamos almacenando los datos de la matriz columna a columna. La forma II.-) es la forma más simple para la lectura de datos de una matriz, tanto para leer por fila como para hacerlo por columna. En cada problema que se nos plantee deberemos determinar la forma más conveniente de ingresar los datos a la matriz: 'por fila' o 'por columnas'.
63
Si realizáramos el seguimiento de los procesos a.-) y b.-) considerando los siguientes datos: 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 la matriz resultante sería: En a.-)
En b.-)
10
20
30
40
50
60
70
80
90
100
110
120
10
40
70
100
20
50
80
110
30
60
90
120
Escritura Mediante la acción ESCRIBIR podemos informar los valores de los elementos de una matriz. Veremos algunos casos. a.-) Se quiere informar el valor del elemento que ocupa la fila 2 y columna 4 de la matriz C. Bastará indicar dentro del algoritmo la acción En Pseudocódigo:
En Diagrama:
ESCRIBIR C[2, 4]
C [2, 4]
b.-) Informar por fila los valores almacenados en una matriz de 2 por 4. En este caso se quiere obtener un informe donde una línea del mismo se corresponda con una fila de la matriz. Para ello se deben tener las siguientes acciones en el algoritmo: I.-)
En Pseudocódigo
En Diagrama
ESCRIBIR C[1, 1], C[1, 2], C[1, 3], C[1, 4]; ESCRIBIR C[2, 1], C[2, 2], C[2, 3], C[2, 4];
C [1, 1], C[1, 2], C[1, 3], C[1, 4] C [2, 1], C[2, 2], C[2, 3], C[2, 4]
En este caso, para cada fila se especifica una acción de salida seguida de los elementos de todas las columnas que forman la matriz. II.-) Una forma más simple de hacerlo es la siguiente: 64
En Pseudocódigo
En Diagrama
Para I desde 1 hasta 2 hacer
C[I,1], C[I,2], C[I,3], C[I,4]
ESCRIBIR C[I, 1], C[I, 2], C[I, 3], C[I, 4];
Finpara
I 1
2
El resultado que se obtiene es el mismo, ya que para cada fila, en un escribir se informan 4 valores que son los correspondientes a las columnas de la matriz. El índice I indica, en cada paso del ciclo Para-Finpara, la fila que se informa. c.-) De una manera más general se puede plantear el siguiente ciclo: En Pseudocódigo
En Diagrama
Para I desde 1 hasta 2 hacer Para J desde 1 hasta 4 hacer ESCRIBIR C[I, J]; Finpara
C [I, J] I
J
Finpara 1
4
1
2
Como resultado de este ciclo se obtiene el informe de cada uno de los elementos de la matriz en una línea diferente. Realizar la prueba de estas acciones y comprobarlo. De acuerdo al problema planteado deberemos usar las distintas opciones que nos permite la acción de escribir.
En expresiones Como en el caso de vectores y siguiendo las mismas reglas, cada elemento de la matriz puede formar parte de: Ø
expresiones aritméticas
Ø
expresiones lógicas
65
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 5 Introducción a la Programación
UNIDAD 5 66
Introducción a la Programación Resumen de Conceptos
Introducción En las unidades anteriores se han resuelto numerosos problemas escribiendo algoritmos mediante diagramas de flujo. Para probar estos algoritmos se efectuaron pruebas de escritorio, ejecutando acciones y simulando lo que haría una computadora. A partir de aquí, se codificarán estas soluciones algorítmicas empleando un lenguaje de programación interpretable por una computadora, creando un programa. De esta forma, será la propia computadora la que ejecute el algoritmo y realice las acciones que conforman la solución. En esta unidad temática se abordarán los conceptos básicos relativos a la creación de programas. En primer lugar se hará una revisión de las etapas más importantes de la resolución de problemas. Luego, se explicará la forma en que se ejecutan (prueban) los programas. Como en general los programas no funcionan correctamente -la primera vez que se ejecutan- será necesario eliminar los errores, proceso que se denomina depuración de los programas. Existe una gran cantidad de lenguajes de programación. En esta materia se abordará uno en particular: el ANSI/ISO C++. Sin embargo, en esta unidad se verán las características generales que distinguen a unos lenguajes de otros y las ventajes relativas. Finalmente se propondrán algunos consejos acerca de un proceso que nunca debe faltar en la programación: la documentación. La documentación incluye toda la información que se puede suministrar acerca del programa y que no constituye el código del programa en si mismo. Se utilizará para los ejercicios un compilador C++, que permitirá afirmar los conceptos teóricos desarrollados y editar, compilar y ejecutar los primeros programas.
Revisión de Conceptos Se estudió en la Unidad 1 el proceso de resolución de problemas computacionales, donde se distinguen las etapas siguientes. Ø Ø Ø Ø Ø Ø Ø
Definición del problema. Análisis del problema. Elección del método Codificación. Prueba. Depuración. Documentación.
Las etapas correspondientes a la Codificación, Prueba y Depuración constituyen el proceso de Programación, que se desarrollará a partir de aquí en la asignatura.
67
Diagrama de las Etapas de Resolución de Problemas Inicio
Definición del problema
Análisis del problema
Programación
Prueba
SI
Error? NO
Fin
Nota: En este diagrama no se incluye el proceso de documentación ya que, como se verá luego, debe realizarse durante todas las etapas de resolución del problema.
Estrategia - Método Top Down Diseñar una estrategia, consiste en dividir o descomponer el problema original en una sucesión de problemas más simples, de tamaño suficientemente pequeño como para que cada uno de ellos pueda ser comprendido en su totalidad. Esta técnica es conocida como Top-Down o de refinamientos sucesivos y, como se verá más adelante, se adapta perfectamente a la codificación de programas mediante un lenguaje modular y estructurado. P
P1
P2
P3
P3.1
P3.2
.................
P3.3
68
Pn
La estrategia nos define QUÉ hacer
Algoritmo En esta etapa se plantea en base a la estrategia, el conjunto de acciones que permitirán resolver el problema, mediante pseudocódigo, diagrama de flujo, etc.
El algoritmo define CÓMO hacerlo
Programa Un algoritmo codificado empleando un lenguaje de programación interpretable por una computadora constituye un programa.
Ejecución y prueba del programa Para poder probar un programa escrito en un lenguaje de programación de Alto Nivel es necesario generar un código ejecutable. Este proceso puede efectuarse mediante la COMPILACION o mediante la INTERPRETACIÓN del código fuente que editó el programador.
Código Ejecutable El Proceso de Compilación El proceso de compilación es una traducción del código fuente a un código ejecutable por la computadora. El resultado de compilar un archivo o programa fuente es un nuevo archivo llamado imagen ejecutable. Los archivos ejecutables pueden ser directamente utilizados por el usuario mediante una simple llamada desde el sistema operativo (por ejemplo un doble clic en un entorno gráfico tipo Windows). El archivo ejecutable ya no requiere del compilador ni del entorno que permitió su creación y puede ser utilizado en cualquier computadora (de plataforma compatible a la admitida por el compilador).
Programa fuente COMPILACION Programa objeto Bibliotecas de código objeto
ENLACE (linking) Imagen ejecutable
69
El Proceso de Interpretación En este caso el intérprete procesa instrucción por instrucción, sin generar un código ejecutable completo. Cada vez que el usuario necesita ejecutar el programa deberá llamar al intérprete para que lo ejecute línea por línea.
Ventajas y Desventajas de Compiladores e Intérpretes Compilación Errores de sintaxis antes de la ejecución Velocidad de ejecución Protección del código.
Ventajas Interpretación Ejecución en una sola etapa Proceso interactivo de depuración
Desventajas Compilación Interpretación Proceso en varias etapas y a menudo Errores de sintaxis detectados engorroso. (*) durante la ejecución. Depuración laboriosa Baja velocidad de ejecución. Código abierto. (*) NOTA: existen compiladores con entornos de desarrollo integrados (IDE) que simplifican esta tarea.
Depuración de Programas Depuración o “debugging” significa eliminar los errores de un programa. En ciertos casos esa depuración es sencilla, pero a menudo constituye un proceso penoso. Esto depende de los tipos de errores de un programa.
Errores de un Programa i) Errores en Tiempo de Compilación: son aquellos en los que se infringen las reglas que definen la estructura de las declaraciones y sentencias. Estos errores son denominados también errores de sintaxis. Los errores de sintaxis más comunes son: errores tipográficos, falta del punto y coma final y utilización de variables que no han sido declaradas previamente. ii) Errores en Tiempo de Ejecución: los programas contienen estos errores cuando, a pesar de contar con sentencias sintácticamente válidas, se producen errores al ejecutar estas sentencias. Por ejemplo, un programa podría intentar utilizar un archivo que no existe en el disco o dividir un número por cero. iii) Errores de Lógica: en muchos casos el programa arroja resultados incorrectos a pesar de que no posea errores de sintaxis y tampoco errores al ejecutarse. En general se trata de los casos en que el programa no realiza las tareas que originalmente se solicitaron en la definición del problema. Por ejemplo, puede que un problema requiera multiplicar dos números; por error, se diseña un algoritmo que los suma. Al probar el programa, se observaría que no hay errores de sintaxis, tampoco errores de ejecución y, sin embargo, al darle dos números al programa devolvería un valor inesperado.
Lenguajes de Programación Los algoritmos se convierten en programas al ser codificados empleando lenguajes, cuyas instrucciones pueden ser procesadas por una computadora. Pero las computadoras procesan los programas de acuerdo al tipo de lenguaje utilizado. Existen varias decenas de lenguajes de programación y a su vez muchas versiones de cada uno de ellos. En base a la similitud de estos lenguajes de programación respecto de nuestro lenguaje natural se los puede clasificar en 3 tipos: Lenguajes de Máquina, Lenguajes de Bajo Nivel (Ensambladores) y Lenguajes de Alto Nivel.
70
Lenguajes de Máquina Los lenguajes de Máquina generan programas usando instrucciones que pueden ser resueltas directamente por el procesador de la computadora sin mediar traducciones. Recuérdese que una computadora es un dispositivo electrónico que solo puede procesar dos estados de señales eléctricas: encendido y apagado; si se representan estas señales mediante un modelo matemático binario usando ceros y unos, es posible representar instrucciones que conformen un programa. Por ejemplo para sumar dos números se puede escribir: 0110
1001
1010
1011
Este tipo de lenguaje tiene la ventaja de que sus programas pueden ser ejecutados directamente sin un proceso de traducción previo, lo cual implica una velocidad óptima del proceso. Como contrapartida, puede observarse que aún en problemas sencillos, el código es complejo de crear, carece de legibilidad, es muy complejo de depurar ante la presencia de errores, y tiene total dependencia del procesador de la computadora. En respuesta a estos problemas se crearon lenguajes intermedios más cercanos al nivel del lenguaje natural que usan las personas para comunicarse.
Lenguajes de Bajo Nivel Estos lenguajes pueden ser interpretados con más facilidad por una persona, pero la codificación continúa siendo una tarea compleja que requiere de una gran especialización por parte del programador. El lenguaje típico de bajo nivel es el ensamblador (Assembler Language), el cual está formado por sentencias nemotécnicas basadas en abreviaturas del inglés para representar acciones: ADD, MOV, SUB, DIV, etc. A modo de ejemplo, para sumar dos valores numéricos usando ensamblador, la acción sería: ADD X, Y, SUMA Lo cual se lee: sumar el número almacenado en la posición de memoria X con el número de la posición Y. El resultado, ubicarlo en la posición de memoria representada por SUMA. La elaboración de soluciones a problemas grandes o complejos se hace muy engorrosa con este lenguaje. Además, está muy ligado al juego de instrucciones de la marca y modelo de cada microprocesador, lo cual hace que los programas sean poco portables. Su uso se limita al control de dispositivos electrónicos que requieren programas pequeños y sencillos, o partes de otros programas de computadoras. SI bien su eficiencia es muy alta, un programa en ensamblador requiere de una traducción a código máquina para que la computadora ejecute sus instrucciones. El programa escrito en ensamblador es el programa fuente y el generado por la traducción es el programa objeto.
Lenguajes de Alto Nivel Los lenguajes de alto nivel son los más populares entre los programadores, y su aparición permitió a la ingeniería del software abordar nuevos paradigmas y modelos, para resolver problemas de mayor complejidad. La formación de programadores es más rápida y su gran ventaja es la portabilidad: los programas son independientes del hardware. Su denominación de alto nivel se debe a que su sintaxis es similar a la forma en que las personas se comunican y dan órdenes, usualmente en forma imperativa. Estos lenguajes están conformados por un conjunto de palabras y símbolos que tienen una relación directa con su significado: while, if, write, else, class, file, float, string, etc.
71
Los actuales lenguajes de alto nivel poseen sofisticados entornos de desarrollo que incluyen un amplio espectro de herramientas para la edición, compilación y depuración de los programas. La difusión de estos lenguajes, sumado a la accesibilidad de los productos de hardware ha revolucionado la industria del software en los últimos 15 años. Como desventajas se debe mencionar el alto requerimiento de recursos de la computadora (memoria, espacio en disco, etc.) y el mayor tiempo de ejecución. Existen numerosos lenguajes de alto nivel. Algunos de ellos: Fortran, Cobol, Basic, Pascal, Modula, C, C++, Java, SmallTalk, Vusal Basic, Visual C++, Delphi (Object Pascal), C++ Builder, Python, etc. Se describen sus características salientes y su origen en la lista siguiente
Algunos Lenguajes de Programación Ø 1949: Primer Assembler (ShortCode). Ø 1951: Grace Hooper escribe el primer compilador. Ø 1957: FORTRAN: FORmula TRANslator. El lenguaje dominante en el ámbito científico. Velocidad de ejecución y tipos de datos de gran precisión. FORTAN IV, FORTRAN 77, FORTRAN 90, FORTRAN 95, FORTRAN 2000. Ø 1958: LISP (John McCarthy, MIT): Nuevo paradigma de programación. Diseñado para inteligencia artificial. Ø 1958: ALGOL: ALGOritmic Language. Propuesta de un comité científico internacional. para uso científico y académico. Primer lenguaje con gramática formal BNF (Bakcus-Naur Format). Recursividad. ALGOL68. Ø 1959: COBOL: COmmon Business Oriented Language. Lenguaje orientado a problemas administrativos y contables, donde los formatos tienen suma importancia y no se requiere gran precisión numérica. Ø 1964: BASIC (John Kemeny, Thomas Kurtz). Lenguaje intérprete de aplicación general. Muy sencillo de aprender. Ø 1968: PASCAL (Niklaus Wirth, ETH). Paradigma de programación estructurada. Gran popularidad en ambientes académicos en los ´80 y parte de los ´90. Propone buenos hábitos de programación, fuertemente tipificado. Alocación dinámica de memoria. Las versiones de los 90 aceptan el modelo de objetos. Sucesores de Pascal: MODULA, MODULA-2. Ø 1972: C (Dennis Ritchie, Bell Labs): Sucesor del lenguaje “B” . Estructuras de control similares a Pascal. Programas simples, rápidos y eficientes. Acepta aritmética de punteros, alocación dinámica de memoria. No es tan amigable como otros lenguajes. Ø 1983: C++ (Bjarne Stroustroup ): C con Clases. Extensión de C al modelo de objetos. Ø 1987: Perl (Larry Wall): Lenguaje de scripts. Poderoso para el tratamiento de texto y programación en Internet. Ø 1990: Python (G. van Rossum). Lenguaje de script creado para un sistema distribuido (Univ. Amsterdam). Descendiente de ABC. Posee influencias de C/ C++ y otros lenguajes. Ø 1994: Java (Sun Labs). Lenguaje multiplataforma, compilación intermedia para bytecode, programación de aplicaciones para Internet.
72
Clasificación de los Lenguajes de Programación según la metodología empleada para abordar el diseño del programa: Ø Procedimentales: estos se basan en un conjunto de subprogramas o subrutinas que resuelven diferentes partes del problema. Por ejemplo, para resolver el problema del cálculo del volumen de un cilindro, se podría tener un programa principal que pide los datos al usuario y muestra los resultados y un subprograma que realiza el cálculo. Ø Imperativos y Declarativos: en los lenguajes imperativos las líneas del programa le dicen a la computadora que debe hacer. A lo largo de la evolución de los lenguajes de alto nivel se ha pasado desde los lenguajes imperativos hacia los lenguajes declarativos. Lenguajes declarativos son aquellos en que en las líneas del programa se encuentran las mismas abstracciones del problema en cuestión. Un buen ejemplo de lenguajes declarativos son los lenguajes orientados a objetos. Ø Orientados a objetos: en este caso, las representaciones que se plasman en el programa tiene una relación directa con la realidad del problema que resuelven. Siguiendo el ejemplo anterior (cálculo el volumen de un cilindro), nuestro programa contaría con un objeto denominado interfaz de usuario y otro cilindro. Estos objetos se encargarían de realizar las operaciones de carga de datos y muestra de resultados (el objeto interfaz de usuario) y de cálculo del volumen (el objeto cilindro). Ø Orientados a eventos: los lenguajes manejados por eventos son aquellos en los que todas las acciones del programa son invocadas por algún suceso o evento que actúa de disparador. Este evento puede provenir del usuario (como apretar un botón del mouse) o del sistema (como el aviso de que hay espacio insuficiente en el disco). En cualquier caso, el evento es enviado al programa y este llamará a ejecutar las acciones específicas propuestas para tal evento. Esta clasificación no es excluyente. Se pueden encontrar, por ejemplo, lenguajes orientados a objetos y manejados por eventos. De forma similar, algunos lenguajes son procedimentales y manejados por eventos. Algunos lenguajes, en particular, las versiones más recientes del lenguaje Pascal o C++ permiten programar en base a cualquiera de las clasificaciones anteriores e incluso combinarlas a todas en un solo programa. Sin embargo es conveniente utilizar de forma consistente un determinado modelo o metodología para abordar el problema.
Paradigmas de Programación Tema elaborado por la cátedra Paradigmas de Programación” de la Fac. Reg. Bs.As. de UTN. Disponible en http://www.tadp.com.ar/paradigmas/3
Surgimiento de los paradigmas
La historia del desarrollo de los lenguajes de programación muestra una creciente evolución en la que se van incorporando elementos que permiten i creando programas cada vez más sólidos y eficientes y a la vez facilitar la tar del programador para su desarrollo, mantenimiento y adaptación. Sin embargo este proceso está lejos de ser lineal. Ciertas características básicas incorporadas por algunos lenguajes fueron puestas en duda y fuertemente criticadas por otro, de manera que se fueron perfilando diferente teorías y grupos de lenguajes que postulaban formas disímiles de construir l soluciones.
73
Así, a medida que fueron avanzando las ciencias de la computación surgen l que actualmente definimos como “paradigmas”. Un paradigma de programac es un modelo básico de diseño e implementación de programas. Un modelo permite desarrollar programas conforme a ciertos principios o fundamentos específicos que se aceptan como válidos. En otras palabras, es una colecció de modelos conceptuales que juntos modelan el proceso de diseño, orientan forma de pensar y solucionar los problemas y, por lo tanto, determinan la estructura final de un programa. Clasificación de los paradigmas A los paradigmas se los podría clasificar de diversas maneras según los criterios que se prioricen. Pero partiendo de los principios fundamentales de cada paradigma en cuanto a las orientaciones sobre la forma para construir las soluciones, podemos distinguir entre los procedimentales y los declarativos. Ø Paradigmas procedimentales u operacionales. Indican el modo de construir la solución, es decir detallan paso a paso el mecanismo para obtenerla. Ø Paradigmas declarativos. Describen las características que debe tener la solución. Es decir especifican “qué” se desea obtener pero no requieren indicar “cómo” obtenerla. Existen también otros paradigmas, que no se pueden encuadrar en esta clasificación como el heurístico y el concurrente. Por otra parte, hay autores que hacen otro tipo de enumeraciones o clasificaciones de paradigmas en base a criterios diferentes, por ejemplo como de “alto nivel” o “bajo nivel”, o que subclasifican estas categorías en otras más específicas o acotadas, como por ejemplo “Paradigma orientado a eventos”.
Paradigmas procedimentales También llamados operacionales, la característica fundamental de estos paradigmas es la secuencia computacional realizada etapa a etapa para resolver el problema. Los programas realizados con lenguajes procedimentales deben incluir en su codificación las instrucciones de control para determinar el flujo de la ejecución, como decisiones, iteraciones y otras, conformando, de esta manera, diferentes “algoritmos”. Actúan modificando repetidamente la representación de sus datos, basándose en asignaciones destructivas con efecto de lado. Utilizan un modelo en el que las variables están estrechamente relacionadas con direcciones de la memoria del ordenador. Cuando se ejecuta el programa, el contenido de estas direcciones se actualiza repetidamente, pues las variables reciben múltiples asignaciones, y al finalizar el trabajo, los valores finales de las variables representan el resultado. Su mayor dificultad reside en determinar si el valor computado es una solución correcta del problema, por lo que se han desarrollado multitud de técnicas de depuración y verificación para probar la corrección de los problemas desarrollados basándose en este tipo de paradigmas. En otras palabras, se basan en “cómo” lograr la solución.
Paradigmas declarativos Los paradigmas declarativos se basan en desarrollar programas especificando o “declarando” un conjunto de proposiciones, condiciones, restricciones, afirmaciones, ecuaciones o transformaciones que caracterizan al problema y describen su solución. A partir de esta información el sistema utiliza mecanismos internos de control que evalúan y relacionan adecuadamente dichas especificaciones, de manera de obtener la solución. No se necesita de
74
la puntualización de los pasos a seguir para alcanzar una solución, ni instrucciones de control que conformen algoritmos. Estos paradigmas permiten utilizar variables para almacenar valores intermedios, pero no para actualizar estados de información. Si bien sus variables se relacionan con posiciones de memoria, no existe el concepto asignaciones destructivas. Las variables son usadas en expresiones, funciones o procedimientos, se unifican con diferentes valores, pero siempre con transparencia referencial, es decir, sin efecto de lado. Como estos paradigmas especifican la solución sin indicar cómo construirla, en principio, eliminan la necesidad de probar que el valor calculado es el valor solución. En otras palabras, se basan en “qué” es necesario especificar.
Principales paradigmas Ø Paradigmas procedimentales: • •
Paradigma Orientado a Objetos Paradigma Imperativo
Ø Paradigmas declarativos: • •
Paradigma Funcional Paradigma Lógico
Ø Otros paradigmas: • •
Paradigma Heurístico Paradigma Concurrente
Principales Ideas
Ø Para poder utilizar un programa la computadora debe interpretarlo o compilarlo previamente. Ø Un compilador convierte el código fuente en una imagen ejecutable (por ejemplo, un archivo .exe). Ø Los programas compilados son más rápidos de ejecutar que los interpretados y permiten ser utilizados sin necesidad de distribuir el código fuente entre los usuarios. Ø Para que un programa funcione correctamente generalmente hay que corregir sus errores mediante el “debugging” o depuración. Ø Existen tres tipos de errores: los de tiempo de compilación, los de tiempo de ejecución y los de lógica. Ø Los lenguajes de programación pueden clasificarse en lenguaje máquina, de bajo nivel y de alto nivel, dependiendo de la cercanía de su sintaxis con el lenguaje natural de las personas. Más cerca de la máquina implica menor nivel, más cerca de los lenguajes humanos, mayor nivel. Ø Un paradigma de programación es un modelo básico de diseño e implementación de programas, que determina la estructura final de los mismos.
75
Ø Los lenguajes de alto nivel se pueden clasificar según los paradigmas de programación que soportan: procedimentales, imperativos/declarativos, orientados a objetos y manejados por eventos. Es posible que algunos lenguajes combinen estos paradigmas. Ø La documentación es muy importante y debe realizarse durante todo el proceso de resolución de un problema mediante computadoras. La documentación debe realizarse tanto en el programa (documentación interna) como en archivos o impresiones adicionales (documentación externa).
76
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 6 INTRODUCCIÓN AL LENGUAJE C++
77
UNIDAD 6
Introducción al Lenguaje C++ Resumen de Conceptos
Breve historia de C++ En 1967 Martin Richards creó un lenguaje de programación BCPL para escribir sistemas operativos y compiladores y Ken Thompson creó el lenguaje B basándose en el BCPL. Estos 2 lenguajes eran muy rústicos y dejaban muchas tareas al programador. En 1972 Denis Ritchie -también de Laboratorios Bell—escribe un lenguaje basado en BCPL y B con varias mejoras que contribuyeron a su posterior popularidad; lo llamó C. La eficiencia del C en términos de ejecución y administración de recursos lo hizo el preferido de las empresas de software que diseñaban sistemas operativos y compiladores. Una de sus principales características es su independencia del hardware, lo cual permitía inicialmente correr programas C en cualquier plataforma con mínimas modificaciones. Pero las empresas de software comenzaron a diseñar versiones de C particulares que le quitaban portabilidad a los programas. Por eso, en 1983 el American National Standards Institute (ANSI) creó un comité técnico para su estandarización. La versión aprobada junto a la Organización Internacional de Estandarizacón (ISO) vio la luz en 1990 y se la conoce como ANSI C. En 1980 Bjarne Stroustrup en Laboratorios Bell, comenzó a experimentar con versiones mejoradas de C (C con clases) con la única finalidad de escribir programas de simulación orientada a eventos. Stroustrup llamó a su nuevo lenguaje C++. Este compilador fue creciendo con renovadas características que lo hacen muy original, manteniendo la compatibilidad con su antecesor C. C++ incorpora clases y funciones virtuales basándose en SIMULA67, tipos genéricos y excepciones de ADA, la posibilidad de declarar variables en cualquier lugar de ALGOL68, así como otras características originales que no existían antes: herencia múltiple, espacios con nombre, funciones virtuales puras, etc. Alex Stepanov y Andrew Koenig idearon la biblioteca de plantillas standard (STL), la cual le da a C++ una potencia única entre los lenguajes de alto nivel. Debido a la enorme difusión del C++, y –nuevamente- a las diferentes versiones que fueron apareciendo, las organizaciones ANSI e ISO se reunieron en 1990 para definir el Standard de este lenguaje, el cual fue aprobado en 1998. Hoy día, C++ posee una notable inserción en el mundo de las computadoras y es uno de los lenguajes clásicos de programación: tanto sistemas operativos y compiladores (software de base) como de aplicaciones.
78
Estructura de un Programa C++ La estructura de un programa Borland C++ es la siguiente: • Include • Macros Datos y Funciones Externas Datos y Funciones Globales
Directivas del Procesador
main( ) { ..... }
La función main( ) siempre está presente en todo programa C++.
En general, todo programa C++ se compone de funciones. Main ( ) es la función principal siempre presente, donde las acciones o instrucciones del programa se plantean dentro del bloque delimitado por las llaves de inicio ( { ) y de fin ( } ) de esta función.
Como agregar Comentarios y documentación interna Hay dos maneras: /* Todo lo que esta entre las barras es un comentario y puede abarcar varias lineas */ // Esto es un comentario que finaliza al terminar la línea
Elementos (Tokens) de un Programa C++ Todo programa C++ se construye a base de tokens o elementos básicos de léxico. Existen cinco clases de tokens: Ø Identificadores Ø palabras reservadas Ø literales Ø operadores Ø separadores. Describiremos brevemente estos elementos básicos de C++. Identificadores
Los identificadores son los nombres que empleamos para representar a importantes elementos de un programa, tal como una constante, una variable, una función, un tipo de dato, o un programa. Algunos identificadores corresponden a elementos predefinidos de C++ y se denominan identificadores estándar. Pero en muchas situaciones es el programador el que debe proponer el identificador de un elemento de programa; para hacerlo en C++, recuerde las siguientes reglas: Ø Ø Ø Ø
Utilizar como primer caracter una letra Continuar con letras, dígitos o guión bajo ( _ ) No utilizar palabras reservadas de C++ C++ considera diferentes las mayúsculas de las minúsculas
79
Ejemplos de identificadores válidos: x y23 suma
Resultado_del_Calculo
Ejemplos de identificadores no válidos: 4to char el producto
tasa&porcentaje
Nota : La elección adecuada de los identificadores favorece la comprensión del programa. No se deberían usar identificadores muy largos ni demasiado cortos. Es recomendable que sugieran un significado. Palabras Reservadas (Identificadores standard)
ANSI/ISO C++ posee el siguiente conjunto de identificadores standard que constituyen palabras reservadas del lenguaje y no pueden emplearse con otro fin: Asm Auto Break Case Match Char Class Const
Continue Default Delete Do double Else Enum Extern
float for friend goto if inline int long
new operator private protected public register return short
signed sizeof stact struct switch template this trhow
try typedef union unsigned virtual void volatile while
Literales (constantes)
Constituyen valores con significado propio y único. Por ejemplo 2.3 ‘a’ 102 “programa” OXF2B . El último ejemplo corresponde a una constante en formato hexadecimal. Operadores
Constituyen elementos del léxico de C++ que permiten conectar operandos provocando un cálculo (computación) determinado. Algunos de ellos son: + - * / = ¡ < > == [ ] : ; % { } Separadores
C++ considera dentro de este grupo a los espacios en blanco, avances de línea, retornos de carro y tabulaciones
Tipos de Datos Estándar de C++ El compilador de C++ reconoce tres tipos de datos estándar: enteros, punto flotante y carácter, a los que agregamos el tipo lógico y el Nulo. Enteros: Los diferentes tipos de datos Enteros sirven para declarar números enteros dentro de los límites de cada uno de sus tamaños. Enteros Tipo Char Unsigned char Short Unsigned short Int Unsigned int Long Unsigned long
Rango --127 .. 128 0 .. 255 -32768 .. 32767 0.. 65535 -2.147.483.648 .. 2.147.483.647 0.. 4.294.967.295 -2.147.483.648 .. 2.147.483.647 0.. 4.294.967.295
80
Tamaño (bytes) 1 1 2 2 4 4 4 4
Reales: Los diferentes tipos de datos Reales sirven para declarar números en formato de coma flotante, dentro de los límites de cada uno de sus tamaños. En definitiva es para números con decimales. Reales (punto flotante) Tipo Flota
Rango
Tamaño (bytes)
3.4 x 10-38 .. 3.4 x 1038
4
Double
1.7 x 10 -308.. 1.7 x 10 308
8
long double
3.4 x 10 -4932 .. 3.4 x 10 4932
10
Caracter: El tipo char es un tipo básico alfanumérico, es decir que puede contener un carácter, un dígito numérico o un signo de puntuación, contendrá un único carácter del código ASCII. Hay que notar que en C un carácter es tratado en todo como un número y esto es entendible si recordamos que según este código ASCII, por ejemplo, al número 65 le corresponde el carácter 'A' o al número 49 el '1'. Este tipo de variables es apto para almacenar números pequeños, como la cantidad de hijos que tiene una persona, o letras, como la inicial de mi nombre de pila. Caracter Tipo Char unsigned char
Rango -128 .. 127 0 .. 255
Tamaño (bytes) 1 1
Lógico: El tipo de datos bool sirve para declarar valores true (verdadero) o false (falso) Lógico Tipo Bool
Rango false,trae
variables que sólo pueden tomar dos
Tamaño (bytes) 1
Nulo: El tipo de datos void es un tipo especial que indica la ausencia de tipo. Se usa, por ejemplo, para indicar el tipo del valor de retorno en funciones que no devuelven ningún valor Nulo Tipo Void
Rango ----
Tamaño (bytes) 0
Notación y Definición de Constantes en C++ C++ admite 4 tipos de constantes diferentes: literales, definidas, declaradas y enumeradas.
81
Constantes literales
Tienen una notación y sintaxis determinada de acuerdo al tipo de dato que se desee expresar. Veamos algunos ejemplos: Tipo de constante literal Ejemplos Entera decimal 123 -5 Entera octal 0455 Entera hexadecimal 0XF4A Real o punto flotante 192.45 .76 -1.3e+4 Char ‘A’ ‘\n’ ‘\f’ Cadenas
“Facultad”
Comentario Secuencia de dígitos decimales con o sin signo Comienzan siempre con cero Comienzan siempre con 0X Se emplea el punto decimal y/o notación científica Caracteres del código ASCII Secuencia de escape para nueva línea Secuencia de escape para nueva página Secuencia de caracteres que forman una cadena
Constantes definidas
Ciertas constantes pueden referenciarse en C++ a través de un nombre simbólico empleando la directiva #define. #define valor 100 #define Pi 3.14159 #define proximalinea ‘\n’ C++ empleará los valores 100, 3.1459 identificadores valor, Pi y proximalinea
y
‘\n’ cuando encuentre en el programa los
Constantes declaradas: const
Al igual que en otros lenguajes como Pascal y Ada, es posible declarar en C++ constantes con nombres o identificadores a través del calificador const, indicando además el tipo asociado a la constante. El calificador const en realidad tiene el efecto de una declaración de variable, solo que el valor asignado al identificador simbólico no puede alterarse. const int n = 200 ; const char letra = ‘B’; const char cadena[] = “Programación”; Constantes enumeradas
Son valores definidos por el programador y agrupados bajo un nombre. Este nombre constituye un tipo de dato enumerado, esto permite más adelante declarar una variable y asociarla al nombre del grupo. Esta variable podrá tomar alguno de los valores listados en al definición del grupo. enum meses { ene, feb, mar, abr, may, jun, jul, ago, set, oct, nov, dic } /* lista de constantes enumeradas */ meses mes = abr /* declaración de la variable mes del tipo meses e inicializada con el valor abr */
82
Declaración e Inicialización de variables Estudiamos en algorítmica computacional el concepto de variable: posición de memoria donde se almacena un valor y que es representada por un nombre o identificador. En C++ toda variable debe tener asociado un tipo, lo cual se hace al declararse o inicializarse la variable en el programa. La declaración puede hacerse en cualquier lugar del programa, pero antes de que la variable sea invocada; esto permite reservar el espacio de memoria necesario de acuerdo al tipo asociado (int, char, double, etc.). Declaración: en C++ se declara un variable indicando un tipo y luego el nombre o identificador de la variable. int x; declaración de la variable x de tipo entera Definición: definir una variable en C++ implica asignar un valor, almacenándolo en el espacio de memoria correspondiente a la variable. x = 27;
// inicialización de la variable x con el valor 27
Declaración y Definición: Es posible declarar y definir (inicializar) una variable en una misma acción. float y = -2.35; */ declaración y definición de y como float e inicialización con el dato –2.35 */ char letra = ‘A’; // declaración de letra e inicialización con el valor ‘A’ extern int z; /* declaración de z pero sin reservar espacio para almacenamiento es decir sin definirla en el programa ya que ha sido definida en otro modulo externo */
Ámbito de validez de una variable Las variables también pueden clasificarse de acuerdo a su ámbito, es decir, la parte del programa en la que la variable es reconocida y puede ser utilizada. De acuerdo con su ámbito, las variables pueden ser locales o globales. Las variables declaradas dentro de una función, y recuerda que main también es una función, sólo serán accesibles para esa función, desde el punto en que se declaran hasta el final. Esas variables son variables locales o de ámbito local de esa función. Al igual que ocurre con las variables locales de bucle, en las de función, las variables se crean al inciar la función y se destruyen al terminar. Las variables declaradas fuera de las funciones, serán accesibles desde todas las funciones definidas después de la declaración. Diremos que esas variables son globales o de ámbito global. El ámbito temporal de estas variables es también global: se crean junto con el programa, y se destruyen cuando el programa concluye. Una variable global declarada después de la definición de una función no será accesible desde esa función, por eso, normalmente se declaran las variables globales antes de definir las funciones. El ámbito de validez de una variable es el bloque del programa en donde fue declarada. Si se requiere una variable global que pueda ser empleada en cualquier bloque debería declarase fuera de la función principal main( )
83
Analicemos el ejemplo siguiente: #include <iostream> Declaración y definición de a
int main(void) { int a=54; { // inicio del bloque anidado int b = 20; char a =’Z’ ; cout << a<<" "<<b<<’\n’; } // fin del bloque anidado cout <<a<<” ”<<b<<’\n’ ; return 0; }
Definición de b y segunda definición de a en el bloque anidado Salida:
Z
20
Causará error de compilación: b no está definida en este bloque.
En el ejemplo del recuadro la variable a fue inicialmente declarada y definida en el bloque principal de la función main( ) como entera y con un valor inicial de 54. Al ser declarada nuevamente en el bloque anidado pero de tipo char permite definir su alcance o ámbito dentro de este bloque prevaleciendo sobre la anterior declaración que usa el mismo nombre. Es decir que el primer flujo de salida cout del programa permitirá obtener Z y 20. El segundo flujo de salida producirá un error de compilación, pues la variable b no fue definida en ese bloque. Nota: no es una buena práctica de programación emplear identificadores duplicados de variables en un programa. El ejemplo solo tiene el fin de mostrar el concepto de ámbito y alcance de las variables en C++.
84
Entrada y Salida Flujos de Entrada y Salida Un flujo de Entrada/Salida o I/O stream es un secuencia de caracteres que se envían (fluyen) desde o hacia un dispositivo. En la I/O estándar, C++ utiliza cout para enviar caracteres a un archivo de salida; y cin para tomar caracteres desde un archivo de texto. También disponemos de otros dos flujos cerr y clog para manejo de errores. Los flujos cin, cout, cerr y clog, son clases predefinidas de C++, las cuales se hallan en el archivo iostream.h. Esto significa que Ud. debe incluir este archivo en la cabecera de su programa para que el compilador enlace las rutinas de definición necesarias e interprete las llamadas a estos flujos. Si no utilizamos archivos, el dispositivo predefinido para entrada y salida será el monitor de video. Observe el ejemplo del recuadro anterior donde la primer línea del código fuente se indica la inclusión de este archivo: #include <iostream>. Estudiaremos la directiva #include más adelante, la cual nos permitirá enlazar código de otros archivos fuente C++ junto a nuestro programa. El flujo de salida cout requiere del operador de inserción o salida << (dos signos menor que consecutivos) para enviar la información a la pantalla. #include <iostream.h> int main(void) { cout <<“Comando de flujo de salida en C++” ; } de igual forma opera el comando de entrada de flujo cin pero empleando los operadores de extracción o entrada >> (dos signos mayor que consecutivos) #include <iostream.h> int main(void) { int edad, anio_nac; cout << “Escriba su edad:” ; cin >> edad; anio_nac = 2010 – edad; cout << “\n”; cout << “Ud. ha nacido en “ << anio_nac; }
Caracter especial o secuencia de escape para producir un avance de línea.
85
Caracteres especiales y manipuladores para I/O Es posible enviar en el flujo de salida algunos caracteres especiales o secuencias de escape que permiten lograr una salida más legible y mejorar la interfaz con el usuario. Algunos de ellos son: Secuencia de escape \a \b \f \n \r \t \v \\ \' \" \?
Caracter
Efecto
BEL BS FF LF CR HT VT \ ' " ?
Campana o pitido de alerta Retroceso (Backspace) Avance de página Avance de línea Retorno de carro Tab horizontal Tab Vertical Barra invertida (backslash) Apóstrofo Doble comilla Marca de interrogación
En la tabla siguiente se proponen algunos casos de caracteres especiales: Ejemplo de código C++ Salida int a=20; Datos: int b= 50; a = 20 cout << “Datos: \n a = “ << a << “\n b= ”<< b b = 50 int a=20; int b= 50; cout<<“Datos:\n a =“<<a<<“\t b= ”<< b
Datos: a = 20
cerr “\a Se ha producido un error”
(suena un pitido) Se ha producido un error
86
b = 50
Existen además manipuladores de flujo a través de los cuales se puede filtrar la información logrando algún efecto, como efectuar un cálculo, una secuencia de escape idéntica a las de la tabla anterior o establecer un formato de salida, etc. Manipulador
Efecto
endl
Avance de línea (“\n”)
Exhibirá el siguiente valor en formato hexadecimal Exhibirá el siguiente valor Dec en formato decimal Exhibirá el siguiente valor Oct en formato octal Establece la base para setbase( ) mostrar el siguiente valor setw( ) Determina ancho de campo para mostrar la información Establece un caracter de setfill( ) relleno Determina el número de setprecision( ) dígitos de la fracción decimal en la presentación de números reales Hex
Ejemplo cout << “a=”<< a << endl << “b=”<< b cout << hex << 1000 cout << dec << x cout << oct << 105 cout << setbase(8) << dato cout << setw(20)<< r
“Resultado:”<<
cout << setfill(‘.’) cout << seprecision(4) << 10.0/3.0
La tabla anterior muestra algunos de los manipuladores disponibles. La mayoría se encuentra definido en el archivo de cabecera iomanip.h por lo cual es necesario incluirlo en el encabezado del programa. using namespace std; #include <iostream> #include <iomanip> int main(void) { cout << “Lenguajes de Programación”; cout << endl<<endl; cout << setfill(‘.’); cout << “1. Cobol” << setw(20)<< “pág. 1”<<endl; cout << “2. Fortran” << setw(20)<< “pág. 2”<<endl; cout << “3. Basic” << setw(20)<< “pág. 3”<<endl; cout << “4. Pascal” << setw(20)<< “pág. 5”<<endl; cout << “5. ANSI/ISO C++” << setw(20)<< “pág. 8”<<endl; return 0; } Estudie y analice la salida de este programa. Investigue el efecto de los manipuladores utilizados.
87
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 7 OPERADORES y ESTRUCTURAS de CONTROL en C++
88
UNIDAD 7
Expresiones, operadores y estructuras de control en C++ Introducción Hemos estudiado las estructuras de control desde el punto de vista algorítmico. Ya conocemos entonces para que sirve cada una de estas estructuras (secuenciales, condicionales y repetitivas) y que tipo de problemas algorítmicos podemos resolver con ellas. En esta unidad nos proponemos desarrollar de qué forma se implementan las estructuras de control en el lenguaje C++. Básicamente aprenderemos las equivalencias entre la sintaxis del pseudocódigo la sintaxis del lenguaje C++. Usted podrá apreciar que estas equivalencias son muy simples y en muchos casos se limitan a casi una traducción entre el castellano (pseudocódigo) y el inglés (C++). Por ejemplo, la estructura que conocemos como Mientras-hacer se traducirá en While. Antes de introducirnos en las estructuras de control de C++, estudiaremos la importancia de los operadores, su sintaxis y su jerarquía. Con ellos podremos construir expresiones esenciales para el planteo de las estructuras de control. Las actividades de esta unidad están diseñadas para trabajar con el entorno integrado de C++ en modo consola. La mayor parte del tiempo de estudio consistirá en actividades de programación.
¡No hay mejor forma de aprender la sintaxis de un lenguaje de programación que programando!
Expresiones Toda expresión consiste en un conjunto de operandos ligados por operadores. Utilizaremos expresiones en C++ habitualmente para efectuar cálculos, relaciones, asignaciones, etc. Para plantear expresiones en C++ debemos conocer los numerosos operadores que posee este lenguaje.
Operadores
89
Operadores Aritméticos Como su nombre lo indica, los operadores aritméticos nos permiten efectuar cálculos aritméticos. La jerarquía o precedencia de estos operadores es idéntica a la que empleamos en el álgebra de números. Esta jerarquía se puede alterar empleando paréntesis. Operador + + * / % ++ --
En tipos Enteros símbolo + unario símbolo – unario suma resta producto división entera resto de la división entera incremento decremento
En tipos Reales símbolo + unario símbolo – unario suma resta producto división en punto flotante NA (no aplicable) NA NA
Se debe tener en cuenta que las operaciones algebraicas tienen asociatividad de izquierda a derecha pero respetando la precedencia de los operadores aritméticos. Ejemplos: 10 + 7 – 4 arroja como resultado 13. Se resuelve: ( 10 + 7 ) – 4 prioridad de operadores se asocia de izquierda a derecha.
porque ante igual
6+2*9 arroja como resultado 24 . Se resuelve: 6 + ( 2 * 9 ) por que el operador producto tiene prioridad (precede) al operador de la suma. 21 / 4
arroja 5 (entero)
20.0 / 4.0
arroja 5.0 (punto flotante)
21 % 4
arroja 1 (entero)
++x
incrementa en 1 el valor de x
x++
toma el valor de x y luego lo incrementa en 1
--x
decrementa en 1 el valor de x
x--
pos decrementa en 1 el valor de x
Nota: obsérvese en los 2 ejemplos siguientes la diferencia entre los operadores de incremento y decremento cuando preceden a una variable y cuando la suceden. int n=2; cout<< n++ ; /* Se visualiza un 2. C++ envía el contenido de n a la salida a través de cout y luego incrementa en 1 a n */ int n=2; cout << ++n ; /* Se visualiza un 3. C++ incrementa en 1 a n y luego muestra el nuevo valor de n */
90
Operadores de asignación El operador = permite asignar el resultado de la expresión de la derecha a la variable de la izquierda. x=130; Debemos observar que este operador es asociativo por la derecha, por lo cual podemos hacer asignaciones múltiples o simultáneas. a=b=c=30; Esto permite asignar simultáneamente a las tres variables el valor 30. El compilador realiza la asociación del modo siguiente: a = (b = (c = 30)) . Debe observarse que para C++ la proposición c = 30 tiene doble sentido: 1) se trata de una asignación y 2) se trata de una expresión que arroja el resultado 30. cout << (n=5) ; /* asigna 5 a la variable n y visualiza 5 (resultado de la expresión)*/
Operadores relativos de asignación C++ dispone de operadores relativos, que permiten hacer más eficiente el código ejecutable resultante de la compilación Operador += - = * = /= %=
Asignación abreviada x+=y x-=y x*=y x/=y x%=y
Asignación no abreviada x=x+y x=x-y x=x*y x=x/y x=x%y
Operadores Relacionales C++ dispone de operadores relacionales, cuyo concepto es idéntico al que poseen en el álgebra de números. Su simbología también es similar, a excepción de los operadores igual que y distinto que como veremos a continuación. Estos operadores nos permitirán plantear expresiones relacionales, las cuales al ser evaluadas arrojarán un valor de verdad: verdadero o falso. C++ dispone del valor int cero (0) para representar al valor falso y de un valor int distinto de cero para verdadero. Valor de verdad Representación en C++ Falso
Cero
Verdadero
Distinto de Cero
91
Los operadores relacionales permiten relacionar (comparar) operandos de tipos compatibles Operador == != < > <= >=
Significado Igual que Distinto que Menor que Mayor que Menor o igual que Mayor o igual que
Ejemplo a == b a != b a<b a>b a <= b a >= b
Utilizaremos expresiones relacionales y lógicas para varias estructuras de control de C++ que nos permitirán plantear decisiones en el programa. Los operadores relacionales se asocian de izquierda a derecha y tienen menor prioridad que los operadores aritméticos por lo tanto una expresión del tipo: a+b<10*c equivale a (a+b)<(10*c) Es posible asignar el resultado de una expresión relacional a una variable: int m=(12+3<=10);
// asigna cero (falso) a la variable entera m
Operadores Lógicos Los operadores lógicos propiamente dichos de C++ son la conjunción o and (&&), la disyunción u or ( || ) y la negación o not ( ! ). Conceptualmente funcionan de igual forma que en la lógica algebraica.
Recordemos que la conjunción (&&) arroja un resultado verdadero (uno) sólo si ambos operandos son verdaderos; la disyunción (||) sólo es falsa si ambos operandos son falsos; y la negación ( ! ) es un operador unario que invierte el valor de verdad del operador afectado. Operador ! && ||
Significado Negación ( no ) Conjunción ( y ) Disyunción ( o )
Ejemplo ! a <= b a < b && n==100 x == 10 || a != c
Evaluación en cortocircuito C++ dispone la evaluación de una expresión lógica de izquierda a derecha. Si el operando de la izquierda es suficiente para determinar el resultado de la proposición, no se evalúa el operando de la derecha. Por ejemplo: 6 < 3 && z == 4 el operando z == 4 no llegará a evaluarse pues 6 < 3 ya decidió el resultado cero (falso) de toda la proposición.
Otros Operadores C++ dispone de otros operadores que describiremos más adelante conforme avancemos en el desarrollo de nuevos temas. Por ejemplo: operadores de bits, operador de desplazamiento, operador de direcciones, operador condicional, operador de ámbito de resolución, operador coma, operador ( ) , operador [ ].
92
Precedencia de Operadores en C++ La precedencia o prioridad de un operador determina el orden de aplicación de los operadores de una expresión. En la tabla siguiente se indican los grupos de operadores según orden de prioridad. Prioridad y categoría
1. (Prioridad más alta)
2. Unarios
3.Acceso a miembros
Operador
Llamada a función Subíndice de arreglos Selector indirecto de miembro Selector de ámbito de resolución Selector directo de miembro
I-D
! ~ + ++ -& * sizeof new delete
Negación lógica Complemento a uno (bits) Más (unario) Menos (unario) Incremento Decremento Dirección Indirección Tamaño del operando en bytes Alocación dinámica en memoria Eliminación dinámica
D-I
* à
Lee o modifica el valor apuntado Accede a un miembro de un objeto I-D apuntado
9. 10. 11. 12. 13. 14.Condicional
?:
15.Asignación
= *= /= %= += -=
5.Aditivos 6.Desplazamiento 7.Relacional 8. Igualdad
Asociatividad
() [] à :: .
* / % + >> << < <= > >= == != & ^ | && ||
4.Multiplicativos
Función o significado
Multiplicación División entera o flotante Resto de la división entera (módulo) Más binario Menos binario Desplazamiento a la derecha Desplazamiento a la Izquierda Menor que Menor o igual que Mayor que Mayor o igual que Igual que Distinto que And (manipulación de bits) Xor (manipulación de bits) Or (manipulación de bits) Conjunción lógica and Disyunción lógica or a ? x : y (significa: if a then b, else c )
I-D I-D I-D I-D I-D I-D I-D I-D I-D I-D D-I
D-I
93
&= ^= |= <<= >>= 16. Coma (prioridad más baja)
,
Evaluación múltiple
Si en una expresión aparecen operadores consecutivos de igual prioridad debe considerarse la forma de asociarlos para resolver la expresión. Por ejemplo en aritmética: ante la presencia de operadores de suma ( + ) y resta ( - ), los cuales tienen igual prioridad, C++ asocia de izquierda a derecha como corresponde al álgebra de números. La expresión a+b-c se resuelve: (a+b)-c Deben tenerse en cuenta las reglas siguientes para el planteo de expresiones: Ø Todos los operadores de un mismo grupo tienen igual prioridad y asociatividad. Ø Si dos operadores se aplican a un operando, se aplica antes el de mayor prioridad Ø Asociatividad I-D significa que primero se aplica el operador de la izquierda y luego el siguiente hacia la derecha. Asociatividad D-I significa hacer lo contrario. Ø La precedencia o prioridad de operadores puede alterarse con los paréntesis, quienes tienen máxima prioridad.
Sentencia compuesta o Bloque Una sentencia compuesta o un bloque es un conjunto de sentencias, encerradas entre llaves "{ }". Sintácticamente, un bloque se considera como una única sentencia. Los bloques pueden estar anidados hasta cualquier profundidad.
94
Estructuras de Control C++ dispone de varias estructuras para controlar la lógica de ejecución de los programas. Estas estructuras pueden clasificarse en: condicionales o selectivas, repetitivas y de interrupción o salto no condicional Tipo de estructura
Sentencia C++
Repetitiva
while do-while for
Condicional o selectiva
if-else switch
Salto no condicional o interrupción
break continue
while Las acciones abarcadas por esta estructura se ejecutan repetidamente mientras la expresión lógica arroje un valor distinto de cero (verdadero). Sintaxis while (expresión lógica ) { acciones }
Ejemplo int a=0; while ( a<100 ) { cout << a<< “\n”; a++; }
do-while Las acciones abarcadas por esta estructura se ejecutan repetidamente hasta que la expresión lógica arroje el resultado cero (falso). Sintaxis Do { acciones } while (expresión lógica );
Ejemplo int b=0; do { b++ ; cout << b<< “\n” ; } while ( b<100 );
95
for Las acciones abarcadas por esta estructura se ejecutan repetidamente hasta que la exp2 arroje cero (falso); exp1 hace de expresión de inicialización y se ejecutan una única vez; exp3 se realiza al final del grupo de acciones y generalmente se emplea para incrementar la variable que controla la estructura Sintaxis for (exp1; exp2; exp3) { acciones }
Ejemplo int a=0; for ( a=0 ; a<100 ; a++ ) cout << a<< “\n” ;
El operador coma y la sentencia for C++ permite a través del operador coma ( , ) realizar más de una instrucción donde generalmente se admite una. Por ejemplo, en el ciclo for, la primer expresión es usada comúnmente para inicializar una variable y la tercer expresión para modificar la variable que controla la estructura. Empleando el operador coma, podemos efectuar más de una inicialización. Ejemplo int i, j; for (i=0, j=10; i < 10 ; i++, j--) cout << i << “ “ << j << endl;
If-else Se evalúa la expresión lógica planteada a continuación del if y si es distinta de cero (verdadero) se realizan las acciones indicadas a continuación; si la expresión lógica es cero (falso) se realizan las acciones a continuación del else. En esta estructura la salida por cero (falso) puede obviarse; en tal caso, si la expresión arroja cero (falso) no se ejecutará acción alguna. Sintaxis if (expresión lógica) acción1; else acción 2;
Ejemplo int c=0; if ( c==200 ) c = c/2; else c = 2*c;
96
switch Esta sentencia permite efectuar una selección entre múltiples opciones en base al valor de una variable de control que nos permite gobernar la estructura (solo acepta variables de tipo int o char). Es similar a la sentencia case o select de otros lenguajes o el según que empleamos en pseudocódigo. Sintaxis
Ejemplo
switch (expresión ) { case valor1: acción_1; break; case valor2: acción_2; break; case valor3: acción_3; break; .................... default: acción_m; }
switch ( m ) { case 1: m++; break; case 2: m=2*m; break; case 3: m = m / 2; break; default : m = 100; break; }
La acción propuesta a continuación de default se ejecutará si el valor de la expresión de control no coincide con ninguno de los valores propuestos en la lista. La opción default es opcional; si no se indica y el valor de la expresión no aparece en la lista propuesta, ninguna acción será ejecutada.
break y continue Ambas sentencias interrumpen la ejecución del grupo de acciones abarcadas por una estructura repetitiva, saltando al final de la estructura. Luego de la interrupción, break, continúa con la sentencia que sigue a la iteración, abandonando la estructura de repetición; continue en cambio, salta al final de la estructura de repetición pero no la abandona, y permite continuar con la próxima iteración. Ejemplo de break
Ejemplo de continue
int a=0; while (a<5) { a++; if a == 4 break; cout << a; }
Salida: 1 2 3
int a=0; while (a<5) { a++; if a == 4 continue; cout << a; }
Salida: 1 2 3 5
97
exit( ) Esta función del lenguaje C++ permite interrumpir un programa, devolviendo un valor al entorno o plataforma empleado (DOS, UNIX, LINUX). Se halla definida en stdlib.h, por lo cual se debe incluir a este archivo en la cabecera del programa y devuelve el valor de su argumento: void exit( int ) El valor entero que se indica como argumento se retorna al proceso padre que invocó al programa, corresponde a cero si se ha interrumpido el programa con éxito. Un código distinto de cero indica que la interrupción del programa se ha debido a un error. Ejemplo cout<<“Desea continuar operando con el programa (S/N)?”; cin >> resp ; resp = toupper( resp ); // pasa a mayúsculas if (resp==´S´) exit(0);
98
ANIDAMIENTO DE ESTRUCTURAS DE CONTROL Vimos que en el diseño de algoritmos, es común la utilización de estructuras lógicas de control complejas, las que se basan en la combinación de estructuras básicas. Teníamos los condicionales anidados, es decir una estructura de decisión dentro de otra estructura de decisión. De la misma manera vimos los ciclos anidados, es decir, estructuras de iteración incluidas dentro de otras siguiendo las mismas reglas: la estructura interna debe estar totalmente incluida en la estructura externa. Veamos algunos ejemplos: Condicionales anidados En pseudicódigo
En C++
SI condicion 1 ENTONCES
if (condicion 1) { A; if (condicion 2) { B; } else { C; D; } } else { if ( condicion 3) { M; } else { R; } W; }
A SI condicion 2 ENTONCES B SINO C; D FINSI
SINO SI
condicion 3 ENTONCES M SINO R
FINSI W FINSI
Condicionales anidados, dentro de un ciclo iterativo En pseudicódigo MIENTRAS condicion 1 SI
En C++
HACER
while ( condicion 1 ) { if ( condicion 2) { if ( condicion 3 ) { B; } } else { A; } }
condicion 2 ENTONCES SI condicion 3 ENTONCES B FINSI SINO A
FINSI FINMIENTRAS
99
Ciclos iterativos Para anidados En pseudicódigo
En C++
Para I desde 1 hasta 10 hacer
for ( i=1 ; i<11 ; i++ ) { A; for ( j=1 ; j<6 ; j++ ) { B; C; } }
A Para J desde 1 hasta 5 hacer B; C Finpara Finpara
Funciones de biblioteca de C++ ANSI/ISO C++ dispone de una interesante variedad de funciones de biblioteca. Ellas nos ahorran un importante esfuerzo a la hora de efectuar ciertos cálculos. El programador C++ sólo debe considerar el tipo de argumento requerido, el tipo de resultado que devuelve y el nombre del archivo de inclusión donde se halla el prototipo de la función para indicarlo en la sentencia #include correspondiente. Más adelante aprenderemos a crear nuestras propias funciones.
Ejemplo #include <iostream.h> #include <math.h> // archivo con el prototipo de sin(x)y M_PI int main ( ) { int ang; cout << “Ingrese un ángulo en grados:”; cin >> ang; float angr = ang*M_PI/180; // pasa a radianes el ángulo cout << “El seno del ángulo es:”<< sin(angr); return 0; }
100
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 8 FUNCIONES
101
UNIDAD 8
Funciones Introducción Para hallar la solución de un problema complejo, es conveniente dividirlo en pequeños problemas más simples y buscar la solución de cada uno de ellos en forma independiente. En el diseño de algoritmos computacionales y programas esta subdivisión en segmentos o módulos - que llamaremos subprogramas - constituye una herramienta muy importante que nos permite modularizar problemas grandes o complejos. Diremos que un subprograma es un conjunto de acciones, diseñado generalmente en forma separada y cuyo objetivo es resolver una parte del problema. Estos subprogramas pueden ser invocados desde diferentes puntos de un mismo programa y también desde otros subprogramas. La finalidad de los subprogramas, es simplificar el diseño, la codificación y la posterior depuración de los programas.
Las ventajas de usar subprogramas Ø Reducir la complejidad del programa y lograr mayor modularidad. Ø Permitir y facilitar el trabajo en equipo. Cada diseñador puede atacar diferentes módulos o subprogramas. Ø Facilitar la prueba de un programa, ya que cada subprograma puede ser probado previamente y en forma independiente. Ø Optimizar el uso y administración de memoria. Ø Crear librerías de subprogramas para su posterior reutilización en otros programas.
Cuándo emplear subprogramas? Ø Es conveniente emplear subprogramas cuando: Ø Existe un conjunto de operaciones que se utilizan más de una vez en un mismo programa. Ø Existe un conjunto de operaciones útiles que pueden ser utilizadas por otros programas. Ø Se desea agrupar procesos para lograr una mayor claridad en el código del programa. Ø Se pretende crear bibliotecas que permitan lograr mayor productividad en el desarrollo de futuros programas. Al plantear la solución a un problema que queremos resolver, diseñamos un programa al que llamaremos programa principal. Incluirá entre sus acciones una sentencia especial que permite llamar al subprograma. En la etapa de ejecución del programa, al encontrar la llamada al subprograma, se transfiere el control de ejecución a éste y comienzan a ejecutarse las acciones previstas en él. Al finalizar la ejecución del subprograma y obtenidos los resultados planeados, el control retorna al programa que produjo la llamada, y continúa la ejecución del programa principal.
102
Observemos lo anterior gráficamente:
Programa A
Subprograma B
acción 1 acción 2
acción 1 acción 2 acción 3
Llamada a B
acción n
Fin Subprograma B
En el esquema, A es un programa que contiene una acción o llamada al subprograma B . Cuando el control de ejecución llega a la llamada, comienzan a ejecutarse las acciones descritas en B. Al finalizar B, el control vuelve al programa principal A, para continuar con las acciones restantes. Decimos que A es cliente del subprograma B. Este esquema simple: programa principal - subprograma , puede adquirir mayor complejidad con la existencia de otros subprogramas. El control puede pasar del programa principal a cualquier subprograma, o de un subprograma a otro, pero siempre se retorna al lugar que produjo el llamado. Programa P
Subprograma A Llamada a B
Llamada a A
Subprograma B Fin Subprograma B
Fin Subprograma A Subprograma C
Llamada a C
Fin Subprograma C
Llamada a D
Subprograma D Fin Programa P
Llamada a C
Fin Subprograma D
En el gráfico hemos representado el programa P que contiene 3 llamadas a subprogramas diferentes, A, C, D. A su vez, los subprogramas A y D son clientes de otros subprogramas: el subprograma A llama al B, y el D al C. Durante la ejecución de P, se encuentra la acción de llamada a A, el control pasa a dicho subprograma y comienzan a ejecutarse las acciones que él describe hasta encontrar la llamada a B; en este momento, el control pasa al subprograma B, se ejecutan sus acciones y al finalizar éste retorna al punto desde donde fue llamado en el subprograma A. Luego se continúan ejecutando las acciones de A, y al finalizar, vuelve el control al punto de llamada en el programa principal P. Continúa la ejecución de P hasta encontrar la llamada a C, pasando el control a este subprograma, se ejecutan sus acciones y retorna a P en el punto de llamada. Continúa P hasta hallar la llamada a D; pasa el control a D, se ejecutan sus acciones hasta encontrar la invocación al subprograma C; comienzan a ejecutarse las acciones de C, y al
103
terminar el control retorna a D en el mismo lugar donde se llamó a C. Continúa la ejecución de D, para luego retornar al programa principal P.
Observación: nótese que el mismo subprograma C fue llamado desde el programa principal P y desde el subprograma D. En otras palabras: P y D son clientes del subprograma C.
104
Tipos de Subprogramas Todos los lenguajes de programación admiten subprogramas. Se los denomina funciones, procedimientos, subrutinas. C++ emplea el subprograma función.
Funciones en C++ En C++ emplearemos funciones siempre. Todo programa C++ consta de una o más funciones y una de ellas debe llamarse main. La ejecución de un programa C++ comienza por las acciones planteadas en main. Si un programa C++ contiene varias funciones estas pueden definirse en cualquier lugar del programa pero en forma independiente una de otra (no incluir una función en otra). Como vimos en la introducción a subprogramas se puede acceder (llamar) a una función desde cualquier lugar del programa y hacerlo varias veces en un mismo programa. Al llamar a una función el control de ejecución pasa a la función y se llevan a cabo las acciones que la componen; luego el control retorna al punto de llamada. Puede existir intercambio de información entre el programa o módulo que llama a la función y ésta. La función devuelve un solo valor (o ninguno) a través de la sentencia return y estudiaremos que puede recibir y devolver información a través de sus parámetros o argumentos. //Ejemplo: calcular el promedio entre 3 valores //enteros que se ingresan como datos de entrada. #include <iostream> #include<iomanip> using namespace std;
Prototipo de la función promedio3
float promedio3(int x,int y,int z);
Llamada a la función promedio3
int main( ) { int d1, d2, d3; cout <<"Ingrese el primer dato:" ; cin >> cout <<"Ingrese el segundo dato:"; cin >> cout <<"Ingrese el tercer dato:" ; cin >> float p = promedio3(d1, d2, d3); cout <<setprecision(3)<<"El promedio es:" return 0; } float promedio3(int x,int y,int z) { float w=(x+y+z)/3.0 ; return(w); }
105
d1; d2; d3; << p;
Definición de función promedio3
Declarando y definiendo funciones en C++. C++ exige declarar una función antes de que sea utilizada. Para ello debemos escribir la cabecera de la función; en ella planteamos el tipo de resultado que devuelve la función, su nombre y sus argumentos). Esta cabecera recibe el nombre de prototipo de la función. Podemos tomar como ejemplo la función promedio3 empleada en el recuadro anterior. float promedio3(int x,int y,int z); Argumentos o parámetros formales Nombre de la función Tipo de resultado
Usualmente se escribe el prototipo de la función antes de main{ } pero recordemos que en C++ es posible efectuar la declaración de un elemento en cualquier lugar del programa con la condición de hacerlo antes de invocar dicho elemento.
Resultados de una función C++ Si una función devuelve un resultado, se debe especificar su tipo antes del nombre o identificador de la función; y en el cuerpo, debemos emplear una variable o expresión de igual tipo como argumento de la sentencia return(). float promedio3(int x,int y,int z) { float w=(x+y+z)/3.0 ; return w; }
Obsérvese en el ejemplo que el tipo de la función promedio3 y el tipo de la variable w que será retornada coinciden. También puede plantearse: float promedio3(int x,int y,int z) { return((x+y+z)/3.0) ; }
Es posible que una función no devuelva resultados; entonces se especifica el tipo nulo void en su prototipo y en la correspondiente definición. void promedio3(int x,int y,int z) { float w=(x+y+z)/3.0 ; cout << “el promedio es:” << w << endl; }
106
Intercambio de información desde funciones C++ El empleo de funciones nos permite diseñar rutinas que pueden ser reutilizadas dentro del mismo programa o desde otros programas. A menudo es necesario enviar información a la función desde el punto de llamada para que complete la tarea asignada. Esto se hace a través de sus parámetros o argumentos.
En el prototipo y en la definición de la función planteamos los parámetros formales o de diseño, y cuando invocamos a la función utilizamos parámetros actuales o de llamada. Si una función no requiere parámetros de entrada se la define con el tipo void entre paréntesis (o directamente con paréntesis vacíos) y se la invoca con paréntesis vacíos y sin asignarla a ninguna variable. void funcion_nula( ); void main() {..... funcion_nula( ); ..... }
Función sin parámetros de resultado Llamada a la función
void funcion_nula( ) { ..... } El pasaje o intercambio de información entre parámetros puede hacerse por valor o por referencia.
Pasaje de parámetros por valor En este caso, al producirse la llamada a la función los parámetros formales son asignados en forma correspondiente con los valores contenidos en los parámetros actuales o de llamada. ..... d1, d2, d3: parámetros int main( ) actuales o de llamada { ..... float p = promedio3(d1, d2, d3); cout << “Datos:”<<d1<<” ”<<d2<<” ”<<d3; cout << “Promedio:”<<p; ..... x, y , z: parámetros formales. return 0;} Son asignados en la llamada: x=d1, y=d2, z=d3
float promedio3(int x,int y,int z) { float w=(x+y+z)/3.0 ; return w; }
Al finalizar las acciones de la función promedio3() se devuelve el control a la función principal main() retornándose el valor obtenido en w. Si en el ejemplo anterior los datos asignados a d1, d2, d3 son 10, 20, 45, la salida a través de los flujos cout será: Datos: 10 20 45 Promedio: 25.00
107
Pasaje de parámetros por referencia La referencia consiste en utilizar como parámetro formal una referencia a la posición de memoria del parámetro actual o de llamada. Esto puede hacerse a través del operador referencia & o empleando punteros. Con el operador referencia es posible definir alias de una variable y emplear los parámetros actuales o de llamada para obtener resultados. C++ emplea el operador & para realizar esta referencia. Observemos el siguiente ejemplo: int m=10; int &q = m; // q es definido como alias de m q++; // se incrementa q en 1 y también m cout << m; // se obtiene 11 como salida
Es decir que la expresión &q permite hacer referencia a la variable m a través de otro nombre (q es el alias de m). Veamos que ocurre en nuestro ejemplo del cálculo del promedio al usar alias para pasaje por referencia: ..... void promedio3(int x,int y,int z,float &p) int main( ) Parámetros actuales { int d1,d2,d3; float prom; o de llamada ..... promedio3(d1, d2, d3, prom); cout << “Datos:”<<d1<<” ”<<d2<<” ”<<d3; cout << “Promedio:”<<prom; El parámetro formal p es un alias de prom ..... return 0; } Modificación del parámetro void promedio3(int x,int y,int z,float &p) { p=(x+y+z)/3.0 ; } formal p y consecuente modificación de prom en main
Ahora, la información obtenida a través de la variable prom en main, se obtuvo a través de p en la función. Como p es una referencia de prom (comparten la misma posición de memoria) al modificar p en al función, se modifica automáticamente prom. El uso de alias a través del operador & permite a una función obtener otros resultados además del correspondiente a la sentencia return( ).
108
Parámetros por defecto Es posible proponer, en el prototipo de la función, parámetros formales inicializados con valores. Estos valores serán asumidos por defecto en el cuerpo de la función si no se indican parámetros actuales para tales argumentos. Parámetro formal con
float promedio3(int x,int y,int z=10) valor 10 por defecto ..... void main( ) Llamada a la función con solo 2 { parámetros actuales ( el tercero ..... se asumirá por defecto) float p=promedio3(d1, d2); ..... float q=promedio3(d1,d2,d3); } Llamada a la función con 3 parámetros actuales. Aquí no se empleará el valor por defecto en la función.
La única restricción sintáctica para estos parámetros por defecto, es el hecho de que deben figurar al final (a la derecha) de la lista de parámetros formales. De acuerdo a esto último, el siguiente prototipo de función C++ sería causa de error en una compilación: float promedio3(int x,int y=5,int z) //ERROR!!
109
Sobrecarga de Funciones C++ admite que dos funciones diferentes puedan tener el mismo nombre. Para que el compilador pueda distinguirlas es necesario que difieran sus parámetros. Esto significa que se puede emplear el mismo identificador en dos o más funciones si estas funciones tienen distinta cantidad de parámetros o diferentes tipos de parámetros. Por ejemplo, // Ejemplo de sobrecarga de funciones #include <iostream> int dividir (int a, int b); float dividir (float a, float b); int main () { int x=5,y=2; float n=5.0,m=2.0; cout << dividir (x,y); cout << "\n"; cout << dividir (n,m); return 0; } int dividir (int a, int b) { return (a/b); } float dividir (float a, float b) { return (a/b); }
La salida del programa será: 2 2.5 En este caso se han definido dos funciones con el mismo nombre, pero una de ellas acepta parámetros de tipo int y la otra acepta parámetros de tipo float. El compilador sabe cual debe emplear pues los tipos de parámetros son considerados previamente. Por simplicidad, ambas funciones tienen el mismo código, pero esto no es estrictamente necesario. Se pueden hacer dos funciones con el mismo nombre pero con comportamientos totalmente diferentes. Obsérvese un caso erróneo de aplicación de sobrecarga en funciones: // Ejemplo erróneo de sobrecarga int dividir(int,int); float dividir(int,int);
En la primera función se propone una división entera y en la segunda una división entre enteros que arroja un flotante, pero ambas funciones están sobrecargadas y con el mismo tipo de parámetros. Cuando el programa cliente invoque a division() no podrá discernir a cual de las 2 funciones se refiere la llamada.
110
Operaciones de entrada y salida en funciones No es conveniente emplear operaciones de entrada y salida interactiva en funciones. Es mejor operar a través de parámetros y que la entrada y salida la realice el cliente de la función. Esto es para independizar la función del tipo de entorno en que se ejecutará el programa cliente que la utilizará. Por ejemplo: si en una función incluimos operaciones de salida empleando el modo consola en C++ a través del objeto cout, no podremos emplear esta función en un programa C++ que opere en un entorno gráfico (como Windows), donde la entrada y salida se realizan a través de componentes visuales situados en formularios (ventanas). En cambio, no representa un inconveniente utilizar entrada y salida a dispositivos que almacenan archivos. Observemos en el ejemplo de abajo la diferencia entre una función que realiza una salida y otra que sólo devuelve el resultado. La función volumen_cilindro1() calcula el volumen de un cilindro y produce una salida con ese resultado void volumen_cilindro1(float radio, float altura) { float vol; vol= 3.14*radio*radio*altura; cout<<”El volumen del cilindro es:”<<vol; }
La función volumen_cilindro2() sólo devuelve el resultado obtenido al cliente que invoque la función. float volumen_cilindro2(float radio, float altura) { float vol; vol= 3.14*radio*radio*altura; return vol; }
La función volumen_cilindro2() puede ser reutilizada en programas cuya entrada y salida se realice a través de componentes visuales de un entorno gráfico. La función volumen_cilindro1() sólo puede emplearse en programas C++ que operen en modo consola.
Recursividad La recursividad es una técnica que permite definir una función en términos de sí misma. En otras palabras: una función es recursiva cuando se invoca a sí misma. C++ admite el uso de funciones recursivas; cualquier función C++ puede incluir en su código una invocación a sí misma, a excepción de main(). Para su implementación los compiladores utilizan una pila (stack) de memoria temporal, la cual puede causar una interrupción del programa si se sobrepasa su capacidad (stack overflow).
111
Como ventaja de esta técnica podemos destacar que permite en algunos casos resolver elegantemente algoritmos complejos. Como desventaja debemos decir que los procedimientos recursivos son menos eficientes –en términos de velocidad de ejecución- que los no recursivos.
Los algoritmos recursivos surgen naturalmente de muchas definiciones que se plantean conceptualmente como recursivas. Obsérvese el caso del factorial de un número: por definición es el producto de dicho número por todos los factores consecutivos y decrecientes a partir de ese número, hasta la unidad: n!= n*.(n-1)*(n-2)*…*2*1. Por ejemplo: 5!=5*4*3*2*1= 120 Pero el producto 4*3*2*1 es 4! Por lo tanto podemos escribir: 5!= 5* 4! Como vemos en la línea anterior, hemos expresado el factorial en función de sí mismo. Es exactamente lo que podemos plantear algorítmicamente usando funciones C++. La solución recursiva del factorial de un número puede expresarse de la siguiente forma: long factorial(unsigned int x) { if (x==0) return 1; else return x*factorial(x-1); };
Obsérvese que en la función recursiva existe una condición (x==0) que permite abandonar el proceso recursivo cuando la expresión relacional arroje verdadero; de otro modo el proceso sería infinito. Condiciones para que una función sea recursiva
Toda función recursiva debe. 1. Realizar llamadas a sí misma para efectuar versiones reducidas de la misma tarea. 2. Incluir uno o más casos donde la función realice su tarea sin emplear una llamada recursiva, permitiendo detener la secuencia de llamadas (condición de detención o stop) Analizando el ejemplo del factorial de un número, podemos ver que la expresión x*factorial(x-1) corresponde al requisito 1 y la expresión x==0 al segundo requisito.
112
Síntesis
1. Los subprogramas permiten modularizar el diseño de programas, con las ventajas de posibilitar la reutilización de código, facilitar el trabajo en equipo, agilizar la depuración de errores y optimizar la administración de recursos en una computadora. 2. En C++ los subprogamas se expresan a través de funciones. Pueden incluirse en el programa cliente que las empleará o en archivos separados que funcionan como bibliotecas de funciones. 3. El prototipo de una función C++ incluye el tipo de resultado que devuelve, el nombre de la función y entre paréntesis la lista de parámetros o argumentos declarados. El código de la función tiene la estructura de un programa, sólo que se programa separadamente. 4. Los programas intercambian información con las funciones a través de los parámetros. Los parámetros de diseño de una función se llaman parámetros formales. Al llamar a una función se utilizan los parámetros actuales o de llamada. El número de parámetros formales debe coincidir en cantidad y tipo con el número de parámetros actuales empleados en la llamada (excepto en el caso de parámetros por defecto). 5. El pasaje de información a través de parámetros puede realizarse por valor o por referencia. Por valor: asignando los valores de los parámetros actuales a los formales. Por referencia: definiendo alias de los parámetros actuales con el operador &, el cual debe preceder a los parámetros formales en el prototipo de la función. El pasaje por referencia permite realizar cálculos y asignarlos a los parámetros formales que se verán reflejados en los parámetros actuales. 6. Las variables locales declaradas dentro de la función y los parámetros formales de la misma, sólo son reconocidos dentro del ámbito de la función. Al completar la ejecución de una función, estos elementos liberan recursos y pierden toda la información que guardaban. 7. Una función puede no devolver valores si se la define de tipo nulo (void). En este caso, la función no incluye la sentencia return. Para funciones no nulas, return debe emplearse en el cuerpo de la función para devolver un resultado del mismo tipo que la función. 8. Se recomienda no realizar operaciones de entrada/salida dentro del código de las funciones. De este modo la función puede ser reutilizada en diferentes entornos y no depende la de la interfaz de usuario empleada. 9. Dos o más funciones pueden en C++ tener igual nombre y realizar distintas tareas. Para ello deben operar con diferentes parámetros. Esta propiedad se denomina sobrecarga de funciones. Al llamar a una función sobrecargada, el compilador C++ reconoce cuál es la que debe ejecutar en base a los parámetros utilizados en la llamada. 10. C++ admite que una función incluya en su código una o más llamadas a sí misma para efectuar versiones reducidas de la misma tarea. En ese caso se dice que la función es recursiva. Una función recursiva, además de incluir la/s llamada/s a sí misma, debe proponer en su código uno o más casos donde la función realice su tarea sin emplear una llamada recursiva, permitiendo detener la secuencia de llamadas (condición de detención o parada).
113
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 9 ARRAYS Y STRUCTS
114
UNIDAD 9
Arrays y Structs Introducción En esta unidad aprenderemos a emplear dos importantes estructuras de datos en C++. Aplicaremos los conceptos estudiados en Fundamentos de Programación: los arreglos, empleando la sintaxis de C++. Estudiaremos como declarar y definir arreglos estáticos en C++, como se almacenan en memoria y como se acceden para ser modificados o utilizados. Analizaremos sus ventajas y limitaciones. Además estudiaremos otra estructura de datos importante de C++: struct, y analizaremos las ventajas de su empleo. Veremos que es posible combinar estructuras de datos de acuerdo a las necesidades del caso a resolver.
Definición de arreglo Definimos como array a la estructura de datos formada por una secuencia de elementos homogéneos (de igual tipo). Cada elemento tiene una posición relativa que puede ser establecida por uno o más índices- dentro de la secuencia.
Características de los arreglos estáticos en C++ Ø Un arreglo es una colección de datos relacionados de igual tipo e identificados bajo un nombre genérico único. Ø La estructura completa ocupa un segmento de memoria único y sus elementos se almacenan en forma contigua. Ø Para procesar un elemento del arreglo, se debe especificar el nombre de la estructura y uno o más índices que determinan la posición del elemento. Ø Se debe establecer en la declaración, la cantidad de elementos (dimensión) que puede tener como máximo el arreglo en el programa. Ø Se puede emplear como índice cualquier expresión que arroje un entero dentro del rango establecido (dimensión) para dicho índice. Ø El índice que determina la posición de los elementos de un arreglo comienza siempre con cero. Ø C++ admite operar fuera del rango preestablecido por la dimensión, pero con resultados impredecibles.
Clasificación de los Arreglos
115
En base al número de índices que determinan la posición de un elemento en el arreglo podemos definir: Ø Arreglos lineales o unidimensionales: la posición de un elemento la determina un único índice. También conocidos como listas o vectores Ejemplo: en el caso de un arreglo lineal v declarado como: int v[200]; v[0]
v[1]
v[2]
v[3]
v[4]
v[5]
v[6]
..........
v[199]
23
56
71
19
33
90
48
..........
74
Ø Arreglos bidimensionales: se requieren 2 índices para posicionar un elemento en la colección. También conocidos como tablas o matrices. Ejemplo: observemos gráficamente el caso de un arreglo m de números de punto flotante de 5 filas por 12 columnas: float m[5] [12]; Nro. de columnas de la matriz
Nro. de filas de la matriz
0 1 2 3 4
0
1
2
3
5.34
6.71
4.22
12.02
...
...
...
...
11 7.92
1.55
1.16
1.65
11.34
...
...
...
...
1.16
6.87
3.12
6.37
13.00
...
...
...
...
3.16
3.21
5.90
3.24
13.72
...
...
...
...
5.98
4.04
8.00
10.11
13.82
...
...
...
...
4.43
Elemento [4][3] de la matriz. Elemento [3][0] de la matriz.
Ø Arreglos multidimensionales: se requieren más de 2 índices para posicionar un elemento en la colección. También conocidos como tablas o matrices multidimensionales. Ejemplo: arreglo de reales tri-dimensional. Analice algunos casos donde se requiera la necesidad de plantear estructuras como la de la figura.
i: índice para las filas
1.16 3.12 5.90 8.00 3.24 1.34 10.11
1.65 6.37 3.24 10.11 13.72 34.65 13.82
11.34 13.00 13.72 13.82 3.24 21.11 10.11
3.24 10.11 3.24 10.11 13.72 23.54 13.82
13.72 13.82 13.72 13.82 13.72 14.52 13.82
k: índice para la 3ra dimensión
j: índice para columnas
Organización en memoria de los arreglos C++ como la mayoría de los lenguajes de programación, reserva segmentos de para almacenar los arreglos, ubicando a cada elemento en forma contigua uno de otro. La memoria reservada se basa en la declaración del arreglo, y constituye segmento estático; esto es: si el arreglo se declara en main{ }, durante toda la vida o ejecución del programa, estará ocupando la porción de memoria necesaria y ese recurso no podrá ser empleado en otra cosa. Si se lo declara dentro de una función o bloque, ocupará memoria mientras el control de ejecución opere dentro de la función o del bloque.
Declaración e inicialización de un arreglo
116
Arreglos lineales Los arreglos estáticos en C++ se declaran y definen como cualquier otra variable. Usualmente se establece la dimensión de la estructura, es decir, la cantidad máxima de elementos que puede contener en el programa. const m = 100; ........... int z[m]; char mensaje[30]; double tabla[4] [12]; static float lista[200]; Tener en cuenta que C++ considera al primer elemento de un array en la posición 0, por tanto una declaración int x[3] implica que podremos referenciar en el programa a los elementos x[0], x[1], x[2]. Para inicializar un arreglo en el programa podemos recorrer cada elemento del arreglo para asignar los valores correspondientes, o bien, pueden inicializarse los elementos en la misma declaración, enumerando la lista de datos a asignar. // definición del arreglo x formado por 100 enteros al azar int x[100]; for (int i=0; i<99; i++) { x[i]= rand( ); } Nota: la función rand( ) pertenece a la librería stdlib.h y es una rutina matemática para generar números pseudoaleatorios enteros entre 0 y RAND_MAX. // definición e inicialización del array de caracteres z char z[7] = {‘J’, ‘M’, ‘L’, ‘P’, ‘Q’, ‘W’, ‘H’} /* definición de un array t con algunos valores iniciales; el resto de los elementos se inicializan a cero */ float t[5] = {7.1,8.4} /* El siguiente arreglo no tiene dimensión. Por defecto C++ asume como tamaño la cantidad de valores iniciales */ int m[]={34, 56, 20, 41, 72}
117
Arreglos bidimensionales Para operar con arreglos bidimensionales (matrices) debemos declarar las dos dimensiones de la tabla. /*Definición de una matriz mat de 10x6 elementos enteros */ int mat[10][6] // declaración de la matriz de enteros mat /* Inicialización de la matriz mat recorriéndola por filas con datos ingresados por consola */ int mat[10][6] ; for (int i=0; i<10; i++) for (int j=0; j<6; j++) { cout<<"dato de fila "<<i<<" columna "<<j<<":"; cin >> mat[i][j]; } El ejemplo siguiente contiene el código C++ que permite mostrar una matriz dispuesta en filas y columnas en la pantalla.
//Ejemplo: mostrar //en forma de tabla
una
matriz
de
2x
3
elementos
#include<iomanip> #include<conio.h> int main() { int m[2][3]={12,34,56,78,90,100}; int i,j; for (i=0;i<2;i++) {for (j=0; j<3; j++) {cout<<setw(4)<<m[i][j]; //escribe elementos de una fila } cout<<endl; //avanza a la próxima línea } return 0; }
En el ejemplo anterior se ha inicializado una matriz m de 6 elementos enteros donde se asignan los datos por filas. Es decir que: int m[2][3]={12,34,56,78,90,100}; ha permitido asignar los datos de la manera siguiente: m[0][0]=12 m[1][0]=78
m[0][1]=34 m[1][1]=90
m[0][2]=56 m[1][2]=100
SI quisiéramos asignarlos por columnas solo deberíamos intercambiar los ciclos for del ejemplo.
118
Dimensión y longitud de un arreglo Los arreglos son estructuras estáticas que requieren establecer la cantidad de elementos que pueden almacenar. Pero en la práctica no siempre se conoce la cantidad exacta de elementos a asignar al arreglo; entonces se debe dimensionar por exceso. El valor empleado para declarar el arreglo se denomina dimensión D y la cantidad real de elementos utilizados es la longitud L del arreglo. Si en un programa L<D habrá posiciones vacías en la estructura, lo cual no representa u propblema. Obviamente, debemos tener cuidado en recorrer el arreglo en toda su longitud L y no en toda su dimensión D.
119
Arreglos como parámetros de funciones Es posible utilizar arreglos como parámetros de funciones. En C++ no es posible pasar por valor un bloque de memoria completo como parámetro a una función, aún si está ordenado como un arreglo, pero está permitido pasar su dirección de memoria, lo cuál es mucho más rápido y eficiente. Al pasar una dirección de memoria estamos efectuando un pasaje por referencia. Para admitir arreglos lineales como parámetros lo único que se debe hacer al declarar la función es especificar en el argumento el tipo de dato que contiene el arreglo, un identificador y un par de corchetes vacíos [ ]. Por ejemplo, observemos la siguiente función: void
leer_arreglo(int arg[])
Vemos que la función leer_arreglo( ) admite un parámetro llamado arg que es un arreglo de enteros (int). ¿Donde está el pasaje por referencia o la dirección de memoria del inicio del arreglo? Respuesta: en el nombre del arreglo. El nombre del arreglo identifica a una variable que contiene la dirección de memoria donde comienza el bloque donde se aloja el arreglo. En otras palabras: el nombre del arreglo es una variable que contiene la dirección de memoria del elemento 0 del arreglo. Para llamar a la función leer_arreglo() del ejemplo anterior debemos utilizar como parámetro actual un arreglo; para ello es suficiente utilizar el identificador del arreglo: int miarreglo [30]; leer_arreglo(miarreglo);
En el siguiente ejemplo se invoca 2 veces a la función muestra_arreglo( ) pasándole en cada caso un arreglo y su longitud. // Ejemplo: arreglos como parámetros #include <iostream.h> #include <iomanip.h> void muestra_arreglo (int lista[], int largo) int main () { int v1[] = {35, 41, 22}; int v2[] = {12, 4, 6, 15, 10}; muestra_arreglo(v1,3); muestra_arreglo(v2,5); return 0; } void muestra_arreglo (int lista[], int largo) { for (int i=0; i<largo; i++) cout<<setw(4)<<lista[i]; cout<<endl;}
La salida del programa será: 35 12
41 4
22 6
Obsérvese que en muestra_arreglo() dimensión.
15 el
10 ejemplo
empleando
se como
invoca dos argumentos
120
veces a la función arreglos de diferente
Arreglos multidimesionales Si se trata de pasar como parámetro un arreglo de más de una dimensión, el parámetro formal debe tener los corchetes correspondientes al primer índice vacíos, pero establecer explícitamente las otras dimensiones. void
leer_tabla(int t[][10], int num_filas);
El modificador const y parámetros de tipo arreglo Hemos visto que al pasar un arreglo como parámetro, se pasa la dirección de memoria del inicio del arreglo y por lo tanto estamos efectuando un pasaje de parámetros por referencia. Esto implica que cualquier modificación efectuada en uno o más elementos del arreglo durante la ejecución de una función, se producirá la automática modificación del arreglo utilizado como parámetro actual o de llamada (se trata en realidad de un único arreglo pues se está trabajando sobre esa única dirección de memoria). Para evitar que un arreglo sea modificado al pasarlo como parámetro, debe utilizarse la etiqueta const precediendo al parámetro formal en el prototipo de la función. Observemos las dos funciones siguientes: float permite_cambiar(int lista[], int n); { ...... lista[3]= 255; //modifica el parámetro de llamada ..... } float no_permite_cambiar(const int lista[], int n); { ...... lista[10]= 320; //error de compilación ..... } En la primer función, el cambio efectuado en lista[3] se reflejará en el arreglo que se utilice como parámetro para llamar a esta función. La segunda función producirá un error de compilación, pues se establece con const que la posición de memoria a la que se quiere acceder es de solo lectura y no puede modificarse el valor allí alojado.
121
Estructuras. El tipo struct. Un arreglo es una estructura de datos homogénea, es decir solo admite una colección de elementos de igual tipo. A menudo se requiere organizar los datos de una entidad en una estructura, pero admitiendo información de diferente naturaleza (tipo). C++ dispone para este caso del tipo struct. Un struct en C++ es una colección de componentes, los cuales pueden ser de diferente tipo. Cada componente o miembro debe declararse individualmente. Su sintaxis general es la siguiente: struct compuesta( miembro 1; miembro 2; miembro 3; ..... miembro n; ); En la definición es obligatorio explicitar el tipo struct y a continuación el identificador (compuesta en el ejemplo) de la estructura. Luego, entre llaves deben definirse cada uno de los componentes o miembros. Tomemos el siguiente ejemplo: ficha apellido nombres Dni Edad
struct ficha { char apellido[20]; char nombres[20]; long dni; int edad; int
Cant_materias
cant_materias; };
Los miembros individuales de una estructura pueden ser de tipos simples, arrays, punteros e inclusive struct. En cuanto a los nombres de estos miembros o componentes deben ser diferentes, pero pueden coincidir con el identificador de alguna otra variable definida fuera de dicha estructura. No se puede inicializar un miembro al definir la estructura. Al definir una estructura estamos planteando el esquema de la composición pero sin definir ninguna variable en particular. Para declarar variables de tipo struct se debe indicar lo siguiente: struct ficha x,y;
// x e y se declaran de tipo ficha
122
Se puede combinar la definición de la composición de la estructura con la declaración de las variables y con su inicialización: struct ficha{ char apellido[20]; char nombres[20]; long dni; int edad; int cant_materias; } x =(“Lopez”, “Gerardo”, 24567890, 21, 11);
En este ejemplo, ficha es el nombre de la estructura, x la variable de tipo ficha y los datos especificados entre { } los valores iniciales de los miembros apellido, nombres, dni, edad, cant_materias.
123
Arreglo de structs Es posible emplear arreglos como miembros de una composición struct. Pero también podemos definir un arreglo cuyos elementos sean estructuras. struct ficha { char apellido[20]; char nombres[20]; long dni; int edad; int cant_materias; }; struct ficha z[5] =( {“Lopez”,“Gerardo”,24567890, 21, 11}, {"Giménez","Ana",25689901,20), {"Zapata","Andrés", 26701231,19,8}, {"Farías","Marina",23199870,22,15}, {"Martino","Manuel",24500654,21,10} }
En el caso anterior se declara e inicializa un arreglo z de 5 elementos de tipo ficha. Para mostrar el miembro dni del tercer elemento del arreglo debemos escribir: cout<<z[2].dni; Para cambiar el miembro edad a 22 en el 4to elemento del arreglo z debemos escribir: z[3].edad=22; Para leer los apellidos, nombres y dni en modo consola: for (int i=0; i<5; i++) { cin.getline( z[i].apellido,15); cin.getline( z[i].nombres,20 ); cin>>z[i].dni; } Para mostrar un listado con los miembros apelido y dni del arreglo z, se codifica de la siguiente forma: for (int i=0; i<5; i++) { cout<<z[i].apellido<<" "<<z[i].dni<<endl; }
124
Procesamiento de una variable struct Para procesar la información relacionada a una estructura podemos operar con sus miembros individualmente o en ocasiones con la estructura completa. Para acceder a un miembro individual debemos utilizar el identificador de la variable struct, un punto de separación y el nombre del miembro componente. variable.miembro Considere el siguiente código de ejemplo. 1. 2. 3. 4. 5. 6. 7.
#include <iostream.h> //-------------------------------------------------------typedef struct{ char ape[15]; char nom[20]; long dni; } registro; //--------------------------------------------------------8. int main( ) 9. { registro f,z; 10. cin.getline(f.ape,15); 11. cin.getline(f.nom,20); 12. cin>>f.dni; 13. z=f; 14. cout<<z.ape<<" "<<z.nom<<"---DNI:"<<z.dni<<endl; 15. return 0; 16. }
Observe en la línea 9 la declaración de las variables struct f y z. Las líneas 10, 11 y12 permiten asignar datos ingresando los valores de los miembros en modo consola. En la línea 14 se asigna la variable struct completa f a una variable de igual tipo z. En 15 se muestran los miembros de z.
125
Tipos definidos por el usuario: typedef Es posible en C++ identificar a tipos existentes o estructuras de datos con nombres y tratarlos como si fueran nuevos tipos de datos. Entonces, las variables o funciones podrán declararse en base a estos nuevos nombres que representan tipos de datos de C++. Estos tipos de datos definidos por el usuario no tiene la importancia que revisten en otros lenguajes (Pascal por ejemplo). Para asignar un nombre correspondiente a una definición de tipoy en C++ debemos empelar la palabra reservada typedef. Veamos algunos ejemplos: typedef unsigned char byte; /*se le da el alias byte a los char sin signo */ typedef int tabla[50][12]; /*definición del nombre tabla como matriz de 50x12 enteros */ typedef struct {
char apellido[20]; char nombres[20]; long dni; int edad; int cant_materias; } ficha // definición del tipo ficha como estructura En base a las definiciones de tipo anteriores so válidas las siguientes declaraciones: byte b; ficha x,y[200]; tabla m,t; En el último ejemplo, b se declara de tipo byte; x es una variable individual que puede almacenar la información de una entidad de acuerdo a los miembros definidos en el tipo struct ficha; la variable y es un array donde cada elemento es del tipo struct ficha.; las variables m y t se declaran como arreglos bidimensionales de 50x12 elementos enteros.
126
Síntesis 1. Un arreglo es una colección de datos relacionados de igual tipo e identificados bajo un nombre genérico único. 2. La estructura completa ocupa un segmento de memoria único y sus elementos se almacenan en forma contigua. 3. Para procesar un elemento del arreglo, se debe especificar el nombre de la estructura y uno o más índices que determinan la posición relativa del elemento. 4. El índice que determina la posición de los elementos de u arreglo comienza siempre con cero. 5. En la declaración se debe establecer la cantidad de elementos (dimensión) que puede tener como máximo el arreglo en el programa o definir los elementos que lo componen. 6. La dimensión de un arreglo debe ser siempre mayor o igual a su longitud. 7. Si se requiere 2 índices para establecer la posición de un elemento, el arreglo es una tabla o matriz. Con 3 índices es una matriz tridimensional y con más índices una matriz multidimensional. 8. El nombre de un arreglo representa la dirección de memoria del inicio el arreglo (de su primer elemento). 9. Al pasar arreglos como parámetros de funciones la relación entre parámetro formalparámetro actual es similar al pasaje por referencia. Para evitar cambios en el arreglo enviado en la llamada a una función se debe preceder a la variable arreglo establecida como parámetro formal en el prototipo de la función con el modificador const. 10. Un struct es una estructura de datos e C++ que permite organizar un conjunto de datos relacionados de diferente tipo. Estos datos que conforman el struct se denominan miembros. 11. Los miembros de un struct pueden ser de tipo simple o también otras estructuras de datos: arreglos, structs, etc. 12. También los elementos de un arreglo pueden ser de tipo struct. 13. Los objetos cin y cout para flujos de entrada y salida no permiten operar estructuras de datos completas. Se deben utilizar los componentes de una estructura, como el elemento de un arreglo o un miembro de un struct. 14. C++ admite la identificación de tipos a través de la palabra clave typedef. Estas definiciones suelen ser globales y se realizan usualmente fuera de la función principal de programa main().
127
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 10 Búsqueda y ordenamiento
128
UADER- FCyT -- UNIDAD 10 Búsqueda y Ordenamiento INTRODUCCIÓN Tanto la búsqueda como el ordenamiento constituyen dos aspectos relevantes dentro del manejo de Información. Estos algoritmos son clásicos y su conocimiento es fundamental para cualquier programador. La búsqueda está relacionada con procesos de recuperación de información y consiste en localizar un dato determinado dentro de un conjunto. Dado un arreglo y un valor del mismo tipo que sus componentes, la búsqueda consiste en determinar si ese valor está en el arreglo y qué posición ocupa. El ordenamiento provee un medio para la organización de la información, facilitando de esta manera la recuperación posterior de los datos. Dado un conjunto de datos, ordenar dicho conjunto, significa obtener un nuevo conjunto donde sus datos se encuentren ordenados ya sea en forma ascendente o descendente. En ambos casos, existen distintos métodos, cuya eficiencia está directamente relacionada con él número de comparaciones y el movimiento de los datos llevados a cabo para completar la operación.
BÚSQUEDA Dado un conjunto de datos se trata de encontrar un dato particular dentro del mismo. El dato que se quiere buscar, puede o no estar entre los elementos del conjunto. Esta operación es muy frecuente dentro de los procedimientos algorítmicos, por ejemplo, encontrar un artículo determinado entre todos los que figuran en la lista de precios de una empresa. El problema de búsqueda puede plantearse de la siguiente forma: Dado un conjunto de N elementos distintos y un dato K, determinar: - si K pertenece al conjunto y su ubicación dentro del mismo - si K no pertenece al conjunto. Para resolver este problema estudiaremos dos métodos: 1) Búsqueda Secuencial o Lineal 2) Búsqueda Binaria o Dicotómica
1) Búsqueda Secuencial o Lineal Este método consiste en recorrer, de izquierda a derecha, todo el conjunto, comparando K con cada uno de los elementos del mismo. El proceso finaliza al encontrar el dato buscado o al llegar al final del conjunto, en cuyo caso podemos concluir que K no figura en el conjunto dado. En los casos en que pueda aparecer el valor repetido, el algoritmo indica el de índice menor (en otras palabras, el primer elemento que coincida con K). Este método es válido tanto para vectores desordenados como ordenados. Al encontrar el elemento debemos suspender la búsqueda y salir del ciclo. Es necesario establecer en el algoritmo cómo se ha salido del ciclo de búsqueda. Es decir, si fue por haber encontrado el dato buscado o por haber llegado al final del arreglo sin encontrar el dato. Esto puede lograrse dando diferentes valores a la variable de control del ciclo.
129
Este algoritmo requiere una sola comparación si el elemento buscado es el primer elemento del conjunto, o N comparaciones, en el peor de los casos, si es el último o no pertenece al conjunto. En promedio, se requieren (N+1)/2 comparaciones. En C++, un algoritmo de búsqueda secuencial puede plantearse de la siguiente manera: #include <iostream> using namespace std; //Búsqueda Secuencial int main() { int A[10], i, band=0, dat, pos, n=5; for (i=0; i<n; i++) { cout<<"Dato: "; cin>>A[i]; } cout<<"*****************************************"<<endl; cout<<"Ingrese el dato a buscar: "; cin>>dat; i=0; while (i < n) { if (A[i] == dat) { band=1; pos=i+1; i=n; } i++; } cout<<"*****************************************"<<endl; if (band == 0) cout<<"El dato no fue hallado"; else cout<<"El dato fue hallado en la posición "<<pos; return 0; }
Como podrá observarse, en el algoritmo anterior puede reducirse el uso de variables auxiliares, pero se pretende mostrar de manera clara los diferentes puntos a considerar Búsqueda Secuencial o Lineal en una Matriz El método de búsqueda visto puede aplicarse también a un conjunto de datos dispuestos en una matriz. En este caso, se realiza mediante el anidamiento de dos estructuras iterativas, cuya finalización vendrá dada por la aparición del valor buscado o la finalización de la matriz. Usualmente se comienza recorriendo la matriz por filas, aunque cambiando de posición los índices con sus correspondientes límites, se puede hacer igualmente por columnas.
130
2) Búsqueda Binaria Este método sólo puede aplicarse a conjuntos cuyos elementos están ordenados, ya sea en forma ascendente o descendente. También se lo conoce con el nombre de búsqueda por bisección o dicotómica. Para la explicación del método, supongamos que queremos buscar un valor en un vector ordenado en forma ascendente (de menor a mayor). El método consiste en partir sucesivamente por mitades el vector y preguntar si el valor buscado es el elemento ubicado en la mitad de la tabla. Si la respuesta es positiva se finaliza la búsqueda. Sino, el valor buscado debe estar en una de las dos mitades del vector con lo cual se descartan todos los elementos de la otra mitad. Con este segmento del vector donde posiblemente está el elemento buscado, se repite el proceso descripto, partiéndolo por la mitad y preguntando si el valor buscado es igual al contenido del elemento de la mitad. Este proceso se repite hasta que se encuentre el valor buscado o hasta que se llegue al límite de consultas en cuyo caso, el valor buscado no está en el vector. En los casos en que existan repeticiones en el vector del valor buscado, este algoritmo obtendrá uno de ellos aleatoriamente según los lugares que ocupen, los cuales necesariamente son consecutivos. Descripción del Método El primer paso consiste en encontrar aproximadamente, la posición media del vector y examinar el valor que contiene Si A es el vector, entonces se compara el dato buscado K con A[medio]. Al hacer dicha comparación, puede suceder: a) K = A[medio] Finaliza la búsqueda y el elemento buscado se encontró, en la posición “medio”. b) K < A[medio] En este caso, se considera la primera mitad de la tabla como la próxima tabla de búsqueda. En esta nueva tabla, se calcula nuevamente el elemento situado en la posición central y se repite todo el proceso presentándose nuevamente una de las tres opciones posibles (a, b ó c). c) K > A[medio] Se considera la segunda mitad de la tabla y se procede como en el caso b). El procedimiento se repetirá en forma iterativa hasta hallar el elemento buscado en alguna de las sucesivas iteraciones, o hasta agotar la tabla (cuando el intervalo de búsqueda queda vacío), en cuyo caso dicho elemento no pertenece al conjunto dado. La posición media del vector se determina en cada paso como la parte entera de la siguiente expresión: (valor inferior del índice + valor superior del índice) / 2 En la expresión precedente, los valores inferiores y superiores del índice se calculan en cada nueva iteración. Ejemplo Dado el siguiente conjunto de 8 elementos ordenados en forma ascendente 5 12 15 17 22 27 33 38 1 2 3 4 5 6 7 8 El elemento a buscar es K = 33
131
•
Determinamos primero la posición media del vector:
medio = (1+8)/2 =4 (recordemos que C++ hace división entera si opera enteros). El dato ubicado en dicha posición es A(4)=17 • Como K=33 es mayor que 17, se eliminan los elementos A[1], A[2] y A[3] y se continúa la búsqueda con los elementos de la segunda mitad: A[S], A[6], A[7] y A[S]. • Se determina el elemento central de esta nueva tabla, donde el valor del índice inicial es 5 y el final 8. Por lo tanto: medio = (5+8) /2) = 6 •
Y el elemento central es ahora A[6]=27.
Como el valor K es mayor que A[6] se deben analizar los elementos que están a su derecha: A[7] y A[S]. • Para hallar el elemento central de este nuevo conjunto, se debe considerar el 1 valor del índice Inicial 7 y el final 8. Luego, la posición media está dada por: medio = (7+8) /2 = 7 ==> A[medio] = A[7] =33 • Como A[7]) es igual a K, la búsqueda finaliza determinando que el elemento está en la posición 7. Vimos en el ejemplo que en cada paso se analiza un vector, para el cual se definen diferentes valores extremos del índice. Por lo tanto para plantear el algoritmo se necesitan: una variable, para, guardar el valor Inicial del índice del vector que se está analizando; una segunda variable para el valor superior y una tercera, para guardar el valor de la posición central. En el primer paso, el valor inicial es 1 y el superior es N. Luego dependerán del vector que se considere para búsqueda.
Observación: Deberá recordarse que en C++, los arreglos tienen dimensión N y el índice varía entre 0 y N-1. Pero, ¿hasta cuándo se debe consultar la tabla ?. Existe un número máximo de particiones, agotado el cual podemos suponer que el valor buscado no pertenece a la misma. Este máximo está dado por la menor potencia de 2 que excede al número de elementos del vector que se consulta. Así, si el vector tiene 500 elementos, el número máximo de particiones es 9, porque 9 es la mínima potencia de 2 que excede a 500.
132
En C++, un algoritmo de búsqueda binaria puede plantearse de la siguiente manera:
#include <iostream> using namespace std; //Búsqueda Binaria int main() { int li, ls, n, medio, dat, A[10], i; cout<<"Ingrese la cantidad de datos a leer: "; cin>>n; for (i=0; i<n; i++) { cout<<"Dato: "; cin>>A[i]; } cout<<"*****************************************"<<endl; cout<<"Ingrese el dato a buscar: "; cin>>dat; li=0; ls=n; medio= (li+ls)/2; while ((li <= ls) && (dat != A[medio])) { if (dat < A[medio]) ls=medio-1; else li=medio+1; medio= (li+ls)/2; } cout<<"*****************************************"<<endl; if (li > ls) cout<<"Elemento no encontrado"; else cout<<"Elemento encontrado en posición: "<<medio+1; return 0; }
133
ORDENAMIENTO En los métodos de ordenamiento, además de considerar el tiempo de ejecución del mismo, se debe tener en cuenta el uso eficiente de la memoria. Entre los métodos de ordenamiento conocidos, podemos hacer una clasificación sobre la base de su eficiencia. Ello indica que los métodos avanzados son mucho más eficientes. Pero antes de pasar a algoritmos más rápidos estudiaremos los métodos directos, por lo siguiente: •
Son más sencillos y obvios y nos permitirán analizar los principios de clasificación.
•
Los algoritmos son cortos y fáciles de entender.
•
Los métodos avanzados, si bien requieren menor número de operaciones, se basan en algoritmos complejos y, para N pequeños los métodos directos son más rápidos.
Los tipos de ordenamientos que pueden realizarse son: •
Ordenamiento ascendente o creciente: Consiste en situar los valores mayores a la derecha y los menores a la izquierda. Los valores repetidos quedarán en posiciones consecutivas.
•
Ordenamiento descendente o decreciente: Es el ordenamiento inverso al anterior.
MÉTODOS DIRECTOS DE ORDENAMIENTO 1) Selección Directa o Mínimos Sucesivos El problema planteado para la explicación del método es: Dado un vector A de N elementos, ordenar sus elementos en forma ascendente. Este método consiste en colocar en la primera posición del vector el menor de los elementos del mismo; luego en la segunda posición, el menor de los N-1 elementos restantes; proseguir con los N-2 elementos restantes seleccionando el menor para la tercera posición y, así sucesivamente hasta que solamente quede el mayor de todos los elementos en la última posición. Para ello, en la primer recorrida (o pasada) del vector debemos comparar el contenido del primer elemento con el valor del segundo elemento, y si este último resulta menor, intercambiar valores de tal manera que en la primera posición siempre quede el menor. Luego repetir este proceso entre el primero y el tercero, luego entre el primero y el cuarto y así sucesivamente, hasta comparar el primer elemento con el último. De esa forma, tendremos seguridad que en la primera posición dejamos el menor de todos los elementos del arreglo. Consideremos ahora los N-1 elementos restantes, desde el segundo elemento hasta el último. Si realizamos el proceso de comparación dado para la primer pasada pero ahora entre el segundo elemento y todos los restantes, obtendremos en la segunda posición del vector, el menor entre todos los elementos analizados. Para ordenar todo el vector, repetimos este proceso sucesivamente hasta comparar finalmente el penúltimo elemento contra el último, después de lo cual termina el proceso.
134
Ejemplo: 12 1
Dado el siguiente vector A de dimensión N=6 10 2
17 3
9 4
14 5
8 6
La primer pasada al comparar A[1] con cada uno de los elementos del vector, resultan los siguientes intercambios: con A[2] 10 12 17 9 14 8 con A[3]
10 12 17 9 14 8 (sin cambios)
con A[4]
9 12 17 10 14 8
con A[5]
9 12 17 10 14 8 (sin cambios)
con A[6]
8 12 17 10 14 9
Obtenemos un vector que contiene en la primera posición el menor de todos sus valores. Ahora, partiendo de este último vector, debemos realizar el mismo proceso para deja A[2] el menor de todos los elementos. Al comparar A[2] con cada uno de los elementos restantes obtendremos el siguiente vector 8
9
17
12
14
10
En las sucesivas pasadas nos quedan los siguientes vectores 8 8 8
9 9 9
10 10 10
17 12 12
14 17 14
12 14 17
135
En C++, un algoritmo de ordenamiento por mínimos sucesivos puede plantearse de la siguiente manera: #include <iostream> using namespace std; //Ordenamiento por mínimos sucesivos int main() { int n, A[50], i, j, aux; cout<<"Ingrese la cantidad de datos a leer: "; cin>>n; for (i=0; i<n; i++) { cout<<"Dato: "; cin>>A[i]; } for (i=0; i<(n-1); i++) for (j=i+1; j<n; j++) { if (A[i] > A[j]) { aux= A[i]; A[i]= A[j]; A[j]= aux; } } cout<<endl; cout<<"ARREGLO ORDENADO"<<endl; for (i=0; i<n; i++) cout<<vec[i]<<endl; return 0; }
Observación: Deberá recordarse que en C++, los arreglos tienen dimensión N y el índice varía entre 0 y N-1.
ATENCIÓN!: Si al ordenar un arreglo existen otros arreglos relacionados con éste, al momento de intercambiar valores, deberán intercambiarse todos los arreglos relacionados para que la información guardada siga siendo consistente.
136
2) Intercambio Directo o Método de la Burbuja Esto método se funda en clasificar pares de elementos contiguos, comenzando desde atrás hacia adelante (de derecha a izquierda), de modo que al recorrer el vector la primera vez el elemento más pequeño ocupará la primera posición. Luego, recorremos el vector desde su último elemento A[N], hasta el A[2] haciendo los intercambios necesarios -SIEMPRE ENTRE ELEMENTOS ADYACENTES. Luego recorremos desde A[N] hasta A[3], y así sucesivamente. Con un poco de imaginación si colocamos el arreglo en posición vertical, poder asimilar a burbujas los elementos que ascienden una posición. De allí, el nombre del método. Supongamos que se dé el caso de que en el primer recorrido el arreglo quede ordenado. De acuerdo a la estrategia planteada, el método realizará recorridos innecesarios, con la consiguiente ineficiencia en el proceso. Esto se puede evitar si el algoritmo “recordase” que en la última pasada no hubo intercambios, lo que mejoraría el método notoriamente. Este método admite aún otras mejoras en su eficiencia.
3) lnserción Directa o Método de la Baraja Supongamos que queremos clasificar en forma ascendente (de menor a mayor) el siguiente arreglo A[i] de 8 elementos: 44
55
12
42
94
18
6
67
1
2
3
4
5
6
7
8
Este método consiste en tomar el elemento A[i] del arreglo y comenzar a compararlo con los elementos que están a su izquierda, hasta encontrar un elemento menor que A[i]. Entonces, se inserta A[i] en ese lugar. Obviamente el método comienza a investigar el segundo elemento [ A[2] ] del arreglo.
137
En nuestro ejemplo los pasos sucesivos serían: Elemento a Insertar Arreglo A[i] Vector inicial
44 55 12 42 94 18 06 67
A[2]
44 55 12 42 94 18 06 67
A[3]
12 44 55 42 94 18 06 67
A[4]
12 42 44 55 94 18 06 67
A[5]
12 42 44 55 94 18 06 67
A[6]
12 18 42 44 55 94 06 67
A[7]
06 12 18 42 44 55 94 67
A[8]
06 12 18 42 44 55 67 94
Analicemos en el ejemplo el paso en que se insertó el elemento A[4]=42. Se fue comparando este elemento con los de su izquierda hasta ubicarlo en la nueva posición A[2]. Los elementos 55 y 44, a su vez, fueron corridos un lugar a la derecha. Notemos que la regla de detención del desplazamiento de X hacia la izquierda está dada por dos condiciones posibles: 1-
Se halló un elemento A[i] <X
2-
Se alcanzó el extremo izquierdo del arreglo.
138
METODOS DE ORDENAMIENTO AVANZADOS 1) Método de Shell D. L. Shell propuso en 1959 un refinamiento del método de inserción directa que hemos visto, en el cual se produce un acercamiento de los elementos descolocados hacia su posición correcta en saltos de mayor longitud. Se repite un mismo proceso con una distancia de comparación que, inicialmente es la mitad de la longitud del vector y que se va reduciendo a la mitad en cada repetición 4 hasta que dicha distancia vale 1. Cada pasada termina al detectarse que no se ha producido ningún cambie elementos en la distancia correspondiente. Analicemos su modificación sobre un vector ejemplo A de 9 elementos. Primero conforma grupos con todos los elementos que estén separados 4 posición es decir A[1] con A[5], A[2] con A[6], A[3] con A[7], A[4] con A[8], y A[5] con A[9]. Luego clasifica estos grupos con el método de Inserción directa. A este proceso lo llama “clasificación 4”. Luego agrupa a todos los elementos separados por 2 posiciones, o sea: A[1] con A[3], A[2] con A{4], A[3] con A[5] y así sucesivamente. Y clasifica cada uno de estos grupos por inserción directa. Por último agrupa los elementos distanciados por 1 posición, es decir, elementos adyacentes; con lo que obtiene un solo grupo, que es el mismo arreglo. Al aplicarle ahora inserción directa, queda completamente ordenado. El último paso es el método de inserción directa propiamente dicho, solo que su trabajo será mucho más ágil, debido a los acomodamientos previos. Veamos como funciona el método en el vector ejemplo: 3
2
4
6
7
3
5
1
1
1
2
3
4
5
6
7
8
9
Primer paso: distancia de comparación 4 3
2
4
6
7
3
5
1
1
3
2
4
1
1
3
5
6
7
3
2
4
1
1
3
5
6
7
1
2
4
1
3
3
5
6
7
Ordenados los pares de distancia 4
139
Segundo paso: distancia de comparación 2 1
2
4
1
3
3
5
6
7
1
1
3
2
4
3
5
6
7
Ordenados los pares de distancia 2
Tercer paso: distancia de comparación 1 1
1
3
2
4
3
5
6
7
1
1
2
3
3
4
5
6
7
Ordenados los pares de distancia 1 Estrategia
Shell
Conocer N
Conocer elementos *
Intervalos *
Calcular intervalo
Informar vector ordenado. *
Cambiar intervalo
Inicializar señal e índice
140
*
Ordenar
*
2) Método QuickSort El ordenamiento rápido (quicksort en inglés) es un algoritmo basado en la técnica de divide y vencerás, que permite, en promedio, ordenar n elementos en un tiempo proporcional a n log n. Esta es la técnica de ordenamiento más rápida conocida. Fue desarrollada por C. Antony R. Hoare en 1960. El algoritmo original es recursivoi, pero se utilizan versiones iterativas para mejorar su rendimiento (los algoritmos recursivos son en general más lentos que los iterativos, y consumen más recursos) Este método consiste en: •
Elegir un elemento de la lista de elementos a ordenar, al que llamaremos pivote.
Resituar los demás elementos de la lista a cada lado del pivote, de manera que a un lado queden todos los menores que él, y al otro los mayores. En este momento, el pivote ocupa exactamente el lugar que le corresponderá en la lista ordenada. •
La lista queda separada en dos sublistas, una formada por los elementos a la izquierda del pivote, y otra por los elementos a su derecha. •
Repetir este proceso de forma recursiva para cada sublista mientras éstas contengan más de un elemento. Una vez terminado este proceso todos los elementos estarán ordenados. Como se puede suponer, la eficiencia del algoritmo depende de la posición en la que termine el pivote elegido. •
En el mejor caso, el pivote termina en el centro de la lista, dividiéndola en dos sublistas de igual tamaño. •
En el peor caso, el pivote termina en un extremo de la lista. El peor caso dependerá de la implementación del algoritmo, aunque habitualmente ocurre en listas que se encuentran ordenadas, o casi ordenadas. •
La mayoría de optimizaciones que se aplican al algoritmo se centran en la elección del pivote. Veamos como funciona con un ejemplo En el siguiente ejemplo se marcan el pivote y los índices i y j con las letras p, I y J respectivamente. Comenzamos con la lista completa. El elemento divisor será el 4: 5
3
7
6
2
1
4 p
Comparamos con el 5 por la izquierda y el 1 por la derecha. 5 I
i
3
7
6
2
1 J
4 p
Un algoritmo recursivo es un algoritmo que expresa la solución de un problema en términos de una
llamada a sí mismo. La llamada a sí mismo se conoce como llamada recursiva. Observar el siguiente ejemplo de una función para el cálculo del factorial de un número. int factorial(n) { if (n<2) return 1; else return n * factorial(n-1); }
141
5 es mayor que cuatro y 1 es menor. Intercambiamos: 1 I
3
7
6
2
5 J
4 p
Avanzamos por la izquierda y la derecha: 1
3 I
7
6
2 J
5
4 p
3 es menor que 4: avanzamos por la izquierda. 2 es menor que 4: nos mantenemos ahí. 1
3 I
7
6
2 J
5
4 p
7 es mayor que 4 y 2 es menor: intercambiamos. 1
3
2 I
6
7 5 J
4 p
Avanzamos por ambos lados: 1
3
2
6 I
7 5 J
4 p
En este momento termina el ciclo principal, porque los índices se cruzaron. Ahora intercambiamos lista[i] con lista[sup] (pasos 16-18): 1
3
2
4 p
7
5
6
Aplicamos recursivamente a la sublista de la izquierda (índices 0 - 2). Tenemos lo siguiente: 1
3
2
1 es menor que 2: avanzamos por la izquierda. 3 es mayor: avanzamos por la derecha. Como se intercambiaron los índices termina el ciclo. Se intercambia lista[i] con lista[sup]: 1
2
3
El mismo procedimiento se aplicará a la otra sublista. Al finalizar y unir todas las sublistas queda la lista inicial ordenada en forma ascendente. 1
2
3
4
5
6
7
142
Universidad Autónoma de Entre Ríos Facultad de Ciencia y Tecnología Sede: Oro Verde
FUNDAMENTOS DE PROGRAMACIÓN
UNIDAD 11 Archivos
143
UADER- FCyT -- UNIDAD 11 Archivos INTRODUCCIÓN Los datos tratados por un algoritmo, como hemos visto hasta ahora, tienen dos limitaciones importantes: por un lado, la cantidad de datos que puede almacenar la memoria principal del procesador es limitada; por otro, su existencia esta condicionada al tiempo que dure la ejecución del algoritmo, es decir, cuando termina el algoritmo todos sus datos desaparecen de la memoria central del procesador y se pierden. Se utilizan entonces las estructuras de datos externas denominadas FICHEROS o ARCHIVOS para manipulación y almacenamiento de datos para usos futuros. Los archivos no están contenidos en la memoria central del procesador, sino que residen en otro tipo de memoria denominada memoria auxiliar o secundaria y más exactamente en otro dispositivo: discos, CD, pendirve, DVD, diskettes. Esta memoria nos permite guardar datos o disponer de ellos en el momento que nos son necesarios mediante una escritura o lectura respectivamente.
¿Qué es un archivo? Definimos como archivo a la estructura de información relacionada, almacenada en forma permanente e independiente del programa que la utiliza.
Características de los archivos ü Siempre se hallan almacenados en soportes o dispositivos externos a la memoria de la computadora. ü La información que contienen es independiente del programa que la utiliza. ü Los programas de tratamiento que acceden a esta información lo hacen a través de unidades lógicas: registros, variables simples, líneas. ü La información guardada en los archivos es permanente, hasta tanto una acción de un programa no la modifique.
Permanencia de la información de un archivo Los archivos contienen información que puede permanecer invariable en un lapso grande de tiempo, pero también pueden contener datos que deben actualizarse con cierta frecuencia; esto último se realiza a través de la información que se incorpora desde otros archivos o de datos que se ingresan interactivamente a través de alguna interfaz de usuario. Estas modificaciones de los datos de un archivo que puede hacer un programa está supeditada a las características del soporte; por ejemplo, un CD Rom no permite que se re-escriba sobre él.
Soportes de almacenamiento Los archivos se almacenan en diferentes medios o soportes: disquetes, discos rígidos, cintas magnéticas, CD Roms, memorias flash, etc., los cuales son controlados por dispositivos
144
externos a la computadora: controladora de disquetes (disquetera), controladora del disco rígido, lector de cinta, lector/grabador de CD, etc. Habitualmente los archivos que son accedidos por los programas se almacenan en el disco de la computadora (disco rígido) y los otros medios se utilizan como soporte portable para llevar información de un lado a otro y como soporte de resguardo de información (backup). Además, el disco es de gran capacidad y vida útil comparado con los otros medios. Un soporte también puede definir el modo en que un programa accede a los datos de un archivo. Por ejemplo: las cintas magnéticas no son direccionables y sólo pueden ser accedidas secuencialmente; los CD ROMs sólo pueden ser accedidos para operar archivos de entrada (lectura), pero son direccionales y admiten acceso directo a sus datos; los discos rígidos y las memorias flash son de lecto-escritura y direccionables.
Tipos de archivos según la Organización de los Datos y el Tipo de Acceso Los archivos pueden clasificarse según la forma en que se organiza la información que contienen y la forma en que se accede a los datos. Tenemos: ü Archivos secuenciales ü Archivos de acceso directo ü Archivos secuenciales indexados Archivos Secuenciales: cada unidad de información, salvo la primera tiene otra que le antecede y todas excepto la última una que le sigue. El orden en que aparecen, es el orden en que han sido escritas. En este tipo de organización, por lo tanto, el orden físico coincide con el orden lógico. Para acceder a la unidad de información que se encuentra en el orden N es necesario leer las N-1 anteriores. Archivos de Acceso Directo: no necesariamente el orden físico se corresponden con un determinado orden lógico. Podemos, en este tipo de organización, acceder directamente a una unidad de información, sin necesidad de leer las precedentes. La información se coloca y se accede aleatoriamente mediante su posición, es decir indicando el lugar relativo que ocupa dentro del conjunto de posiciones posibles. Requieren que el soporte admita este direccionamiento. Archivos Secuenciales Indexados: Las unidades de información se almacenan secuencialmente pero admiten el acceso selectivo a través de tablas de índices que facilitan la clasificación y acceso a los datos.
Archivo Físico y Lógico Como dijimos, los archivos se hallan soportados en algún medio físico (disquete, disco, CD Rom, etc.). Denominamos archivo físico a la unión de la información del archivo y su soporte. Ambos son identificados por el sistema operativo con una ruta de ubicación (path en inglés) y un nombre. Este nombre debe respetar las reglas sintácticas del sistema operativo. Por ejemplo, para identificar al archivo datos.txt que se encuentra en la carpeta trabajos que es hija de la carpeta Mis Documentos del disco C, debemos escribir: C:\Mis Documentos\Trabajos\Datos.txt
145
El archivo lógico -en cambio- es una variable dentro del programa que representa al archivo físico. Esta variable es definida en el programa con un nombre acorde a la sintaxis de identificadores del lenguaje. En el programa debemos relacionar la variable o archivo lógico con el archivo físico. Una vez establecida esa relación -que habitualmente se hace en la apertura del archivo- toda referencia sobre el archivo lógico implicará: a) una conexión con el dispositivo que controla el soporte, y b) una determinada operación sobre el archivo físico.
Unidades de información de un archivo Los archivos físicos son una secuencia de bytes, pero los programas que los generan pueden utilizar unidades lógicas o componentes para accederlos. Si conocemos la estructura de las unidades lógicas que forman el archivo podemos leer esa información en forma ordenada a través de un programa e identificar los datos almacenados. Estas unidades lógicas o componentes pueden ser: a) líneas b) registros de estructura fija. c) registros de estructura variable d) sin unidades lógicas definidas El caso (a) es típico de los archivos de texto. Su longitud es variable y existe un carácter o marca que indica el final de cada línea. El (b) se utiliza al organizar los datos de muchas unidades de información de igual estructura, como por ejemplo; los datos de los clientes de una empresa, donde se requiere de todos ellos: apellido, nombres, DNI, fecha nacimiento, etc. Cada cliente requiere una cantidad fija de bytes. El caso (c) es posible si se indica en cada registro su longitud. Permite optimizar el espacio en el soporte del archivo pero es más complejo el algoritmo de acceso. En (d) el archivo no tiene identificadas unidades o componentes; es el caso de un archivo que constituye una única unidad lógica, como por ejemplo una imagen capturada por algún dispositivo (scanner, cámara digital, etc.). En cada lenguaje de programación existen particularidades para el manejo de unidades lógicas para el acceso a los archivos. Normalmente nos referimos a ellas como registros y a sus componentes como campos.
146
ALGUNAS OPERACIONES SOBRE ARCHIVOS Vamos entonces a resumir las operaciones más comunes que se pueden realizar sobre archivos secuenciales:
Apertura de un Archivo: La apertura de un archivo determinado en un algoritmo conecta nuestro archivo lógico con el dispositivo físico que contiene al archivo almacenado y al que queremos acceder. Una vez abierto, el archivo permitirá que el algoritmo lo use para ingreso de datos y/o salida de información. La acción de apertura de un archivo implica automáticamente lo siguiente: • Asociar el nombre lógico del programa al nombre físico del archivo. • Comunicar al programa con el dispositivo que controla el soporte del archivo disponiendo de recursos en la computadora para este fin. • Efectuar el posicionamiento inicial del dispositivo de lectura y/o escritura en el soporte del archivo.
Cierre de un Archivo: Luego de haber concluido con el procesamiento de un determinado archivo debemos proceder a cerrarlo, o sea, la acción contraria a cuando necesitábamos comenzar a usarlo. El cierre de un archivo permite desconectar el canal de comunicación del programa con el dispositivo que controla al soporte del archivo, liberando recursos del sistema operativo.
Lectura El ingreso a la memoria de los datos que contiene una unidad de información determinada desde un archivo.
Escritura El volcado de los datos contenidos en la memoria, en base a la unidad de información, al archivo.
Creación Es la generación del mismo, con todas sus cualidades y la escritura de información en él.
Consulta: Lectura de algunas de sus unidades de información.
147