Índice Tema
Página
Notas Preliminares Introducción a la Programación en C/ C++. Estructura de un programa en “C”: Tipos de Datos- Declaración y asignación de variables Entrada / Salida – cin -cout Constantes. Operadores Iteraciones y decisiones Sentencia IF switch Sentencias de iteración: for while Do while FUNCIONES Pasaje de Parámetros Vectores o Vectores Unidimensionales Enum, Typedef Vectores Bidimensionales o Matrices Consideraciones importantes asociadas al uso de matrices: ORDENAMIENTO Ordenamiento Por Selección (Selection Sort) Ordenamiento BubbleSort. Ordenamiento Por Inserción Directa Método De Ordenamiento Por Inserción Binaria Ordenamiento por el Método Shell Ordenamiento Heap Sort Búsqueda de elementos en un Vector Búsqueda secuencial Búsqueda binaria Recursividad Fibonacci Torres de Hanoi Operaciones recursivas con Vectores Archivos en C++ Backtracking La vuelta del caballo El problema de las ocho reinas El Problema de la mochila (selección óptima) Ejemplo Backtraking Cadenas O Strings (swap, find first of,
3 3 4 5 6 7 7 8 9 10 11 12 13 14 16 16 18 19 21 22 23 24 25 26 27 29 29 29 31 33 34 35 37 40 42 45 47 48 53 55 56 70 74
Biblioteca conio - math Punteros Templates (introducción) Trabajos Prácticos
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
2
Notas Preliminares
La Programación es el arte de dar soluciones a los problemas para que el equipo pueda ejecutarlas. cutarlas. La gran parte del esfuerzo esfuerzo en programar es buscar buscar soluciones soluciones y refinarlas refinarlas.. A menudo, el problema es sólo comprender plenamente a través del proceso de programación la solución. Este apunte es para alguien que nunca ha programado antes, pero que está dispuesto a trabajar duro para aprender. Asimismo, le ayudará a comprender los principios y adquirir los conocimientos prácticos de la programación usando el lenguaje de programación C++. ¿Por qué C++? No se puede aprender a programar sin un lenguaje de programación, y C++ apoya directamente los principales conceptos y técnicas que se utilizan en el mundo real del software. C++ es uno de los lenguajes de programación más ampliamente utilizados. La mayoría de los conceptos de programación pueden utilizarse directamente en otros lenguajes, como C#, Fortran, PhP y Java. Por último, C++ es frecuente elegirlo como lenguaje para escribir código elegante y eficiente. La hipótesis fundamental es desear escribir los programas para el uso de otros, y de hacerlo con responsabilidad, proporcionando un buen nivel de calidad de todo el sistema, sistema, es decir, lograr un muy buen nivel de profesionalismo. profesionalismo. La programación se adquiere por escribir programas. En este tipo de programación es similar a la de otras actividades con un componente práctico. Las personas no pueden aprender a nadar, a tocar un instrumento musical, o conducir un coche solo con leer un libro. Todos debemos practicar. No se puede aprender a programar sin leer y escribir bastante código. Este apunte intenta centrase en ejemplos de código estrechamente vinculado con texto explicativo y diagramas. Esto es esencial, pero, por sí sola, no le brindará los conocimientos prácticos de programación. Para ello, se necesita hacer los ejercicios y acostumbrarse a las herramientas para escribir, compilar y ejecutar los programas.
Introducción a la Programación en C/ C++.
a) Introducción Teórica
Creador: Dennis Ritchie (Laboratorios Bell) en 1972, cuando trabajaba junto con Ken Thompson diseño del sistema operativo UNIX. El ‘C’ se creó como herramienta para programadores, en consecuencia su principal objetivo es ser un lenguaje útil. C++ C++ es un leng lengua uaje je de prog progra rama maci ción ón crea creado do a medi mediad ados os de los los años años 1980 1980 por por BJaBJarne Stroustrup. Stroustrup. La intención intención de su su creación creación fue extender extender al exitoso exitoso lenguaje lenguaje de programa programa-ción C con mecanismos que permitan la manipulación de objetos. Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
3
Características: El “C” es un lenguaje de programación de “alto nivel” (alto nivel quiere decir “próximo al lenguaje humano”), pero con características de “bajo nivel” (bajo nivel= próximo al lenguaje máquina). Es de ALTO de ALTO NIVEL porque NIVEL porque es racional, estructurado y fácil de aprender. Es de BAJO de BAJO NIVEL porque NIVEL porque permite trabajar con “bits”, registros de la C.P.U. y posiciones de memoria. ¿Por qué el “C”? El lenguaje ‘C’ es poderoso y flexible: la mayor parte del sistema operativo UNIX fue escrito en ‘C’. Incluso están escritos en ‘C’ los compiladores e intérpretes de otros lenguajes, como FORTRAN, APL, PASCAL, LISP, LOGO y BASIC. El lenguaje ‘C’ es “amistoso” porque es lo suficientemente estructurado para ejercer buenos hábitos de programación. Es el lenguaje de programación más utilizado por el programador de sistemas.
Estructura de un programa en “C”: El ‘C’ es gráficamente:
CÓDIGO FUENTE: es FUENTE: es el programa que nosotros escribimos, escribimos, se graba con la extensión CPP CÓDIGO OBJETO: es OBJETO: es el programa fuente pero traducido a lenguaje máquina (sucesión de ceros y unos), se graba con la extensión OBJ PROGRAMA EJECUTABLE: EJECUTABLE: es el programa objeto más las “librerías del C”, se graba con la extensión EXE. Y no necesita el programa que hemos utilizado para crearlo, para poder ejecutarlo. El código Objeto que genera un compilador de “C”, es casi tan eficiente (rápido) como si lo hubiéramos escrito en lenguaje ENSAMBLADOR (lenguaje de programación más próximo al lenguaje máquina).
El presente apunte está orientado a la construcción de programas sobre el compilador Borland C++ Builder 6.0 Para Borland Para Borland C++ Builder 6.0 se 6.0 se utiliza: File – New- other- Console Wizard. Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
4
Los programas en C++ consisten en una o más funciones. La única función que debe estar absolutamente presente es la denominada main, siendo la primera función que es llamada cuando comienza la ejecución del programa. Aunque main no no forma técnicamente parte del lenguaje C, hay que tratarla como si lo fuera. Borland C++ Builder 6.0 #include m.h> Declaración Declaración de librerías librerías int main() { Inicio de bloque // cuerpo del d el programa Return(0); } fin de bloque La forma general de un programa en C es:
El programa así escrito se denomina programa fuente y puede estar escrito en uno o varios archivos. Para que el programa pueda ser ejecutado se debe compilar y Ejecutar (run) con todas aque- llas funciones de la biblioteca que se necesiten.
Tipos de Datos
Todos los programas necesitan, en algún momento, almacenar números o datos ingresado por el usuario. Estos datos son almacenados en variables, y en C++ como en otros lenguajes estas variables deben tener un tipo.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
5
bool
La palabra clave bool es el nombre para el tipo de datos Booleano en C++. Un tipo de datos Booleano puede tomar uno de dos valores: verdadero o falso, que en C++ se señalan con las palabras clave true y false respectivamente.
Ejemplo En el siguiente siguiente código, se inicializa inicializa una variable variable booleana booleana con valor falso y falso y luego se usa esta variable variable para controlar controlar la ejecución ejecución de un bucle, la cual termina cuando la variable toma el valor verdadero: verdadero: bool bool list listo o = fals false; e; whil while( e( !lis !listo to ) { ... }
bool
Por lo general general utiliza utiliza 1 byte 1 byte de memoria, valores: true valores: true o o false false
Declaración y asignación de variables Para declarar una variable, basta con indicar su tipo y su nombre. Existen ciertas convenciones en cuanto al nombre de las variables. Algunos prefieren separar las partes de un nombre con '_', otros prefieren escribir una mayúscula para separarlas. Ejemplo: int mes;
o
int receta_del_mes;
Asignar un valor
Es posible asignar un valor a una variable al momento de declararla: int Mes = 12; También es posible declarar varias variables en una misma línea, pero en este caso, todas las variables de la línea tendrán el mismo tipo.
Otro Ejemplo double double d; int int i; short short s; //... d=d+i; i=s*i;
int recetaDelMes = 12301, recetaDelAño = 45644545;
Entrada / Salida
Cout (C output) cout out << "Tex "Texto to: : " << vari variab able le << "\n" "\n"; ;
Se trata de un objeto global definido en "iostream.h " iostream.h". ". Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
6
int int ente entero ro = 10; 10; char char caract caracter er = 'c'; 'c'; char char cadena cadena[20 [20] ] = "Hola "Hola"; "; floa float t pi = 3.14 3.1416 16; ;
cout cout cout cout cout cout cout cout
<< << << <<
"ent "enter ero= o=" " << ente entero ro << "\n" "\n"; ; "carac "caracter ter=" =" << caract caracter er << endl; endl; "cad "caden ena= a=" " << cade cadena na << endl endl; ; "pi= "pi=" " << pi << endl endl; ;
Cin #include #include #include using using namespac namespace e std;
int entero entero; ; string nombre; nombre; int main() main() { Cout<< Cout<<”in ”ingre grese se un número número entero”<< entero”<>entero; Cout <<”Ingrese <<”Ingrese Frase”<
Constantes. Las constantes se declaran, añadiendo la palabra const delante. const delante. Por ejemplo, para declarar una constante con valor 14: cons const t int int nume numero ro = 14; 14;
Estas constantes no pueden ser modificadas a lo largo del programa. Por eso deben ser definidas al mismo tiempo que declaradas.
Operadores
aritméticos
lógicos
relacionales
Asignación
List Listaa de oper operad ador ores es arit ritmético icos con su significado
! Not (no lógico) lógico) && And (y lógi lógi-co) || Or (ó lógico lógico))
== Igual Igual a != No igual a > Mayor Mayor que < Menor Menor que >= Mayor o igual que
= *= /= %= += -=
+ Suma Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
Asignación Asig Asigna na produ product ctoo Asigna división Asigna Asigna resto resto (módulo (módulo)) Asig Asigna na suma suma Asign Asignaa dife diferen renci ciaa (rest (resta) a) 7
- Resta * Producto / Cociente de una división % Resto de una división
<= Menor Menor o igual igual que
<<= >>= &= ^= |=
Asigna desplaza desplazamiento miento izquierda izquierda Asigna desplaza desplazamiento miento derecha derecha Asign Asignaa AND AND entr entree bits bits Asig Asigna na XOR XOR entr entree bits bits Asig Asigna na OR entr entree bits bits
Ejemplo: x = 3; x += 3; x &= 3;
Iteraciones y decisiones DEFINICIÓN Las sentencias de decisión o también llamadas de CONTROL DE FLUJO son estructuras de control que realizan una pregunta la cual retorna verdadero o falso (evalúa una condición) y selecciona la siguiente instrucción a ejecutar dependiendo la respuesta o resultado. En algún momento dentro de nuestros programas, es preciso cambiar el flujo de ejecución de las instrucciones, es decir, el orden en que las instrucciones son ejecutadas. Muchas de las veces tenemos que tomar una decisión en cuanto a que se debe ejecutar basándonos en una respuesta de verdadero o falso (condición). La ejecución de las instrucciones incluyendo una estructura de control como el condicional funciona de esta manera: Las instruccion instrucciones es comienzan comienzan a ejecutarse ejecutarse de forma secuencia secuenciall (en orden) y cuando se llega a una estructura condicional, la cual está asociada a una condición, se decide qué camino tomar dependiendo siempre del resultado de la condición siendo esta falsa o verdadera.
Cuando Cuando se termina termina de ejecutar ejecutar este bloque de instrucciones instrucciones se reanuda la ejecución ejecución en la instrucción siguiente a la de la condicional.
Sentencia IF
La instrucción if es, es, por excelencia, la más utilizada para construir estructuras de control de flujo. SINTAXIS Primera Forma if (condici (condición) ón) { Set de instrucc instruccione iones s }
Siendo Siendo "condición" "condición" el lugar donde se pondrá la condición condición o pregunta pregunta que se tiene que cumcumplir para que sea verdadera la sentencia y así proceder a realizar el "conjunto de sentencias" o código contenido dentro de la sentencia. Segunda Forma Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
8
if (condici (condición) ón) { Conj Conjun unto to de sent senten enci cias as } else { Conj Conjun unto to de sent senten enci cias as 2 }
//PA //PART RTE E VERD VERDAD ADER ERA A
//Pa //Part rte e FALS FALSA A
La forma mostrada anteriormente muestra la unión de la parte "VERDADERA" con la nueva secuencia la cual es la parte "FALSA" de la sentencia de decisión "IF" en la cual esta compuesta por el: else { Conj Conjun unto to de sent senten enci cias as 2
//Pa //Part rte e FALS FALSA A
} la palabr palabra a "else"
o "De lo contrario" indica al lenguaje que de lo contrario al no ser verdadera o no se cumpla la parte verdadera entonces realizara el "set de instrucciones 2". EJEMPLOS DE SENTENCIAS IF...
Ejemplo 1: #include #include #pragma #pragma hdrstop hdrstop #include #include #pragma #pragma argsused argsused int numero; numero; int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { cout<<"ingrese cout<<"ingrese numero"; cin>>numero; if(n if(num umer ero o == 0) //La //La cond condic ició ión n indi indica ca que que tien tiene e que que ser ser igua igual l a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Igual Igual a Cero"; Cero"; } getch(); retu return rn 0; }
Ejemplo 2:
if(n if(num umer ero o > 0) // la cond condic ició ión n indi indica ca que que tien tiene e que que ser ser mayo mayor r a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Mayor Mayor a Cero"; Cero"; }
Ejemplo 3: if(n if(num umer ero o < 0) // la cond condic ició ión n indi indica ca que que tien tiene e que que ser ser meno menor r a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Menor Menor a Cero"; Cero"; }
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
9
Ahora uniremos todos estos ejemplos para formar un solo programa mediante la utilización de la sentencia "Else" e introduciremos el hecho de que se puede escribir en este espacio una sentencia if ya que podemos ingresar cualquier tipo de código dentro de la sentencia escrita después de un Else. Ejemplo 4: if(n if(num umer ero o == 0) //La //La cond condic ició ión n indi indica ca que que tien tiene e que que ser ser igua igual l a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Igual Igual a Cero"; Cero"; } else { if(n if(num umer ero o > 0) // la cond condic ició ión n indi indica ca que que tien tiene e que que ser ser mayo mayor r a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Mayor Mayor a Cero"; Cero"; } else { if(n if(num umer ero o < 0) // la cond condic ició ión n indi indica ca que que tien tiene e que que ser ser meno menor r a Cero Cero { cout<< cout<<"El "El Numero Numero Ingres Ingresado ado es Menor Menor a Cero"; Cero"; } } }
Sentencia switch
switch es switch es otra de las instrucciones que permiten la construcción de estructuras de control. A diferencia de if , para controlar el flujo por medio de una sentencia switch se switch se debe de combinar con el uso de las sentencias sentencias case case y y break break . Notas: cualquier número de casos a evaluar por switch así como la sentencia default sentencia default son son opcionales. La sentencia switch sentencia switch es es muy útil en los casos de presentación de menús. Sintaxis: switch (condición) { case primer_c primer_caso: aso: bloque bloque de instr instrucc uccion iones es 1 break; case segundo_caso: segundo_caso: bloque bloque de instr instrucc uccion iones es 2 break; case caso_n: caso_n: bloque bloque de instr instrucc uccion iones es n break; defaul default: t: bloque bloque de instru instrucci ccione ones s por por defect defecto o }
Ejemplo 1 #include #include #pragma #pragma hdrstop hdrstop Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
10
#include #include #pragma #pragma argsused argsused int numero; numero; int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { cout<<"ingrese cout<<"ingrese numero"; cin>>numero; switch switch (numero) (numero) { case case 0: cout cout << "num "numer ero o es cero cero"; "; } getch(); retu return rn 0; }
Ejemplo 2 switch (opcion) (opcion) { case case 0: cout cout << "Su "Su opci opción ón es cero cero"; "; brea break; k; case case 1: cout cout << "Su "Su opci opción ón es uno" uno"; ; brea break; k; case case 2: cout cout << "Su "Su opci opción ón es dos" dos"; ; }
Ejemplo 3 switch switch (opcion) (opcion) { case case 1: cout cout << "Su "Su opci opción ón es 1"; 1"; brea break; k; case case 2: cout cout << "Su "Su opci opción ón es 2"; 2"; brea break; k; case case 3: cout cout << "Su "Su opci opción ón es 3"; 3"; brea break; k; defa defaul ult: t: cout cout << "Eli "Elija ja una una opci opción ón entr entre e 1 y 3"; 3"; }
Sentencias de iteración Definición Las Sentencia Sentenciass de Iteración de Iteración o Ciclos son Ciclos son estructuras de control que repiten la ejecución de un grupo de instrucciones. Básicamente, una sentencia de iteración es una estructura de control condicional, ya que dentro de la misma se repite la ejecución de una o más instrucciones mientras o mientras o hasta hasta que que una a condición específica se cumpla. Muchas veces tenemos que repetir un número definido o indefinido de veces un grupo de instrucciones por lo que en estos casos utilizamos este tipo de sentencias. En C++ los ciclos o bucles se construyen por medio de las sentencias for, for, while y while y do - while. while. La sentencia for es for es útil para los casos en donde se conoce de antemano el número de veces que una o más sentencias han de repetirse. Por otro lado, la sentencia while sentencia while es es útil en aquellos casos en donde no se conoce de antemano el número de veces que una o más sentencias se tienen que repetir. Sentencias For for(cont for(contador ador; ; final; final; incremen incremento) to) { Código Código a Repeti Repetir; r; }
donde: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
11
1. contador contador es una variable variable numérica numérica 2. final es la condición condición que se evalúa, o sea, el valor final para contador contador 3. incremento incremento es el valor que se suma o resta al contador contador Ejemplo 1: #include #include #include #include #pragma #pragma hdrstop hdrstop #pragma #pragma argsused argsused int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { for(i for(int nt i=1; i=1; i<=10; i<=10; i++) i++) { cout<<"Hola Mundo"<
Esto indica que el contador "i" inicia desde 1 y finaliza cuando el contador "i" sea menor o igual a 10 ( en este caso llegará hasta 10) e "i++" realiza la sumatoria por unidad lo que hace que el for el for y y el contador se sumen. repitiendo 10 veces "HOLA MUNDO" en pantalla. Ejemplo 2: #include #include #include #include #pragma #pragma hdrstop hdrstop #pragma #pragma argsused argsused int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { for(i=10 for(i=10; ; i>=0; i>=0; i--) { cout<<"Hola cout<<"Hola Mundo"<
Este ejemplo hace lo mismo que el primero, salvo que el contador se inic inicia iali liza za a 10 en luga lugar r de 1; y por por ello ello camb cambia ia la cond condic ició ión n que que se eval evalúa úa así así como como que que el cont contad ador or se decr decrem emen ento to en luga lugar r de ser ser incr increm emen enta tado do. .
Sentencia while while(condición) { código código a Repeti Repetir r }
donde: 1. condición condición es la expresión a evaluar Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
12
Ejemplo 1: #include #include #include #include #pragma #pragma hdrstop hdrstop #pragma #pragma argsused argsused int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { int int cont contad ador or = 0; while(contador<=10) { contador=contador++; cout<<"Hola Mundo"<
El contador Indica que hasta que este llegue a el total de 10 entonces se detendrá y ya no se realizará el código contenido dentro de la sentencia while, while, de lo contrario mientras el "contador" sea menor a 10 entonces el código contenido se ejecutará desplegando hasta 10 veces "Hola Mundo" en pantalla. Sentencia do - while
La sentencia do sentencia do es es usada generalmente en cooperación con while con while para para garantizar que una o más instrucciones se ejecuten al menos una vez. Por ejemplo, en la siguiente construcción no se ejecuta nada dentro del ciclo while ciclo while,, el hecho es que el contador inicialmente inicialmente vale cero y la condición para que se ejecute lo que está dentro del while es while es "mientras el contador sea mayor que diez". Es evidente que a la primera evaluación hecha por while la condición deja de cumplirse. int contador = 0; while(contador > 10) { contador ++; cout<<"Hola Mundo"; }
Al modificar el segmento de d e código anterior usando do usando do tenemos: tenemos: #include #include #include #include #pragma #pragma hdrstop hdrstop #pragma #pragma argsused argsused int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { int int cont contad ador or = 0; do { contador contador ++; cout<<"Hola Mundo"; } while(co while(contad ntador or > 10); getch(); Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
13
return return 0; }
Observe cómo en el caso de do la do la condición es evaluada al final en lugar de al principio del bloque de instrucciones y, por lo tanto, el código que le sigue al do se do se ejecuta al menos la primera vez. FUNCIONES Definición de una Función
Uno de los conceptos actualmente utilizados en el mundo del software, es la de Modularidad. Se ha dicho que la Modularidad, Modularidad, es el atributo atributo individual individual del software software que permite a un programa ser intelectualmente manejable. El software monolítico (es decir, un programa compuesto de un único módulo) no puede ser fácilmente abarcado por un lector. El número de camino caminoss de control, control, la expans expansión ión de refere referenci ncias, as, el número número de variab variables les y la complejid complejidad ad global podrían hacer imposibles su correcta compresión.
Estructura de una función: tipo_de_ tipo_de_func funcion ion
nombre_d nombre_de_la e_la_fun _funcion cion (argumen (argumentos) tos)
{ Cuerpo Cuerpo de la Funci Función ón retu return rn(v (var aria iabl ble e ó valo valor) r); ; /* opci opcion onal al solo solo cuan cuando do la func funció ión n es de tipo void*/ void*/ }
Donde el tipo_de_funcion el tipo_de_funcion corresponde corresponde al tipo de datos que retorna ó devuelve dicha función, la cual puede ser del tipo entero ( int ) , flotante (float), carácter (char ) etc, además es importante aclarar que aquellas funciones que no son definidas, por defecto son de tipo entero. argumentos: corresponde argumentos: corresponde a valores recibidos por la función, los cuales también se deben definir de un tipo determinado, como si se tratase de una definición de variable común y corriente, cabe destacar además que no necesariamente una función debe recibir un valor, si no que esta puede estar vacía. Cuerpo de la función: función : Corresponde al código fuente que se encargará de realizar el proceso, aquí se deberán declarar declarar variables si fuese necesario, necesario, dichas dichas variables son denominadenominadas variables locales porque pertenecen a esa función y sólo existen cuando el compilador toma dicha función, dejando de existir cuando el compilador termina de ejecutar dichas líneas de código. Existen Existen las variables globales, definidas definidas en el programa principal, antes del main(), main(), las cuales pueden ser utilizadas en cualquier parte del programa, incluyendo las funciones. return(variable return(variable ó valor): Corresponde al valor que retornará dicha función donde fue llamada, es importante destacar que una variable ó valor único. Más adelante veremos como
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
14
retornar variables que tengan asociados más de un valor, por lo que por el momento sólo nos quedaremos con la proposición inicial. Algunas veces no necesitaremos que las funciones nos retornen un valor, por lo que podremos omitir esta sentencia. Ejemplo Crear Ejemplo Crear un programa utilizando funciones donde se sumen dos números. En este programa existen variables globales (x e y) y variables locales (result en el cuerpo del programa principal; y las variables a y b en la función suma. Las variables locales sólo tienen existencia durante la ejecución de la respectiva función. Pueden existir variables locales con el mismo nombre en distintas funciones funciones las cuales estarán estarán haciendo haciendo referencia referencia a posiciones posiciones distintas de memoria. #include #include #include #include #pragma #pragma hdrstop hdrstop #pragma #pragma argsused argsused int x,y; x,y; int int suma suma(i (int nt a,in a,int t b); b); // Toda Todas s las las func funcio ione nes s se decl declar aran an ante antes s que que el // main main() (), , para para que que pued puedan an ser ser reco recono noci cida das s por por el //comp //compil ilado ador r y utiliz utilizada adas s en cualqu cualquier ier parte parte del //programa int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { int result; result; cout<< cout<<"In "Ingre grese se el primer primer valor valor "; cin>>x; cout<< cout<<"In "Ingre grese se el segund segundo o valor valor "; cin>>y; result=suma(x,y); result=suma(x,y); //se ingres ingresan an las variab variables les adecua adecuadas das como como paráme parámetro tros s y el //va //valo lor r devu devuel elto to por por la func funció ión n es asig asigna nada da a la vari variab able le resu result lt. cout<< cout<<"La "La suma suma es : "<
Otro Ejemplo Escribir un programa que permita al usuario elegir el cálculo del área de cualquiera de las figuras geométricas: círculo, cuadrado, rectángulo o triángulo mediante funciones. #include #include #pragma #pragma hdrstop hdrstop #include #include #include Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
15
#pragma #pragma argsused argsused int n,r,b,a,b1,b n,r,b,a,b1,b2,a2; 2,a2; float float circul circulo(i o(int nt r); void void carga( carga(); ); floa float t tria triang ngul ulo o (int (int b, int int a); a); floa float t cuad cuadra rado do (int (int b1); b1); floa float t rect rectan angu gulo lo (int (int b2, b2, int int a2); a2); int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) { carga(); getch getch (); return return 0; } void void carg carga a () { do { clrscr(); cout<<"1. cout<<"1. circulo"<>n; switch switch (n) { case 1:cout<<"Opc 1:cout<<"Opcion ion 1=circulo"<< 1=circulo"<>r; cout<<"El cout<<"El superficie superficie del circulo circulo es:"<>b; cout<< cout<<"In "Ingre grese se la altura altura del triang triangulo ulo:"< :"<>a; cout<<"L cout<<"La a superfic superficie ie del triangul triangulo o es:"<
break; case 3:cout<<"Opc 3:cout<<"Opcion ion 3=cuadrado"< 3=cuadrado"<>b1; cout<< cout<<"La "La superf superfici icie e del cuadra cuadrado do es:"<< es:"<>b2; cout<< cout<<"In "Ingre grese se la altura altura del rectan rectangul gulo:" o:"<>a2; cout<<"L cout<<"La a superfic superficie ie del rectangu rectangulo lo es:"<
break; } getch(); } Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
16
whil while e (n !=5) !=5); ; } float float circul circulo(i o(int nt r) { return ((float)(3. ((float)(3.14*r*r 14*r*r)); )); } floa float t tria triang ngul ulo( o(in int t a, int int b) { return return ((floa ((float) t) (b*a)/ (b*a)/2); 2); } floa float t cuad cuadra rado do (int (int b1) b1) { return return ((floa ((float) t) (b1*b1 (b1*b1)); )); } floa float t rect rectan angu gulo lo (int (int b2, b2, int int a2) a2) { return ((float)(b2 ((float)(b2*a2)); *a2)); }
Paso de parámetros C++ C++ perm permit itee dos dos tipo tiposs de paso paso de pará paráme metr tros os:: por por valo valorr (tam (tambi bién én deno denomi mina nado do por por copia, en terminol terminología ogía de de C++), y por refere referencia ncia.. Paso de parámetros por referencia El paso de parámetros por referencia se utiliza cuando se le quiere pasar una variable a una función o procedimiento, de manera que los cambios que se le hagan a esa variable dentro de la función sean repercutidos después en el resto del programa. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #pragma #pragma argsused argsused void imprimeValor imprimeValor(int (int *n); int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) { int int cont contad ador or = 0; contador++; cout<< cout<<"el "el valor valor del contad contador or es:" es:" << contad contador< or<
Paso de parámetros por valor
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
17
El paso paso de parámetr parámetros os por valor valor se utiliz utilizaa cuando cuando se le quiere quiere simpleme simplemente nte pasar pasar un dato a una función o procedimiento, sin más repercusiones en el resto del programa. El paso de parámetros por valor admite dos variantes, que es necesario utilizar en función del tipo de dato del parámetro que se quiera pasar. Para los tipos de datos simples, esto es, Entero y Real, el paso de parámetros por valor consiste básicamente en poner el nombre del tipo y el nombre del parámetro formal a continuación. Para su invocación, se indica el nombre de la variable o un valor literal. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #pragma #pragma argsused argsused void imprimeValor imprimeValor(); (); int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) { int int cont contad ador or = 0; contador++; cout<< cout<<"el "el valor valor del contad contador or es:" es:" << contad contador< or<
enum Sintaxis: enum nombre {lista-de-nombres} variable-lista; La palabra clave enum es usada para crear un tipo enumerador llamado nombre que consiste de los elementos en lista-de-nombre. La variable-lista es opcional, y puede ser usada para crear instancias de tipo nombre junto con la declaracion. Por ejemplo, el siguiente código crea un tipo enumerador para colores: enum enum ColorT ColorT {rojo, {rojo, naranj naranja, a, amari amarillo llo, , verde, verde, azul, azul, indigo indigo, , viole violeta} ta}; ; ... Colo ColotT tT c1 = indi indigo go; ; if( if( c1 == ind indigo igo ) { cout << "c1 "c1 es índi índigo go" " << endl endl; ; }
En el ejemplo anterior, el efecto de enumeración es introducir nuevas constantes llamadas ro jo, naranja, amarillo, etc. Por defecto, estas constantes son asignadas consecutivamente como enteros empezando en cero. Puedes cambiar los valores de estas constantes, como es mostrado en el siguiente ejemplo: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
18
int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { enum enum Colo ColorT rT { rojo rojo = 10, 10, azul azul = 166, 166, verd verde e }; //ve //verd rde e toma toma el valo valor r de azul azul+1 +1 Colo ColorT rT c = azul azul; ; cout << "c es " << c << endl; getch(); retu return rn 0; }
Se pone typedef para para que funcione en compiladores C y C++ a la par: type typede def f enum enum Colo ColorT rT { rojo rojo = 10, 10, azul azul = 15, 15, verd verde e } Colo ColorT rT; ; Colo ColorT rT c = verd verde; e; cout << "c es " << c << endl;
Vectores Unidimensionales Un vector vector o vector es un conjunto conjunto de datos del mismo tipo que se puede puede representar representar de la siguiente manera:
Dicho Dicho vector podría haber sido representado representado por una definición definición de 8 variables variables de tipo char. Cabe destacar destacar además que los vectors comienzan comienzan en el índice 0. Para declarar declarar un vector se sigue la siguiente sintaxis. Tipo_Dato
Nombre_Variable[Cantid Nombre_Variable[Cantidad_Elemento ad_Elementos]; s];
Ejemplo: Ingresar 10 elementos utilizando vectors y mostrar el mayor. Entrada: 10 enteros Salida Salida:: El mayor mayor de los los 10 entero enteross #include #include #include #include #include #pragma #pragma hdrstop hdrstop Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
19
#pragma #pragma argsused argsused void cargar() cargar(); ; void obtener_mayor(int obtener_mayor(int vector[10]); vector[10]); void mostrar_ mostrar_mayo mayor(in r(int t mayor); mayor); int main(){ main(){ cargar(); getch(); return return 0; } void cargar() cargar(){ { int vector[10],i; vector[10],i; for(i=0;i<10;i++){ clrscr(); cout<< cout<<"I "Ingr ngrese ese el numero numero en la posici posicion on "<>vector[i]; } obtener_mayor(vector); } void obtener_mayor(int obtener_mayor(int vector[10]){ vector[10]){ int mayor=0, mayor=0,i; i; for(i=0;i<10;i++){ if(vector[i]>mayor){ mayor=vector[i]; } } mostrar_mayor(mayor); } void mostrar_ mostrar_mayo mayor(in r(int t mayor){ mayor){ clrscr(); cout<<"E cout<<"El l mayor mayor numero numero ingresad ingresado o es: "<
Vectors Bidimensionales o Matrices Un vector multidimensional, es un vector de vectors. Una matriz es un vector bidimensional. Declaración de una matriz: int vector[filas][columnas]; vector[filas][columnas]; int a[5][ a[5][5], 5],m[1 m[10][ 0][4] 4],i, ,i,j,f j,f,c ,c // Ejemplo: int vector[5][3]; vector[5][3];
nombre nombre del del vector vector y dimen dimensió sión n
Su representación es:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
20
Lectura de una Matriz (llenado): for (i=0; (i=0; i<5;i++) i<5;i++) { for (j=0; j < 5 ; j=j+1) { Cout< out<<” <”\n \n Ingre ngrese se elele mento A[“<>a[i][j]; } }
Cada elemento se referencia a través del nombre y su ubicación en el con junto, por ejemplo: { a[4] a[4][2 [2]= ]=10 10; ; // Se alma almace cena na en la fila fila 5, colu column mna a 3 el valo valor r 10 m[0][5]=0; // Se almacena en la fila fila uno, uno, colu column mna a 6 el valo valor r 0 if (a[i (a[i][ ][j] j] == a[j] a[j][i [i] ] ) // se cons consul ulta ta si el valo valor r ubic ubicad ado o en la fila fila i-1 i-1 y colu column mna a j-1 j-1 es igua igual l al elemento // alma almace cena nado do en la fila fila j-1 j-1 y colu column mna a i-1 }
Consideraciones importantes asociadas al uso de matrices: • El procesamient procesamientoo de todos los elementos elementos requiere requiere como mínimo dos ciclos iterativos. iterativos. • Dentro Dentro de los ciclos ciclos se deben realizar realizar las operaciones operaciones específic específicas as que se solicitan. solicitan. • Una matriz matriz cuadrada es aquella aquella en el numero de filas es igual al número de columnas. columnas. • Entre las aplicacion aplicaciones es más importantes importantes de las matrices está la posibilidad posibilidad de resolver resolver sistemas de ecuaciones con n variables. Las matrices cuadradas tienen algunas características importantes asociadas a la ubicación de sus elementos en el conjunto. Se puede hablar de diagonal principal, diagonal secundaria, triangular superior, triangular inferior, por mencionar algunas.
ORDENAMIENTO Es la operación operación de arreglar arreglar los registros registros de una tabla en algún orden secuencial secuencial de acuerdo acuerdo a un criterio de ordenamiento. El ordenamiento se efectúa con base en el valor de algún campo en un registro. registro. El propósito propósito principal de un ordenamien ordenamiento to es el de facilitar facilitar las búsquedas de los miembros del conjunto ordenado.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
21
El ordenar un grupo de datos significa mover los datos o sus referencias para que queden en una secuencia tal que represente un orden, el cual puede ser numérico, alfabético o incluso alfanumérico, ascendente o descendente. Ordenamiento Por Por Selección (Selection Sort) Sort) • Busca el elemento más pequeño de la lista. • Intercambia con el elemento ubicado en la primera posición de la lista. • Busca el segundo elemento más pequeño de la lista. • Lo intercambia con el elemento que ocupa la segunda posición en la lista. • Repite este proceso hasta que haya ordenado toda la lista. ANÁLISIS DEL ALGORITMO. • Requerimientos de Memoria: Al igual que el ordenamiento burbuja, este algoritmo sólo necesita una variable adicional para realizar los intercambios. • Tiempo de Ejecución: El ciclo externo se ejecuta n veces para una lista de n elementos. Cada búsqueda requiere comparar todos los elementos no clasificados. Ventajas: • Fácil implementación. • No requiere memoria adicional. • Rendimiento constante: poca diferencia entre el peor y el mejor caso. Desventajas: • Lento. • Realiza numerosas comparaciones #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #pragma #pragma argsused argsused void seleccio seleccionsor nsort(in t(int t vector[1 vector[15],i 5],int nt tamano); tamano); void mostrarV mostrarVecto ector(in r(int[], t[], int); int); int int _mai _main( n( ) { cons const t int int tama tamano no = 15; 15; int vector[tamano] vector[tamano] = {25,17,13,16,41,32,12,1 {25,17,13,16,41,32,12,115,95,84,54 15,95,84,54,63,78,21,1 ,63,78,21,10}; 0}; int int i; cout cout << "vecto "vector r sin ordena ordenar\ r\n" n" ; mostrarVector(vector,tamano); cout cout << "vecto "vector r ordena ordenado\ do\n" n" ; seleccionsort(vector,tamano); mostrarVector(vector,tamano); getch(); return return 0; } void void selecc seleccion ionsor sort t (int (int A[], A[], int n) { int min,i,j, min,i,j,aux; aux; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
22
for (i=0; (i=0; i A[j] A[j]) ) {min=j; aux=A[min]; A[min]=A[i]; A[i]=aux A[i]=aux ;} } } } void mostrarV mostrarVecto ector( r( int vector[] vector[], , int tamano) tamano) { for (int i = 0 ; i < tamano ; i++) cout cout << vect vector or[i [i] ] << "/"; "/"; cout<<"\n"; }
Ordenamiento BubbleSort o Burbuja o Intercambio Directo. Es un sencillo algoritmo de ordenamiento. Funciona revisando cada elemento de la lista que va a ser ordenada con el siguiente, intercambiándolos de posición si están en el orden equivocado. Es necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la forma con la que suben por la lista los elementos durante los intercambios, como si fueran pequeñas "burbujas". También es conocido como el método del intercambio directo. Dado que solo usa comparaciones para operar elementos, se lo considera un algoritmo de comparación, siendo el más sencillo de implementar. #include #include #pragma #pragma hdrstop hdrstop #include #include #include > #pragma #pragma argsused argsused void BubbleSort( BubbleSort(int int vector[15], vector[15],int int tamano); tamano); void mostrarVect mostrarVector(int or(int[], [], int);
argc, _TCHAR _TCHAR* * argv[] argv[]) int main( main(int argc, { cons const t int int tama tamano no = 15; 15; int vector[tama vector[tamano] no] = {20,17,13,1 {20,17,13,16,41,3 6,41,32,12, 2,12,115,95 115,95,84,54 ,84,54,63,78 ,63,78,21,10 ,21,10}; }; int int i; cout cout << "vec "vecto tor r sin sin orde ordena nar\ r\n" n" ; mostrarVector(vector,tamano); cout cout << "vecto "vector r ordena ordenado\ do\n" n" ; BubbleSort(vector,tamano); mostrarVector(vector,tamano); getch(); return return 0; } //----------------------------------------------------------------void void Bubble BubbleSor Sort(i t(int nt A[],in A[],int t n) {int {int i, j, inc, inc, temp temp, , k,it k,item em ; for (i = 1; i
23
for (j = 0; j ]> A[j A[j + 1]) 1]) { temp temp = A[j] A[j]; ; A[j] = A[j + 1] ; A[j A[j + 1] = temp temp; ; } } } } void void mostra mostrarVe rVecto ctor( r( int vector vector[], [], int tamano tamano) ) { for (int i = 0 ; i < tamano ; i++) cout cout << vect vector or[i [i] ] << "/"; "/"; cout<<"\n"; }
Ordenamiento Por Inserción Directa DESCRIPCIÓN. El algoritmo de ordenación por el método de inserción directa es un algoritmo relativamente sencillo y se comporta razonablemente bien en gran cantidad de situaciones. Completa la tripleta de los algoritmos de ordenación más básicos y de orden de comple jidad cuadrático, junto con SelectionSort y BubbleSort. Se basa en intentar construir una lista ordenada en el interior del array a ordenar. De estos tres algoritmos es el que mejor resultado da a efectos prácticos. Realiza una cantidad de comparaciones bastante equilibrada con respecto a los intercambios, y tiene un par de características que lo hacen aventajar a los otros dos en la mayor parte de las situaciones. Este algoritmo se basa en hacer comparaciones, así que para que realice su trabajo de ordenación son imprescindibles dos cosas: un array o estructura similar de elementos comparables y un criterio claro de comparación, tal que dados dos elementos nos diga si están en orden o no. • En cada iteración del ciclo externo los elementos 0 a i forman una lista ordenada ANÁLISIS DEL ALGORITMO. • Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto es estable. • Requerimientos de Memoria: Una variable adicional para realizar los intercambios. • Tiempo de Ejecución: Para una lista den elementos el ciclo externo se ejecuta n1 veces. El ciclo interno se ejecuta como máximo una vez en la primera iteración, 2 veces en la segunda, 3 veces en la tercera, etc. Ventajas:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
24
• Fácil implementación. • Requerimientos mínimos de memoria. Desventajas:
• Lento. • Realiza numerosas comparaciones. Este también es un algoritmo lento, pero puede ser de utilidad para listas que están ordenadas o semi ordenadas, porque en ese caso realiza muy pocos desplazamientos. void insercio insercionDir nDirecta ecta(int (int A[],int A[],int n) { int i,j,v; i,j,v; for (i = 1; i < n; i++) { v = A[i] [i]; j=i j=i -1; -1; while (j >= 0 && A[j] > v) { A[j A[j + 1] = A[j] A[j]; ; j--; }A[j+ 1] = v ; } }
Método De Ordenamiento Por Inserción Binaria El método de ordenación por 'inserción binaria'' es una mejora del método de inserción directa. Para lograr esta mejora se recurre a una búsqueda binaria en lugar de una búsqueda secuencial para insertar un elemento en la parte izquierda del vector, que ya se encuentra ordenado. El resto del procedimiento es similar al de inserción directa, es decir, se repite este mismo procedimiento desde el segundo término hasta el último elemento. void insercio insercionBin nBinaria aria(int (int A[],int A[],int n) { int i,j,aux,izq,der,m; i,j,aux,izq,der,m; for(i=1;i=izq) { A[j+1]=A[j]; j=j-1; }A[izq]=aux; } Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
25
}
Ordenamiento por el Método Shell El método Shell Shell es una versión mejorada mejorada del método de inserción directa. directa. Este método también se conoce con el nombre de inserción con incrementos decrecientes. En el método de ordenación por inserción directa cada elemento se compara para su ubicación correcta en el vector, con los elementos que se encuentran en la parte izquierda del mismo. Si el elemento a insertar es más pequeño que el grupo de elementos que se encuentran a su izquierda, es necesario efectuar entonces varias comparaciones antes de su ubicación. Shell propone que las comparaciones comparaciones entre elementos se efectúen efectúen con saltos de mayor tamaño pero con incrementos decrecientes, así, los elementos quedarán ordenados en el vector más rápidamente. El Shell sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: 1. El ordenamiento ordenamiento por inserción inserción es eficiente eficiente si la entrada está "casi ordenada". ordenada". 2. El ordenamiento ordenamiento por inserción inserción es ineficiente, ineficiente, en general, general, porque mueve los valores valores sólo una posición cada vez. El algoritmo algoritmo Shell sort mejora el ordenamient ordenamientoo por inserción comparando comparando elementos elementos separados por un espacio de varias posiciones. Esto permite que un elemento haga "pasos más grandes" hacia su posición esperada. Los pasos múltiples sobre los datos se hacen con tamaños de espacio cada vez más pequeños. El último paso del Shell sort es un simple ordenamiento por inserción, pero para entonces, ya está garantizado que los datos del vector están casi ordenados. El Shell sort lleva este nombre en honor a su inventor, Donald Shell, que lo publicó en 1959. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #include > void ordenShell( ordenShell(int int vector[15], vector[15],int int tamano); tamano); void mostrarVect mostrarVector(int or(int[], [], int); #pragma #pragma argsused argsused int _tmain _tmain(in (int t argc, argc, _TCHAR _TCHAR* * argv[] argv[]) ) { cons const t int int tama tamano no = 15; 15; int vector[tama vector[tamano] no] = {25,17,13,1 {25,17,13,16,41,3 6,41,32,12, 2,12,115,95 115,95,84,54 ,84,54,63,78 ,63,78,21,10 ,21,10}; }; int int i; cout cout << "vec "vecto tor r sin sin orde ordena nar\ r\n" n" ; mostrarVector(vector,tamano); cout cout << "vecto "vector r ordena ordenado\ do\n" n" ; ordenShell(vector,tamano); mostrarVector(vector,tamano); getch(); Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
26
return return 0; } //--------------------------------------------------------------------------void void ordenS ordenShel hell(i l(int nt A[],in A[],int t n) {int {int i, j, inc, inc, temp temp; ; for(in for(inc c = 1 ; inc 0) { for for (i=i (i=inc nc; ; i < n; i++) i++) { j = i; temp temp = A[i] A[i]; ; whil while e ((j ((j >= inc) inc) && (A[j (A[j-i -inc nc] ] > temp temp)) )) { A[j] A[j] = A[j A[j - inc] inc]; ; j = j - inc; } A[j] A[j] = temp temp; ; } inc/= inc/= 2; } } void void mostra mostrarVe rVecto ctor( r( int vector vector[], [], int tamano tamano) ) { for (int i = 0 ; i < tamano ; i++) cout cout << vect vector or[i [i] ] << "/"; "/"; cout<<"\n"; }
Ordenamiento Heap Sort El ordenamiento por montículos (Heap sort) es un algoritmo de ordenación no recursivo, no estable. Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en un montículo (heap), y luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteraciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos, por la cual, la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él. El significado de heap en ciencia computacional es el de una cola de prioridades (priority queue). Tiene las siguientes características: Un heap es un vector de n posiciones ocupado por los elementos de la cola. (Nota: se utiliza un vector que inicia en la posición 1 y no en cero, de tal manera que al implementarla en C se tienen n+1 posiciones en el vector.) Se mapea un árbol binario de tal manera en el vector que el nodo en la posición i es el padre de los nodos en las posiciones posiciones (2*i) y (2*i+1). (2*i+1). El valor en un nodo es mayor o igual a los valores de sus hijos. Por consiguiente, el nodo padre tiene el mayor valor de todo su subárbol. PROCEDIMIENTO Heap Sort consiste esencialmente en: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
27
• Convertir el vector en un heap • Construir un vector ordenado de atrás hacia adelante (mayor a menor) repitiendo los siguientes pasos: • Sacar el valor máximo en el heap (el de la posición 1) • Poner ese valor en el vector ordenado • Reconstruir el heap con un elemento menos • Utilizar el mismo vector para el heap y el vector ordenado #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #include > #pragma #pragma argsused argsused void heapsort(in heapsort(int t vector[15], vector[15],int int tamano); tamano); void mostrarVect mostrarVector(int or(int[], [], int); int _tmain _tmain(in (int t argc, argc, _TCHAR _TCHAR* * argv[] argv[]) ) { cons const t int int tama tamano no = 15; 15; int vector[tama vector[tamano] no] = {0,17,13,16 {0,17,13,16,41,32 ,41,32,12,1 ,12,115,95, 15,95,84,54, 84,54,63,78, 63,78,21,10} 21,10}; ; int int i; cout cout << "vec "vecto tor r sin sin orde ordena nar\ r\n" n" ; mostrarVector(vector,tamano); cout cout << "vecto "vector r ordena ordenado\ do\n" n" ; heapsort(vector,tamano); mostrarVector(vector,tamano); getch(); return return 0; } //---//-----Es -Este te método método comien comienza za en la posici posición ón 1!!! 1!!! -----------------------------------void void heapso heapsort( rt(int int A[],in A[],int t n) {int {int i, j, inc, inc, temp temp, , k,it k,item em ; for(k=n;k>0;k--) { for(i=1;i<=k;i++) { item=A[i]; j=i/2; while(j>0 while(j>0 && A[j]
28
cout<<"\n"; }
Búsqueda de elementos en un Vector La búsqueda de un elemento dentro de un array es una de las operaciones más importantes en el procesamiento de la información, y permite la recuperación de datos previamente almacenados. El tipo de búsqueda se puede clasificar como interna o externa, según el lugar en el que esté almacenada la información (en memoria o en dispositivos externos). Todos los algoritmos de búsqueda tienen dos finalidades: - Determinar Determinar si el elemento buscado buscado se encuentra encuentra en el conjunto conjunto en el que se busca. - Si el elemento está en el conjunto, hallar la posición en la que se encuentra. En este apartado nos centramos en la búsqueda interna. Como principales algoritmos de búsqueda en arrays tenemos la búsqueda secuencial, la binaria y la búsqueda utilizando tablas de hash. Búsqueda secuencial Consiste en recorrer y examinar cada uno de los elementos del array hasta encontrar el o los elementos buscados, o hasta que se han mirado todos los elementos del vector. void secuenci secuencia(in a(int t a[n1],in a[n1],int t k1) { int cual,x1; cual,x1; bool ubicado=false; ubicado=false; cout<<"Q cout<<"Que ue elemento elemento se buscara? buscara? : ";cin>>c ";cin>>cual; ual; cout<
Búsqueda binaria La búsqueda binaria sólo se puede implementar si el vector está ordenado. La idea consiste en ir dividiendo el vector en mitades. Por ejemplo supongamos que tenemos este vector: int vector[10] vector[10] =
{2,4,6,8,10 {2,4,6,8,10,12,14 ,12,14,16,1 ,16,18,20} 8,20};;
La clave que queremos buscar es 6. El algoritmo funciona de la siguien manera 1. Se determinan determinan un indice arriba arriba y un indice abajo, abajo, Iarriba=0 e Iabajo=9 Iabajo=9 respectivamen respectivamen-te. 2. Se determina determina un indice indice central central,, Icentr Icentroo = (Iarrib (Iarribaa + Iabajo) Iabajo)/2, /2, en este este caso caso quedar quedaría ía Icentro = 4. Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
29
3. Evaluamos Evaluamos si vector[Icen vector[Icentro] tro] es igual a la clave de busqueda, si es igual ya encontraencontramos la clave y devolvemos Icentro. 4. Si son distintos, distintos, evaluamos evaluamos si vector[Ice vector[Icentro] ntro] es mayor o menos que que la clave, como el vector está ordenado al hacer esto ya podemos descartar una mitad del vector asegurandonos que en esa mitad no está la clave que buscamos. En nuestro caso vector[Icentro] = 4 < 6, entonces la parte del vector vector[0...4] ya puede descartarse. 5. Reasignamos Reasignamos Iarriba Iarriba o Iabajo para obtener la nueva nueva parte del vector vector en donde queremos buscar. Iarriba, queda igual ya que sigue siendo el tope. Iabajo lo tenemos subir hasta 5, entonces quedaria Iarriba = 9, Iabajo = 5. Y volvemos al paso 2. Si la clave no fuese encontrada en algun momento Iabajo > Iarriba, con un while vamos a controlar esta condición para salir del ciclo en tal caso y devolver -1 (clave no encontrada). Hagamos modificaciones al código de búsqueda lineal para implementar una función de búsqueda binaria. //Búsq //Búsqued ueda a binari binaria a en un vector vector. .
#include #include #pragma #pragma hdrstop hdrstop #include #include #include #include int busqueda busquedaBina Binaria( ria(cons const t int[], int[], int, int); int); //vector //vector, , tamaño, tamaño, clave clave void void ordena ordenarVe rVecto ctor(i r(int[ nt[], ], int); int); //prot //prototi otipo po que modifi modifica ca y ordena ordena el vector vector void intercam intercambiar biar(int (int&, &, int&); int&); //protot //prototipo, ipo, intercam intercambia bia los valores valores de dos elementos void mostrarV mostrarVecto ector(in r(int[], t[], int); int); //-------------------------------------------------------------------#pragma #pragma argsused argsused int _tmain(i _tmain(int nt argc, argc, _TCHAR* _TCHAR* argv[]) argv[]) { int int clav clave e =0; =0; cons const t int int tama tamano no = 15; 15; int vector[tamano] vector[tamano] = {20,17,13,16,41,32,12,1 {20,17,13,16,41,32,12,115,95,84,54 15,95,84,54,63,78,21,1 ,63,78,21,10}; 0}; int int i; //orde //ordenam namos os el vector vector para para que funcio funcione ne la busque busquedaB daBina inaria ria cout cout << "Vect "Vector or sin ordena ordenar\n r\n" " ; mostrarVector(vector,tamano); ordenarVector(vector,tamano); cout cout << "Elem "Element entos os del vector vector orden ordenado ado:\n :\n"; "; mostrarVector(vector,tamano); cout cout << "Ind "Indiq ique ue un valo valor r a busc buscar ar y se le devo devolv lver era a el indi indice ce: : " ; cin cin >> clav clave; e; cout<< cout<< "Su valor valor se encuen encuentra tra en vector["<
30
} int busqueda busquedaBina Binaria( ria(cons const t int vector[] vector[], , int tamano, tamano, int clave) clave) { int Iarrib Iarriba a = tamano tamano-1; -1; int int Iaba Iabajo jo = 0; int Icentro; Icentro; while while (Iabaj (Iabajo o <= Iarrib Iarriba) a) { Icentr Icentro o = (Iarri (Iarriba ba + Iabajo Iabajo)/2 )/2; ; if (vector[ (vector[Icen Icentro] tro] == clave) clave) return return Icentro; Icentro; else if (clave (clave < vector[I vector[Icent centro]) ro]) Iarriba=Icentro-1; else Iabajo=Icentro+1; } return return -1; } void ordenarV ordenarVecto ector(in r(int t vector[] vector[], , int tamano) tamano) { for for (int (int i = 0; i< tama tamano no -1 ; i++) ++) for (in (int j = 0; j< tam tamano ano -1 ; j++) if (vector[ (vector[j] j] > vector[j vector[j+1]) +1]) intercambiar(vector[j],vector[j+1]); } void void interc intercamb ambiar iar(in (int t &a, int &b) &b) { int int tmp tmp = b; b = a; a = tmp; }
Recursividad Se dice que algo es recursivo si se define en función de sí mismo o a sí mismo. También se dice que nunca se debe incluir la misma palabra en la definición de ésta. El caso es que las definiciones recursivas aparecen con frecuencia en matemáticas, e incluso en la vida real. Un ejemplo: basta con apuntar una cámara al monitor que muestra la imagen que muestra esa cámara. El efecto es verdaderamente curioso, en especial cuando se mueve la cámara alrededor del monitor. monitor. En matemáticas, tenemos múltiples definiciones recursivas: - Números naturales: (1) 1 es número natural. (2) el siguiente número de un número natural es un número natural - El factorial: factorial: n!, de un número natural natural (incluido el 0): (1) si n = 0 entonces: 0! = 1 Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
31
(2) si n > 0 entonces: n! = n · (n-1)! Asimismo, puede definirse un programa en términos recursivos, como una serie de pasos básicos, o paso o paso base (también base (también conocido como condición de parada), y un paso recursivo, recursivo, donde vuelve a llamarse al programa. En un computador, esta serie de pasos recursivos debe ser finita, terminando con un paso base. Es decir, a cada paso recursivo se reduce el número de pasos que hay que dar para terminar, llegando un momento en el que no se verifica la condición de paso a la recursivida recursividad. d. Ni el paso base ni el paso recursivo recursivo son necesariam necesariamente ente únicos. únicos. Por otra parte, la recursividad también puede ser indirecta, si tenemos un procedimiento P que llama a otro Q y éste a su vez llama a P. También en estos casos debe haber una condición de parada. Un ejemplo de programa recursivo en C, el factorial: int factoria factorial(in l(int t n) { if (n == 0) retur eturn n 1; retu return rn n * factorial(n-1); }
Como se observa, en cada llamada recursiva se reduce el valor de n, llegando el caso en el que n es 0 y no efectúa más llamadas recursivas. Hay que apuntar que el factorial puede obtenerse con facilidad facilidad sin necesidad necesidad de emplear funciones funciones recursivas recursivas,, es más, el uso del programa anterior es muy ineficiente, ineficiente, pero es un ejemplo muy claro. A continuación se expone un ejemplo de programa que utiliza recursión indirecta, y nos dice si un número es par o impar. Al igual que el programa anterior, hay otro método mucho más sencillo de determinar si un número es par o impar, basta con determinar el resto de la división entre dos. Por ejemplo: si hacemos par(2) devuelve 1 (cierto). Si hacemos impar(4) devuelve 0 (falso). /* declar declaraci acion on de funcio funciones nes, , para para evitar evitar errore errores s */ int par(in par(int t n); int impar( impar(int int n); int par(in par(int t n) { if (n == 0) retur eturn n 1; return impar(n-1); } int impar( impar(int int n) { if (n == 0) retur eturn n 0; return par(n-1); }
¿Qué pasa si se hace una llamada recursiva que no termina? Cada llamada recursiva almacena los parámetros que se pasaron al procedimiento, y otras variables necesarias para el correcto funcionamiento del programa. Por tanto si se produce una llamada recursiva infinita, esto es, que no termina nunca, llega un momento en el que no quedará memoria para almacenar más datos, y en ese momento se abortará la ejecución del proLaboratorio de Programación EEST Nº5 – Prof Abdala Pablo
32
grama. Para probar esto se puede intentar hacer esta llamada en el programa factorial definido anteriormente: factorial(-1); Por supuesto no hay que pasar parámetros a una función que estén fuera de su dominio, pues el factorial está definido solamente para números naturales, pero es un ejemplo claro.
Fibonacci Sucesión de Fibonacci, en matemáticas, sucesión de números en la que cada término es igual a la suma de los dos términos precedentes: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... y así sucesivamente, que empieza con 0 y 1. Esta sucesión fue descubierta por el matemático italiano Leonardo Fibonacci. Los números de Fibonacci tienen interesantes propiedades y se utilizan mucho en matemáticas. matemáticas. Las estructura estructurass naturales naturales,, como el crecimien crecimiento to de hojas en espiral espiral en algunos árboles, presentan con frecuencia la forma de la sucesión de Fibonacci. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #pragma #pragma argsused argsused //----------------------------------------------double double Fibonacc Fibonacci(in i(int t n); int _tmain(i _tmain(int nt argc, argc, _TCHAR* _TCHAR* argv[]) argv[]) { int int n; /* Se soli solici cita ta al usua usuari rio o el valo valor r de n */ Cout<< Cout<<"In "Ingre grese se el valor valor de n: "; Cin>>n; /* Impr Imprim ime e el fibo fibona nacc cci i de n */ Cout<<"E Cout<<"El l termino termino “<
El triángulo de Pascal En algún momento de tu vida habrás aprendido que (x + z) 2 = x2 + 2xz + z2, que (x + z)3 = x3 + 3x2z + 3xz2 + z3 y, en general, general, para cualquier cualquier entero positivo n, a calcular los coeficien coeficientes tes de n m n-m (x + z) , y posiblemente le diste el nombre de nCm al coeficiente de x z . Seguramente recuerdas la siguiente tabla triangular: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
33
1 11 12 1 1331 14641 ...... Esa tabla se conoce como triángulo de Pascal y y se construye como sigue: Al principio se coloca un 1 (que corresponde con 0C0). Para cada renglón subsecuente, digamos para el renglón n, se coloca un 1 a la izquierda y un 1 a la derecha (que corresponden con nC0 y nCn, respectivamente) y los elementos restantes se calculan sumando los dos números que tiene justo arriba a la izqui izquier erda da y arri arriba ba a la dere derech cha, a, es deci decir, r, nCm = n-1Cm-1 + n-1Cm para toda 0 < m < n. Entre otras cosas, el número nCm cuenta la cantidad de formas de escoger m objetos de un total de n objetos distintos. A estos números también se les llama las combinaciones de de m ob jetos en n. int int comb comb(i (int nt n, int int m) { if ((n == 0) || (n == m)) return 1; else else return return comb(n comb(n-1, -1,m-1 m-1) ) + comb(n comb(n-1, -1,m); m); }
Torres de Hanoi La Leyenda Según una leyenda, los monjes del templo de una antigua ciudad de la India tienen que mover una torre de 64 discos sagrados de un sitio a otro. Pero los discos son frágiles así que solo uno de ellos puede moverse a la vez. Ningún disco puede colocarse encima de otro más pequeño. Y únicamente existe otro lugar en el templo (además del sitio original y el destino) lo suficientemente sagrado para que una torre de discos pueda ponerse ahí.
La leyenda dice además que antes de que los monjes realicen el último movimiento para completar la torre en su nuevo lugar, el templo se reducirá a cenizas y el mundo se acabará.
.
El problema de las Torres de Hanoi Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
34
Este es un problema clásico de recursión, ya que pertenece a la clase de problemas cuya solución se simplifica notablemente al utilizar recursión. Se tienen 3 torres y un conjunto conjunto de n discos de diferentes diferentes tamaños. tamaños. Cada uno de ellos tiene una perforación en el centro que les permite deslizarse por cualquiera de las torres. Inicialmente, los n discos están ordenados de mayor a menor en una de las torres (Torre A). Se deben pasar los discos a otra torre, utilizando utilizando la del medio como auxiliar. auxiliar. Los movimientos deben hacerse respetando las siguientes reglas: 1. Solo puede moverse un disco a la vez, por lo tanto éste será el que esté en la parte superior de una torre. 2. No se puede colocar un disco grande encima de uno más pequeño. Las torres de identificaran con las letras A, B y C; los discos están inicialmente en la torre A y se desea transferirlos a la torre B, de la misma manera como están en A. Este programa programa calcula la cantidad cantidad de movimientos movimientos necesarios necesarios ingresando ingresando la cantidad cantidad de discos. #include #include #pragma #pragma hdrstop hdrstop #include #include #include //--------------------------------------------------------------------------int hanoi( hanoi(int int n); #pragma #pragma argsused argsused int _tmain(i _tmain(int nt argc, argc, _TCHAR* _TCHAR* argv[]) argv[]) { int int n; int disc, disc, mov; mov; cout<<": cout<<"::TOR :TORRES RES DE HANOI::\ HANOI::\n"; n"; cout<<"N cout<<"Numer umero o de discos: discos: "; cin>>disc; cout<<"\tMovimientos cout<<"\tMovimientos necesarios: necesarios: “<
Operaciones recursivas con Vectores
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
35
- Dado un vector constituido de números enteros y que contiene N elementos siendo N >= 1, devolver la suma de todos los elementos. elementos. int sumarray(int numeros[], int posicion, int N) { if (posicion == N-1) return numeros[posicion]; else return numeros[posicion] + sumarray(numeros, posicion+1, N); } ... int numeros[5] = {2,0,-1,1,3}; int N = 5; cout<
int sumarray(int numeros[], int posicion) { if (numeros[posicion] == -1) return 0; else return numeros[posicion] + sumarray(numeros, posicion+1); } ... int numeros[5] = {2,4,1,-3,-1}; cout<
La razón por la que se incluye este ejemplo se debe a que en general no se conocerá el número de elementos de la estructura de datos sobre la que se trabaja. En ese caso se introduce un centinela -como la constante -1 de este ejemplo o la constante NULO para punteros, u otros valores como el mayor o menor entero que la máquina pueda representarrepresentar- para indicar el fin de la estructura. - Dado un array constituido de números enteros y que contiene N elementos siendo N >= 1, devolver el elemento mayor. int mayor(int numeros[], int posicion) { int aux; if (posicion == 0) Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
36
return numeros[posicion]; else { aux = mayor(numeros, posicion-1); if (numeros[posicion] > aux) return numeros[posicion]; else return aux; }
} ... int numeros[5] = {2,4,1,-3,-1}; int N = 5; cout<
Archivos en C++ Al igual que ocurre con la escritura en pantalla, a la hora de d e manejar los archivos desde C++, podemos emplear las funciones que ya conocíamos de C, o bien emplear otras nuevas posibilidades que aporta C++. También al igual que ocurría ocurría con la pantalla, el manejo de archivos archivos se basará en flujos de entrada y salida. Tenemos las clases fstream (archivo, en general), ifstream (archivo de entrada) y ofstream (archivo de salida), todas ellas definidas en “fstream.h”. Leeremos y escribiremos con << y >>, al igual que para la pantalla. Cerraremos un archivo con “close” (tanto si lo hemos abierto como para leer o para escribir) escribir) y comprobarem comprobaremos os si se ha terminado terminado un archivo archivo de entrada entrada con “eof” (end of file – fin de archivo). Vamos a ver un primer ejemplo que lo aplique, creando un archivo de d e texto: #include Int main() { ofstream archivo("c: \\ejemplo.txt"); archivo << "Hola" << endl; archivo << "Adios" << endl; archivo.close(); } Debería ser muy fácil de seguir: • Incluimos Incluimos el archivo de cabecera cabecera “fstream.h “fstream.h”. ”. • Definimos Definimos un archivo archivo de salida, que tendrá por nombre físico físico “ejemplo.txt” “ejemplo.txt” en la unidad C: \ • Escribimos Escribimos dos líneas líneas de texto en el archivo. archivo. • Cerramos Cerramos en el el archivo archivo.. En un caso general, puede puede ocurrir que no sepamos el nombre nombre físico del archivo archivo en el momento momento de definir la variable variable “archivo”, “archivo”, sino más tarde (por ejemplo, porque el usuario usuario sea el que vaya a teclear el nombre del archivo con el que trabajar, o porque vaya a escoger dicho nombre en una ventana ventana de diálogo). En ese caso, podemos usar usar la función función miembro “open”. “open”. Como ejemplo, vamos a leer el archivo que acabamos de crear: #include #include Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
37
int main() { fstream archivo; char texto[200];
}
archivo.open("ejemplo.txt", ios::in); // Abro para lectura lectura arch archiv ivoo >> text texto; o; // Leo Leo una una prim primer eraa líne líneaa while while (!arch (!archivo ivo.eof .eof()) ()) // Mientr Mientras as se haya haya podid podidoo leer leer algo algo { cout cout << texto texto << endl; endl; // Mues Muestro tro lo que que se se lee lee arch archiv ivoo >> texto texto;; // Y vuel vuelvo vo a inte intent ntar ar leer leer } arch archiv ivo. o.cl clos ose( e(); ); // Fina Finalm lmen ente te,, cier cierro ro
La estructura es ligeramente distinta, pero aun así, debería resultar fácil de seguir. Esta vez, el archivo archivo lo hemos declarado declarado como “genérico”, “genérico”, sin especific especificar ar si va a ser para lectura lectura o escrituescritura, de modo que este dato lo indicamos cuando realmente abrimos el archivo. Los modos de apertura que tenemos disponibles son: • ios::in abre abre el archivo archivo para lectur lecturaa • ios::out ios::out abre el archivo archivo para escritu escritura ra • ios::append ios::append abre el archivo archivo para añadir datos (al final, final, después de los que ya contenga) Si hubiéramos declarado el archivo como “ifstream”, se daría por sentado que lo abrimos para leer, y no sería necesario indicarlo: ifstre ifstream am archiv archivo; o; // Abro Abro para para lectur lecturaa archivo.open("C: \\ ejemplo.txt"); No hemos comprobado comprobado si el archivo realmente realmente se ha podido abrir. Para conseguirlo, conseguirlo, añadiríaañadiríamos después de “open” algo parecido a esto, similar a lo que hacíamos en C estándar: if (!archivo) { cerr << "No se ha podido abrir el archivo." << endl; exit(1); } Estas son las ideas básicas. Pero hay más posibilidades, que voy a comentar con menos detalle, pero prefiero que se sepa que existen, porque pueden ser útiles en muchos casos. Por ejemplo, podemos leer un bloque de datos de una determinada longitud, lo que será útil cuando manejemos archivos binarios, o escribir una serie de bytes, o leer un dato de un flujo pero sin avanzar de posición. Estas son algunas funciones funciones miembro de iostream iostream que nos servirán para cosas como esas: • put(char put(char c) escribe escribe un carácter carácter en un flujo de salida. salida. • get(char& get(char& c) lee un carácter carácter de un flujo flujo de entrada. • read(char* read(char* s, int n) lee n bytes del flujo flujo de entrada y los deposita deposita en la cadena cadena s (normalmente se usará para entrada binaria). • write(const write(const char* char* s, int n) escribe n bytes de la cadena cadena s en un flujo de salida (normalmen (normalmente te se usará para salida binaria). Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
38
• get(char* get(char* s, int n, char c=’\n’) c=’\n’) lee como máximo n caracteres caracteres del flujo de entrada (incluyendo el ‘\0’) y los introduce en la cadena s, o hasta que encuentre el carácter de terminación nación (por defecto defecto ‘\n’, salto de línea), línea), o el fin de archivo. archivo. No retira el carácter carácter de terminación terminación del flujo de entrada. • getline(ch getline(char* ar* s, int n, char c=’\n’) c=’\n’) lee como máximo n-1 caracteres caracteres del flujo de entrada, o hasta que encuentre el carácter de terminación (por defecto un final de (línea) o hasta el fin de archivo. Retira el carácter de terminación del flujo de entrada, pero no lo almacena en la cadena s. • ignore(int ignore(int n=1, int delim=EOF) delim=EOF) ignora ignora o descarta los n caracteres caracteres siguientes siguientes de un flujo de entrada (o un solo carácter, si no se indica el valor de n), o hasta que encuentra un cierto carácter de terminación (por defecto el fin de archivo EOF). • peek() peek() lee un carácter del flujo de entrada entrada pero sin retirarlo de dicho flujo. flujo. • putback(c putback(char har c) devuelve devuelve el carácter carácter c al flujo de entrada (de modo que sería lo primero que se leería en la próxima operación de entrada). Por otra parte, en la clase “fstream” tenemos otras funciones miembro que nos ayudarán a comprobar errores en la lectura o escritura: • good () devuelve devuelve un valor valor distinto de cero cero si no ha habido ningún error. error. • eof() devuelve devuelve un valor valor distinto de cero si se ha llegado al fin del archivo, archivo, como ya hemos visto. • bad() devuelve devuelve un valor valor distinto de cero si ha habido un error grave de entrada/salid entrada/salidaa grave. No se puede continuar en esas condiciones. • fail() fail() devuelve un valor valor distinto de cero si ha habido cualquier cualquier error de E/S distinto de EOF. Después podemos llamar a bad() para comprobar si el error es grave o si se puede intentar proseguir la lectura. Si bad() devuelve 0, el error no es grave y la lectura puede proseguir después de llamar a la función clear(). • clear() clear() resetea la situación situación de error (siempre (siempre que no sea grave), grave), para poder seguir leyendo. leyendo. Además, también podemos pod emos comprobar si s i ha habido algún error en la forma que hemos empleado en el ejemplo anterior: cada función (open, read, etc) devolverá un valor distinto de cero cuando exista algún error, por lo que es habitual emplear construcciones como if (!archivo) { // No se ha podido abrir el archivo } o como if (!archivo.get(ch)) { // No se ha podido po dido leer el siguiente dato. d ato. } Ejemplo de lectura de archivo sumo.in, convierte los contenidos en una matriz y guarda los contenidos en un archvivo sumo.out del ejercicio LUCHADORES JAPONESES pag. 103. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #pragma #pragma argsused argsused int _tmain(i _tmain(int nt argc, argc, _TCHAR* _TCHAR* argv[]) argv[]) {
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
39
fstream fstream archivo; archivo; char char text texto[ o[20 200] 0]; ; int int matr matriz iz[1 [12] 2][2 [2], ],f, f,c; c; archivo. archivo.open open("c: ("c:\\su \\sumo.i mo.in", n", ios::in) ios::in); ; // Abro para lectura lectura archivo >> texto; // Leo una primera linea matriz[0][0]=atoi(texto); while while (!arch (!archivo ivo.eo .eof() f()) ) // Mientr Mientras as se haya haya podido podido leer leer algo algo { for (f=1; (f=1; f<=10;f+ f<=10;f++) +) { for (c=1; (c=1; c<=2; c<=2; c++) c++) { archivo >> >> te texto; // Y vuelvo a intentar le leer matriz[f matriz[f][c] ][c]=ato =atoi(te i(texto) xto);// ;// asigno asigno a la matriz matriz los datos datos leidos leidos } } } ofstream archivoout("c:\\sumo.o archivoout("c:\\sumo.out"); ut"); cout<
// Finalmente, cierro
Backtracking * Introducción * La vuelta del caballo * El problema de las ocho reinas * El problema de la mochila (selección óptima)
Introducción Los algoritmos de vuelta atrás se utilizan para encontrar soluciones a un problema. No siguen unas reglas para la búsqueda de la solución, simplemente una búsqueda sistemática, que más o menos viene a significar que hay que probar todo lo posible hasta encontrar la solución o encontrar que no existe solución al problema. Para conseguir este propósito, se separa la búsqueda en varias búsquedas parciales o subtareas. Asimismo, estas subtareas suelen incluir más subtareas, por lo que el tratamiento general de estos algoritmos es de naturaleza recursiva.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
40
¿Por qué se llaman algoritmos de vuelta atrás?. Porque en el caso de no encontrar una solución en una subtarea se retrocede a la subtarea original y se prueba otra cosa distinta (una nueva subtarea distinta a las probadas anteriormente). Puesto que a veces nos interesa conocer múltiples soluciones de un problema, estos algoritmos se pueden modificar fácilmente para obtener una única solución (si existe) o todas las soluciones posibles (si existe más de una) al problema dado. Estos algoritmos se asemejan al recorrido en profundidad dentro de un grafo (ver sección de grafos, estructuras de datos, y recorrido de grafos, algoritmos), siendo cada subtarea un nodo del grafo. El caso es que el grafo no está definido de forma explícita (como lista o matriz de adyacencia), sino de forma implícita, es decir, que se irá creando según avance el recorrido. A menudo dicho grafo es un árbol, o no contiene ciclos, es decir, al buscar una solución es, en general, imposible llegar a una misma solución x partiendo de dos subtareas subtareas distintas a distintas a y y b b;; o de la subtarea subtarea a a es es imposible llegar a la subtaréa b subtaréa b y y viceversa. Gráficamente se puede ver así:
A menudo ocurre que el árbol o grafo que se genera es tan grande que encontrar una solución o encontrar la mejor solución entre varias posibles es computacionalmente muy costoso. En estos casos suelen aplicarse una serie de restricciones, de tal forma que se puedan podar algunas de las ramas, es decir, no recorrer ciertas subtareas. Esto es posible si llegado a un punto se puede demostrar que la solución que se obtendrá a partir de ese punto no será mejor que la mejor solución obtenida hasta el momento. Si se hace correctamente, la poda no impide encontrar la mejor solución. A veces, es imposible demostrar que al hacer una poda no se esté ocultando una buena solución. Sin embargo, el problema quizás no pida la mejor solución, sino una que sea razonablemente buena y cuyo coste computacional sea bastante reducido. Esa es una buena razón para aumentar las restricciones a la hora de recorrer un nodo. Tal vez se pierda la mejor solución, pero se encontrará una aceptable en un tiempo reducido. Los algoritmos de vuelta atrás tienen un esquema genérico, según se busque una o todas las soluciones, y puede adaptarse fácilmente según las necesidades de cada problema. A contiLaboratorio de Programación EEST Nº5 – Prof Abdala Pablo
41
nuación se exponen estos esquemas, extraídos de Wirth Los bloques se agrupan con begin y begin y end, end, equivalentes a los corchetes de C, además están tabulados. - esquema para una solución: procedimiento ensayar procedimiento ensayar (paso : TipoPaso) repetir | seleccionar_candidato | if aceptable then aceptable then | begi begin n | anotar_candidato | if solucion_incompleta then solucion_incompleta then | begin | ensayar(paso_siguiente) | if no no acertado then acertado then borrar_candidato borrar_candidato | end | else else begi begin n | anotar_solucion | acertado <- cierto; | end hasta que (acertado que (acertado = cierto) o cierto) o (candidatos_agotados) (candidatos_agotados) fin procedimiento
- esquema para todas las soluciones: procedimiento ensayar procedimiento ensayar (paso : TipoPaso) para cada candidato cada candidato hacer hacer | seleccionar candidato | if aceptable then aceptable then | begi begin n | anotar_candidato | if solucion_incompleta then solucion_incompleta then | ensayar(paso_siguiente) | else | almacenar_solucion | borrar_candidato | end hasta que candidatos_agotados que candidatos_agotados fin procedimiento
Por último, se exponen una serie de problemas típicos que se pueden resolver fácilmente con las técnicas de vuelta atrás. El primero que se expone es muy conocido. Se trata de la vuelta del caballo. Muchos problemas de los pasatiempos de los periódicos pueden resolverse con la ayuda de un ordenador y en esta web se muestran algunos de ellos.
La vuelta del caballo
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
42
Se dispone de un tablero rectangular, por ejemplo el tablero de ajedrez, y de un caballo, que se mueve según las reglas de este juego. El objetivo es encontrar una manera de recorrer todo el tablero partiendo de una casilla determinada, de tal forma que el caballo pase una sola vez por cada casilla. Una variante es obligar al caballo a volver a la posición de partida en el último movimiento. Por último se estudiará como encontrar todas las soluciones posibles partiendo de una misma casilla. Para resolver el problema hay que realizar todos los movimientos posibles hasta que ya no se pueda avanzar, en cuyo caso hay que dar marcha atrás, o bien hasta que se cubra el tablero. Además, es necesario determinar la organización de los datos para p ara implementar imp lementar el algoritmo. - ¿Cómo se mueve un caballo?. Para aquellos que no sepan jugar al ajedrez se muestra un gráfico con los ocho movimientos que puede realizar. Estos movimientos serán los ocho candidatos.
Con las coordenadas en las que se encuentre el caballo y las ocho coordenadas relativas se determina el siguiente movimiento. Las coordenas relativas se guardan en dos arrays: ejex ejex = [2, [2, 1, -1, -1, -2, -2, -2, -2, -1, -1, 1, 2] ejey ejey = [1, 2, 2, 1, -1, -2, -2, -1] El tablero, del tamaño que sea, se representará mediante un array bidimensional de números enteros. A continuación se muestra un gráfico con un tablero de tamaño 5x5 con todo el recorrido partiendo de la esquina superior izquierda.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
43
Cuando se encuentra una solución, una variable que se pasa por referencia es puesta a 1 (cierto). Puede hacerse una variable de alcance global y simplificar un poco el código, pero esto no siempre es recomendable. Para codificar el programa, es necesario considerar algunos aspectos más, entre otras cosas no salirse de los límites del tablero y no pisar una casilla ya cubierta (selección del candidato). Se determina que hay solución cuando ya no hay más casillas que recorrer. A continuación se expone un código completo en C, que recubre un tablero cuadrado de lado N partiendo de la posición (0,0). #include #define N 5 #define ncuad N*N void mover(int tablero[][N], int i, int pos_x, int pos_y, int *q); const int ejex[8] = { -1,-2,-2,-1, 1, 2, 2, 1 }, ejey[8] = { -2,-1, 1, 2, 2, 1,-1,-2 }; int main(void) { int tablero[N][N]; /* tablero del caballo. */ int i,j,q; /* inicializa el tablero a cero */ for (i = 0; i < N; i++) for (j = 0; j < N; j++) tablero[i][j] = 0; /* pone el primer movimiento */ tablero[0][0] = 1; mover(tablero,2,0,0,&q); if (q) { /* hay solucion: la muestra. */ for (i = 0; i < N; i++) { for (j = 0; j < N; j++) printf("%3d ", tablero[i][j]); putchar('\n'); } } else printf("\nNo existe solucion\n"); }
return 0;
void mover(int tablero[][N],int i, int pos_x, int pos_y, int *q) { int k, u, v; k = 0; *q = 0; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
44
}
do { u = pos_x + ejex[k]; v = pos_y + ejey[k]; /* seleccionar candidato */ if (u >= 0 && u < N && v >= 0 && v < N) { /* esta dentro de los limites? */ if (tablero[u (tablero[u][v] ][v] == 0) 0) { /* es valido? valido? */ tablero[u][ tablero[u][v] v] = i; /* anota el candidato candidato */ if (i < ncuad) ncuad) { /* llega al al final del recorrido recorrido?? */ mover(tablero,i+1,u,v,q); if (!*q) tablero[u][v] = 0; /* borra el candidato */ } else *q = 1; /* hay solucion */ } } k++; } while (!*q && k < 8);
Cambiando el valor de N puede puede obtenerse una solución para un tablero cuadrado de tamaño N. A continuación, se muestra una adaptación del procedimiento que q ue muestra todas las solucioso luciones. Si se ejecuta para N = 5 se encuentra que hay 304 soluciones partiendo de la esquina superior izquierda. Cuando se encuentra una solución se llama a un procedimiento (no se ha codificado aquí) que imprime todo el tablero. void mover(int tablero[][N],int i, int pos_x, int pos_y) { int k, u, v;
}
for (k = 0; k < 8; k++) { u = pos_x + ejex[k]; v = pos_y + ejey[k]; if (u >= 0 && u < N && v >= 0 && v < N) { /* esta dentro de los limites */ if (tablero[u][v] == 0) { tablero[u][v] = i; if (i < ncuad) mover(tablero,i+1,u,v); else imprimir_solucion(tablero); tablero[u][v] = 0; } } }
El problema de las ocho reinas Continuamos con problemas relacionados con el ajedrez. El problema que ahora se plantea es claramente, como se verá, de vuelta atrás. Se recomienda intentar resolverlo a mano. Se trata de colocar colocar ocho reinas reinas sobre un tablero de ajedrez, ajedrez, de tal forma que ninguna amenace (pueda comerse) a otra. Para los que no sepan ajedrez deben saber que una reina amenaza a otra pieza que esté en la misma columna, fila o cualquiera de las cuatro diagonales. La dificultad que plantea este problema es la representación de los datos. Se puede utilizar un array bidimensional de tamaño 8x8, pero las operaciones para encontrar una reina que amenaLaboratorio de Programación EEST Nº5 – Prof Abdala Pablo
45
ce a otra son algo engorrosas y hay un truco para evitarlas. La solución aquí expuesta vuelve a ser tomada de Wirth Es lógico que cada reina debe ir en una fila distinta. Por tanto, en un array se guarda la posición de cada reina en la columna que se encuentre. Ejemplo: si en la tercera fila hay una reina situada en la quinta columna, entonces la tercera posición del array guardará un 5. A este array se le llamará col. llamará col. Hace falta otro array que determine si hay puesta una reina en la fila j-ésima. A este array se le llamará fila llamará fila.. Por último se utilizan dos arrays más para determinar las diagonales libres, y se llamarán diagb y diagb y diagc. diagc. Para poner una reina se utiliza esta instrucción: col[i] = j ; fila[j] = diagb[i+j] = diagc[7+i-j] = FALSE; Para quitar una reina esta otra: fila[j] = diagb[i+j] = diagc[7+i-j] = TRUE; Se considera válida la posición para este caso: if (fila[j] && diagb[i+j] && diagc[7+i-j]) entonces proceder ... A continuación se expone el código completo en C. Se han utilizado tipos enumerados para representar los valores booleanos. #include enum bool {FALSE, TRUE}; typedef enum bool boolean; void ensayar(int i, boolean *q, int col[], boolean fila[], boolean diagb[], boolean diagc[]); int main(void) { int i; boolean q; int col[8]; boolean fila[8],diagb[15], diagc[15]; for (i = 0; i < 8; i++) fila[i] = TRUE; for (i = 0; i < 15; i++) diagb[i] = diagc[i] = TRUE; ensayar(0,&q,col,fila,diagb,diagc); if (q) { printf("\nSolucion:"); for (i = 0; i < 8; i++) printf(" %d", col[i]); } else printf("\nNo hay solucion"); }
return 0; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
46
void ensayar(int i, boolean *q, int col[], boolean fila[], boolean diagb[], boolean diagc[]) { int j; j = 0; *q = FALSE; do { if (fila[j] && diagb[i+j] && diagc[7+i-j]) { col[i] = j; fila[j] = diagb[i+j] = diagc[7+i-j] = FALSE; if (i < 7) { /* encuentra solucion? */ ensayar(i+1,q,col,fila,diagb,diagc); if (!*q) fila[j] = diagb[i+j] = diagc[7+i-j] = TRUE; } else *q = TRUE; /* encuentra la solucion */ } j++; } while (!*q && j < 8); } Por último, se deja al lector que implemente un procedimiento que encuentre todas las soluciones. Si se desea complicar más entonces se puede pedir que encuentre todas las soluciones distintas, es decir, aquellas que no sean rotaciones o inversiones de otras soluciones. Ahora que se conoce el método general, puede hacerse extensible a múltiples piezas simultáneamente.
El Problema de la mochila (selección óptima) Con anterioridad se ha estudiado la posibilidad de encontrar una única solución a un problema y la posibilidad de encontrarlas todas. Pues bien, ahora se trata de encontrar la mejor solución, la solución óptima, de entre todas las soluciones.
Partiendo del esquema que genera todas las soluciones expuesto anteriormente se puede obtener la mejor solución (la solución óptima, seleccionada entre todas las soluciones) si se modifica la instrucción almacenar_solucion por esta otra: si f(solucion) si f(solucion) > f(optimo) entonces f(optimo) entonces optimo optimo <- solución
siendo f(s) función función positiva, optimo es es la mejor solucion encontrada hasta el momento, y solu- es una solucion que se está probando. probando. cion es
El problema de la mochila consiste en llenar una mochila con una serie de objetos que tienen una serie de pesos con un valor asociado. Es decir, se dispone de n tipos de de objetos y que no Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
47
hay un número limitado de cada tipo de objeto (si fuera limitado no cambia mucho el problema). Cada tipo i de de objeto tiene un peso w i i positivo y un valor v i i positivo asociados. La mochila tiene una capacidad de peso igual a W . Se trata de llenar la mochila de tal manera que se ma ximice el valor el valor de de los objetos incluidos pero respetando al mismo tiempo la restricción de capacidad. Notar que no es obligatorio que una solución óptima llegue al límite de capacidad de la mochila. mochila.
Ejemplo: se Ejemplo: se supondrá: n=4 W=8 w() = 2, 3, 4, 5 v() = 3, 5, 6, 10 Es decir, hay 4 tipos de objetos y la mochila tiene una capacidad de 8. Los pesos varían entre 2 y 5, y los valores relacionados varían entre 3 y 10. Una solución no óptima de valor 12 se obtiene introduciendo cuatro objetos de peso 2, o 2 de peso 4. Otra solución no óptima de valor 13 se obtiene introduciendo 2 objetos de peso 3 y 1 objeto de peso 2. ¿Cuál es la solución óptima?. A continuación se muestra una solución al problema, variante del esquema para obtener todas t odas las soluciones. void mochila(int i, int r, int solucion, int *optimo) { int k;
}
for (k = i; k < n; k++) { if (peso[k] <= r) { mochila(k, r - peso[k], solucion + valor[k], optimo); if (solucion + valor[k] > *optimo) *optimo = solucion+valor[k]; } }
Dicho procedimiento puede ser ejecutado de esta manera, siendo n, W, peso y valor variables globales para simplificar el programa: n = 4, W = 8, peso[] = {2,3,4,5}, valor[] = {3,5,6,10}, optimo = 0; ... mochila(0, W, 0, &optimo);
Ejemplo Backtraking
Caminos
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
48
Sea un tablero de dimensiones MxN, 1<=M<=9, 1<=N<=9, tal que cada casilla contenga una letra mayúscula. La casilla que está en la fila m y la columna n la identificamos mediante (m,n). Dos casillas diferentes (mi,ni) y (mj,nj) son adyacentes si se cumple: - para la primera componente, |mi-mj|<=1 o |mi-mj|=M-1, y - para la segunda componente, |ni-nj|<=1 o |ni-nj|=N-1. Es decir, son adyacentes todas aquellas casillas que rodean a una dada, considerando que en el tablero como si la última fila estuviera unida a la primera, y lo mismo para las columnas. En el dibujo siguiente marcamos con un asterisco las casillas adyacentes a las casillas (2,3) (a la izquierda) y (1,1) (a la derecha) en un tablero 4x4: .*** .*.* .*.* **.* .*** .... .... **.* Dada una palabra de k letras mayúsculas A=a1 a2 ... ak, k>=1, decimos que A está contenida en el tablero si se cumple que: - existe una casilla (m1,n1) que contiene la letra a1, - para cada letra ai+1, 1<=i
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
49
- Línea 1: valores de M y N (un carácter del '1' al '9') separados por un único blanco - Líneas de la 2 a la M+1 (la línea k representa la fila k-1 del tablero): N caracteres, representando el contenido de la línea correspondiente del tablero - Línea M+2: p caracteres, M*N>=p>=1, que representa la palabra a tratar. Salida A guardar en el archivo de caracteres "CAMI.OUT": p líneas (una para cada letra de la palabra a tratar), siendo el contenido de la línea k igual a la casilla que aparece en posición k dentro del camino de la palabra, de esta forma: carácter del '1' al '9' - blanco - carácter del '1' al '9' Ejemplo de entrada 44 SHAZ IOLG EZEF OHDI SOLA Ejemplo de salida 11 22 23 13 Este problema se ha resuelto utilizando la recursividad (marcha atrás, backtracking). Primero se busca la primera letra de la palabra buscada, y una vez encontrada se busca la siguiente entre las adyacentes. Así se miran todas las posibilidades hasta que se encuentra la palabra buscada. Es un método de fuerza bruta, un poco lento para casos grandes, pero muy efectivo cuando el tamaño de la tabla es pequeño (el límite en este problema es 9). El problema en sí no tiene más dificultades, pero se pueden utilizar un par de trucos para hacer el código más sencillo: 1.- No está permitido recorrer dos veces la misma casilla en una palabra, por lo que hay que tener algo que nos indique si una casilla se ha utilizado anteriormente o no. Para eso se utiliza otra tabla auxiliar del mismo tamaño que la original, original, inicializada inicializada a 0. Cuando una casilla casilla se utiliza, la casilla correspondiente de la tabla auxiliar pasa a marcar 1, así cuando se vaya a utilizar una casilla primero habrá que mirar si ya se ha usado o no (marca 1 ó 0). Hay que tener cuidado, al hacer hacer backtracking backtracking hay que volver a poner la casilla casilla a 0. 2.- Para mirar las casillas adyacentes en busca de una nueva letra se puede implementar una a una las 8 direcciones, lo que haría un código largo, engorroso y difícil de depurar, o se puede tener en dos arrays los incrementos posibles de sila y de columna; si estamos en (F,C), podemos ir a (F-1,C-1), (F-1,C), (F-1,C+1), (F,C-1), (F,C+1), (F+1,C-1), (F+1,C) y (F+1,C+1). Si tenemos un array con los valores:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
50
FF={-1,-1,-1, 0, 0, 1, 1, 1}; CC={-1, 0, 1,-1, 1,-1, 0, 1}; se puede llegar a las 8 casillas con un bucle for, del tipo: for(i=0;i<8;i++) { filanueva = filaantigua + FF[i]; columnanueva = columnaantigua + CC[i]; ... } Así se ahorra líneas de código, y en caso de haber errores, con modificarlo mo dificarlo en un sitio siti o basta. b asta. 3.- El problema también considera adyacentes de una casilla situada en un borde las casillas del lado opuesto, como si la tabla fuera cíclica. Para no tener que preocuparse de este problema, al hallar las casillas adyacentes basta con hacerlas módulo número de filas (o columnas, según corresponda): filanueva = (filaantigua + FF[i]) % numerodefilas; columnanueva = (columnaantigua + CC[i]) % numerodecolumnas; Pero esto falla en un caso, cuando filaantigua es 0, y FF[i] es -1, filanueva toma el valor -1 (lo que daría un runtime error). Para evitar eso, y aprovechándonos de que a % b = (a + b) % b, basta con poner: filanueva = (filaantigua + FF[i] + numerodefilas) % numerodefilas; columnanueva = (columnaantigua + CC[i] + numerodecolumnas) % numerodecolumnas; Así nos aseguramos de d e que las nuevas coordenadas son positivas. 4.- El programa te pide que des las posiciones de las casillas en las que está la palabra, ordenadas del principio al final, y al hacer backtracking salen ordenadas justo al revés (del final al principio). Para dar la salida correctamente hay dos soluciones: una es guardar las casillas en una tabla, lo que supone un gasto de memoria (y de tiempo, importante en una función recursiva). Lo más eficaz es buscar la palabra del final al principio, en vez de buscarla del principio al final. Por ejemplo, si te piden hallar la palabra SOLA, hallamos la palabra ALOS, y al dar las coordenadas de esta palabra al revés, se obtienen las coordenadas de la palabra SOLA en orden correcto. #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #include #include #include > #pragma #pragma argsused argsused bool bool busca( busca(int int,in ,int,i t,int) nt); ; // Funció Función n recurs recursiva iva que // busc busca a la pala palabr bra a pedi pedida da en la tabl tabla. a. char char mapa[9 mapa[9][9 ][9]; ]; // Variab Variable le que contie contiene ne la tabla. tabla. Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
51
char char v[9] v[9][9 [9]; ]; // Indi Indica ca si hemo hemos s util utiliz izad ado o una una casi casill lla a o no. no. int int F,C; F,C; // Núme Número ro de fila filas s y colu column mnas as de la tabl tabla. a. char cad[100]; cad[100]; int int l; // Pala Palabr bra a a busc buscar ar y su long longit itud ud. . int ff[8]= ff[8]={1, {1,1,1 1,1,-1 ,-1,-1 ,-1,-1 ,-1,0, ,0,0}; 0}; // Increm Increment ento o de la fila fila int cc[8]= cc[8]={-1 {-1,0, ,0,1,1,-1,0 1,0,1, ,1,-1, -1,1}; 1}; // Increm Increment ento o de la column columna a int main(i main(int nt argc, argc, char* char* argv[] argv[]) ) { int a,b; a,b; ifstream ifstream archivo_entra archivo_entrada("c: da("c:\\cam \\cami.dat" i.dat"); ); ofstream archivo_salida("c:\\cami.out");
// Abro los archivos.
archivo_entrada>>F; archiv archivo_e o_entr ntrada ada>>C >>C; ; // Leo el número número de filas filas y column columnas. as. for(a= for(a=0;a 0;a>mapa[a][b]; } archiv archivo_e o_entr ntrada ada>>c >>cad; ad; // Leo la palabr palabra a a buscar buscar l=strl l=strlen( en(cad cad); ); // y su longit longitud. ud. memset memset(v, (v,0,s 0,size izeof( of(v)) v)); ; // No he utiliz utilizado ado ningun ninguna a casill casilla. a. for(a= for(a=0;a 0;a
52
return return(tr (true) ue); ; // Seguir Seguir deshac deshacien iendo do el camino camino. . } v[f1][ v[f1][c1] c1]=0; =0; // Se marca marca como como no utiliz utilizada ada } } return return(fa (false lse); ); // No se ha encont encontrad rado o la palabr palabra. a. }
Cadenas de caracteres en C++. STRING Una cadena de caracteres en C++ no es más que un vector de caracteres. #include #include #include #include using using namesp namespace ace std; std; int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) {
// inicializaci inicializaciones ones string sCadena; sCadena; string sCadena2("ho sCadena2("hola2"); la2"); sCaden sCadena a = "hola" "hola"; ; cout cout << "1: "1: " << sCad sCaden ena a << " " << sCad sCaden ena2 a2 << endl endl; ;
// paso paso de char char* * a stri string ng y vice viceve vers rsa a char szCadena[10] szCadena[10]="adio ="adios"; s"; sCaden sCadena a = szCade szCadena; na; cout cout << "2: "2: " << sCad sCaden ena a << endl endl; ; sCaden sCadena a = "hola" "hola"; ; strcpy(szCadena,sCadena.c_str()); cout cout << "2b: "2b: " << szCa szCade dena na << endl endl; ;
// oper operac acio ione nes s de acce acceso so cout cout << "3: "3: " << "[3] "[3] " << sCad sCaden ena[ a[3] 3] << endl endl; ; cout cout << "4: "4: " << sCad sCaden ena. a.su subs bstr tr(0 (0,3 ,3) ) << endl endl; ;
// operac operacion iones es de busque busqueda da cout cout << "5: "5: " << sCad sCaden ena. a.fi find nd(" ("la la", ",0) 0) << endl endl; ;
// operac operacion iones es de modifi modificac cacion ion cout cout << "6: "6: " << sCad sCaden ena. a.er eras ase( e(0, 0,2) 2) << endl endl; ;
// operac operación ión de concat concatena enació ción n cout cout << "7: "7: " << sCad sCaden ena a + sCad sCaden ena2 a2 << endl endl; ;
// operac operación ión de compar comparaci ación ón cout cout << "8: "8: " << (sCa (sCade dena na == sCad sCaden ena) a) << endl endl; ;
// Oper Operac acio ion n de long longit itud ud cout cout << "9: "9: " << sCad sCaden ena. a.le leng ngth th() () << endl endl; ;
// Oper Operac acio ion n de tama tamaño ño cout cout << "10: "10: " << sCad sCaden ena. a.si size ze() () << endl endl; ; return return 0;
operador[]
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
53
Imprime el contenido de la variable str, caracter por caracter con el ciclo for. #include #include #include #include using namespace namespace std;
main () int main { stri string ng str str ("pr ("prue ueba ba de stri string ng") "); ; int i; (i=0; i < str. str.le leng ngth th() (); ; i++) i++) for (i=0; { cout cout << str[ str[i] i]; ; } return 0; }
Swap Vuelca el contenido de un String en otro
#include #include #include #include using using namesp namespace ace std; std; int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) { string string buyer buyer ("dine ("dinero" ro"); ); string seller ("mercaderia ("mercaderia"); "); cout cout << "Ant "Antes es de camb cambia iar r el comp compra rado dor r tien tiene e " << buye buyer; r; cout cout << " y el vend vended edor or " << sell seller er << endl endl; ; seller.swap seller.swap (buyer); (buyer); cout cout << " Ante Antes s de camb cambia iar r el comp compra rado dor r tien tiene e " << buye buyer; r; cout cout << " y el vend vended edor or tien tiene e " << sell seller er << endl endl; ; getch(); return return 0; }
find_first_of Encuentra caracteres en una variable String #include #pragma hdrstop #include #pragma argsused #include #include using namespace std; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
54
int main(int argc, char* argv[]) { string str ("Remplaza las vocales por asteriscos."); size_t found; found=str.find_first_of("aeiou"); while (found!=string::npos) { str[found]='*'; found=str.find_first_of("aeiou",found+1); } cout << str << endl; getch(); return 0; }
Biblioteca conio Contiene los prototipos de las funciones, macros, y constantes para preparar y manipular la consola en modo texto en el entorno de MS-DOS. Nombre Función clrscr
getch
getchar goto gotoxy xy(i (int nt x, int int y);
Descripción Esta función función despeja la ventana ventana de texto actual actual y coloca el cursor en la esquina superior izquierda: posición (1,1). La función función getch retorna retorna el carácter leído desde el teclado.
Ejemplo clrscr();
Lee un caracter de el teclado y regresa el caracter leido.
char vocal;
Mueve el cursor de la ventana de texto a la posición según las coordenadas especificadas por los argumentos x argumentos x e e y y.. Si las coordenadas no son válidas entonces la llamda a la función gotoxy es ignorada. Los argumentos no pueden ser 0.
getch();
vocal=getchar(); gotoxy( 1, 15 );
Librería math.h es math.h es un archivo de cabecera de la biblioteca la biblioteca estándar . estándar . Muchas de sus funciones incluyen el uso de números en coma en coma flotante. flotante. Nombre Nombre acos asin atan atan2 cos
Descrip Descripció ción n arcocoseno arcoseno arcotangente arcotangente de arcotangente de dos parámetros coseno
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
55
abs fmod
valor absoluto resto del punto flotante prin printf tf ("fm ("fmod od de 5.3 5.3 / 2 es%l es%lf\ f\n" n", , fmod fmod (5.3 (5.3,2 ,2) ) );
pow(x,y) eleva un un valor dado dado a un exponent exponente, e, xy sin seno Sqr Cuadrado de un número
int int main main () { double double param, param, result; result; param param = 1024.0 1024.0; ; result result = sqrt sqrt (para (param); m); printf printf ("sqrt ("sqrt(%l (%lf) f) = %lf\n" %lf\n", , param, param, result result ); return return 0; }
sqrt tan
raíz cuadrada tangente
Punteros Introducción El puntero es una técnica muy potente que hace que la programación C++ sea tan utilizada. La técnica de punteros apoya a la programación orientada a objetos, que es una de las grandes diferencias entre C y C++. Definición: Un puntero es una variable que almacena una dirección de memoria.
Operador de Dirección: &
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
56
Referencias
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
57
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
58
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
59
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
60
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
61
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
62
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
63
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
64
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
65
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
66
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
67
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
68
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
69
Templates INTRODUCCIÓN Las técnic técnicas as de Templa Templates tes en C++, permite permitenn un grado grado de progra programac mación ión genéri genérica, ca, creand creandoo códigos especiales especiales para problemas problemas especializa especializados. dos. Por ejemplo, ejemplo, la idea idea del del valor valor mínimo mínimo o máximo, máximo, se repite infinidad infinidad de veces veces en la programaprogramación, ción, aunqu aunquee los objet objetos os a evalu evaluar ar varíe varíenn de un caso caso a otro otro por el el tipo de de datos. datos. Sobre Sobre esta esta idea surgió un nuevo paradigma paradigma denominado denominado programación programación genérica genérica o funcional. funcional. La programación genérica está mucho más centrada en los algoritmos que en los datos y su postulado fundamental puede sintetizarse en una palabra: generalización. Significa que, en la Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
70
medida de lo posible, los algoritmos algoritmos deben deben ser parametrizado parametrizadoss al máximo y expresados de la forma forma más más indepe independi ndient entee posible posible de deta detalle lless concret concretos, os, permi permitie tiendo ndo así así que puedan puedan servir servir para para la mayor mayor varied variedad ad posible posible de tipos tipos y estruc estructur turas as de datos. datos. A menudo se tiene el pensamiento que un programa es la implementación de un mapeo (map (mappin ping) g).. El progr program amaa toma toma valo valore ress y mapea mapea enton entonce cess a su salid salida. a. En la progr program amaación ción impera imperativ tivaa este este mappi mapping ng es es reali realizad zadoo en forma forma indire indirecta cta,, por los coma comando ndoss que que leen leen valore valoress de de entr entrada ada,, man manipu ipulan lan estos estos y luego luego escrib escriben en las salida salidas. s. Los comand comandos os influy influyen en en los programas programas mediante mediante el uso de las variables variables almacenada almacenadass en en la memoria. memoria. En la programa programación ción funcional, funcional, el mapping mapping de valores valores de entrad entradaa a valores de salida salida es realirealizado de modo directo. El programa es una función o grupo de funciones; sus relaciones son muy simples: entre ellas se invocan. Los programas son escritos en un lenguaje de expresiones, funciones funciones y declarac declaraciones. iones. El código es similar siempre, pero estamos obligados a rescribir ciertas funciones que dependen del tipo o de la clase del objeto que se almacena. Tómese por ejemplo el problema de encont encontrar rar el valor valor mayor mayor de un par de datos; datos; tanto tanto para para un entero entero,, flotan flotante, te, carác carácter ter,, etc. etc. Se hace hace uso de las funcio funciones nes proto prototipo tipos; s; en este este caso caso para para enco encontr ntrar ar el el mayor mayor de dos dos valovalores para distintos tipos de datos: Se hace ace uso de esta sta sobrecarg sobrecargaa de funciones funciones,, para obtener el mayor entre dos enteros, doble flotantes flotantes y carácter. carácter. int max(int,int) max(int,int); ; double max(double,d max(double,double) ouble); ; char max(char,cha max(char,char); r);
#include #include #include #include // sobr sobrec ecar arga ga de func funcio ione nes s para para max( max() ) int max(int,int) max(int,int); ; double max(double,d max(double,double) ouble); ; char max(char,cha max(char,char); r); void void main() main() { int a=5,b= a=5,b=3; 3; cout cout <<" <<" El mayo mayor r de los los ente entero ros s es : “ << max( max(a, a,b) b)<< << endl endl; ; double c=5.5,d=10; c=5.5,d=10; cout cout << “ El mayo mayor r de los los flot flotan ante tes s es: es: “ << max( max(c, c,d) d)<< << endl endl; ; char e='a',f='A'; e='a',f='A'; cout << “ El may mayor de los los cha char es : “ << max max(e,f)<< end endl; system(“PAUSE”); } int int max( max(in int t a,in a,int t b) { return return a>b?a:b; a>b?a:b; } Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
71
double double max(do max(doubl uble e a,doub a,double le b) { return return a>b?a:b; a>b?a:b; } char char max( max(ch char ar a,ch a,char ar b) { return return a>b?a:b; a>b?a:b; }
Un Template es una forma de objeto, que se aplica a diferentes instancias, sin especificar el tipo de objet objetoo a ser ser refer referenc enciad iado. o. El patrón patrón con un simpl simplee código código cubre cubre un gran gran rango rango de funcio funciones nes de de sobrec sobrecarg argaa denomi denominad nadas as funci funcione oness patron patrones es o un gran gran rango rango de clas clases es denodenominadas clases patrones. Se dice dice que los los patrones patrones son son como una una factoría factoría de ensamblaje, ensamblaje, porque producen producen una varievariedad de objetos objetos;; es decir, decir, dado un materi material al se produc producee un determ determina inado do artícu artículo. lo. Las templa templates tes permite permitenn parame parametri trizar zar estas estas clase clasess para adapt adaptarl arlas as a cualqu cualquier ier tipo. tipo. Así el cambio de las tres sobrecargas, viene reemplazado siguiente Template: Esta Esta func funció iónn trab trabaj ajaa para para entero enteros, s, como como tambi también én para para flot flotan ante tess y para para cara caract cter eres es.. Afortunadamente existen los template que q ue hacen la labor de programación más fácil. Los templ templat ates es tamb tambié iénn deno denomi mina nada dass tipos tipos para parame metr triza izados dos,, son un meca mecani nism smoo de C++ C++ que permit permitee que un tipo tipo pueda pueda ser utiliz utilizado ado como como pará parámet metro ro en la defini definició ciónn de una clase clase o una función. función. template T max(T a,T b) { return a>b?a:b; }
#include #include #pragma #pragma hdrstop hdrstop #include #include #include #include // sobr sobrec ecar arga ga de func funcio ione nes s para para max( max() ) template T max( max(T T a,T a,T b) { return return a>b?a:b; a>b?a:b; } #pragma #pragma argsused argsused int int main main(i (int nt argc argc, , char char* * argv argv[] []) ) { int a=5,b=3; cout cout << " El mayo mayor r de los los ente entero ros s es : " << max( max(a, a,b) b)<< << endl endl; ; double double c=5.5,d=10; c=5.5,d=10; cout cout << " El mayo mayor r de los los flot flotan ante tes s es: es: " << max( max(c, c,d) d)<< << endl endl; ; char e='a',f='A'; e='a',f='A'; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
72
cout cout << " El mayo mayor r de los los char char es : " << max( max(e, e,f) f)<< << endl endl; ; system("PAUSE"); return return 0; }
C++ permite crear Templates de funciones y de clases. La sintaxis sintaxis para para declarar declarar un templat templatee de funció funciónn es pareci parecida da a la de cualquie cualquierr otra funci función, ón, pero pero se añade añade al principi principioo una presenta presentació ciónn de la clase clase que se usará usará como refere referenci nciaa en la plantilla: La lista de clases clases que se incluye incluye a contin continuac uación ión de la palabr palabraa reserv reservada ada templa template te se escribe escribe entre las llaves llaves "<" y ">"; ">"; y en en este caso esos símbolos símbolos no no indican indican que que se debe introducir introducir un literal. literal. Se ha conside considerad radoo que el templa template, te, radiqu radiquee en un archiv archivoo tipo tipo header header,, donde donde se ha ha inc inclui lui-do la función plantilla min(), template[...]> typename[...]> retorno> ( or>() os>) { // cuer cuerpo po de la func funció ión n }
Considerar Considerar que el template template radique en un archivo archivo tipo header, header, donde se ha incluido incluido la función función plantilla min(). // minymax.h #ifndef __MINYMAX_H #define __MINYMAX_H template T max(T a,T b) { return (a>b)?a:b;} template T min(T a,T b) { return (a #include #include "minymax.h" void main() // Eduardo Raffo Lecca { int x1=4,x2=3; double y1=7.5,y2=8.3; char c1='a',c2='A'; c1='a',c2='A'; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
73
cout cout << "min "min int int : " << << min(x1 min(x1,x2 ,x2)) << endl; endl; cout << "max double : " << max(y1,y2) << endl; cout << << "max "max char char : " << max(c1,c2) max(c1,c2) << << endl; endl; system("PAUSE"); } Un Template Template que ejecuta ejecuta el valor máximo para para tres valores valores #include #include #include #include templa template te T maxi maximo mo(T (T a,T a,T b,T b,T c) { T max=(a>b?a:b max=(a>b?a:b); ); return(max>c?max:c); } Int main() main() { int a,b,c; a,b,c; cout cout << "ing "ingre rese se 3 ente entero ros s cin >> a >> b >> c; int j=maximo(a,b j=maximo(a,b,c); ,c); cout << "mayor : " << j << char char d,e,f; d,e,f; cout << << "i "ingrese 3 ch char cin >> d >> e >> f; char k=maximo(d,e k=maximo(d,e,f); ,f); cout << "mayor : " << k << system("PAUSE"); }
: " << endl endl; ;
endl; : " << << en endl;
endl;
Trabajos Trabajos Prácticos Prácticos Trabajo practico Estructuras de control Escribir los programas que se detallan a continuación. 1. La municipalidad debe liquidar impuestos atrasados de los últimos 10 años, los datos a ingresar son: Nro. De Contribuyente, Año, e Importe. Desarrollar un algoritmo que ingrese los datos e imprima la liquidación actualizando el importe de acuerdo al índice de la siguiente tabla. 1992-1994 1995 1996-1997 Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
:31 :3150 :3000 :28 :2800 74
1998-2004 2005:20 :2012
:20 :2001 :20 :2000
2.- Leer una temperatura e imprimir el deporte apropiado de acuerdo a la siguiente tabla: Temp Temp > 28 28>-= 28>-= Temp Temp >= 20 20 20>-= Temp >= 15 15 15>15>-= = Temp Temp >= 5 -5 = Temp
:Wat :Water erpo polo lo : Surf Surf :futbol :futbol :ajed :ajedre rezz :Snowboard
3.- Dados tres tres números hallar hallar el mayor. mayor. 4.- Calcular Calcular la suma de los N primeros números números naturales. naturales. 5.- Dado un número número entero entero decir decir si: a) es par par o impar impar;; b) es mayor, mayor, menor o igual a cero. cero. 6.- Dado un mes escribir la cantidad de días de dicho mes. 7.- Escribir las tablas de multiplicar del número 1 al número 9 de los primeros 15 números. 8 Una Una empr empres esaa fabr fabric icaa tapa tapass de mate materi rial al lami lamina nado do en 3 form format atos: os: redo redond ndo, o, cuad cuadra rado do o rectangular. Cobra $18 el metro cuadrado y si la tapa es redonda, le suma $4 más al total. Se pide: a) Ingresar Ingresar el código de forma: 1-redonda, 1-redonda, 2- cuadrada, cuadrada, 3- rectangular rectangular b) Ingres Ingresar ar la longitud longitud en metros: metros: si es cuadra cuadrada, da, se ingresa ingresa un solo valor valor y si es redonda, corresponde al radio del círculo c) Informar Informar el costo total de la tapa tapa 9.- Se ingresan pares de valores decimales y se debe informar el promedio de cada par. El ingreso de datos finaliza cuando el operador responde NO a la siguiente pregunta: “ Desea calcular el promedio? (SI / NO)?” 10.- Se realiza una encuesta para estimar el grado de aceptación de los productos x e y e y en en el mercado. A cada encuestado se le pregunta si consume el producto x y si consume el producto y. Fin de ingreso de datos -1 datos -1 a X. La X. La respuesta puede ser si ser si o o no no.. Se pide calcula calcularr e informar informar el porcentaje de consumidores de: a) del producto x b) del producto y c) del producto producto x solamente solamente d) del producto producto y solamente solamente e) de ambos ambos productos productos f) de ninguno ninguno de los productos productos 11.- En una empresa el sueldo se calcula adicionando al básico 50% del mismo, en caso en que la antigüedad sea superior a los 10 años. Diseñar un programa que lea el nombre del empleado, el sueldo básico y la antigüedad y escriba el nombre y el sueldo a cobrar.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
75
12.- Ingresar 3 números, donde los dos primeros representan los extremos de un intervalo. Se solicita verificar si el valor pertenece o no al intervalo. 13.- Una empresa ha decidido decidido dar a sus empleados empleados una gratificación gratificación adicional adicional que depende depende de las horas extras y ausencias. Sea Horas= Horas Extras – (2/3)* ausencias. La gratificación G se calcula de la siguiente manera: Horas <= 10 G: 100 10< 10< horas oras <=20 G: 200 20200 kwh.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
76
18.- El equipo de Hockey ha tenido una buena buena campaña campaña y desea premiar premiar a sus jugadores con un aumento de salario para la siguiente campaña. Los sueldos deben ajustarse de la siguiente forma: Sueldo Actual Aumento Hasta 4800
20%
4801- 6000
10%
6001 – 6600
5%
Mas de 6600
No hay
El equipo tiene un cuadro de 20 jugadores. Diseñe un algoritmo que lea el Nombre del Jugador y el salario Actual y que a continuación imprima el nombre, el sueldo actual y el monto aumentado. Al final de la lista debe proporcionar, también, el monto total de la nueva nómina que incluye los aumentos mencionados. 19.- Calcular la suma de los primeros 1000 múltiplos de 2. 20.- Que imprimen los siguientes códigos a)
b)
c)
d)
int x = 2, y = 6, z = 4;
int x = 2, y = 6, z = 4;
int x = 2, y = 6;
int i=4, x=5;
y = y+4*z;
if(x>y || x
if(x
for(i=0; i<10; i++)
y +=x;
cout<<"verdadero" ;
cout<<"verdadero";
{
cout<
else
else
if(i
cout<<"falso";
cout<<"falso";
else cout<
Trabajo Practico Funciones 1. Escribir un programa que lea una cadena de caracteres y la visualice en un cuadro ********** *Algoritmos* ********** 2. Escribir un programa que lea una frase, sustituir todas las secuencias de dos o varios blancos por un solo blanco y visualizar visualizar la frase obtenida. obtenida. 3. Escribir un programa que lea una frase y a continuación visualice cada palabra de la frase en una columna, seguido del número de letras que componen la frase.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
77
4. Escribir Escribir un programa que posea una función función lógica llamada llamada Vocal que determine determine si un carácter es una vocal. 5. Escribir un programa que permita al usuario elegir el cálculo del área de cualquiera de las figuras geométricas: círculo, cuadrado, rectángulo o triángulo mediante funciones. 7. Escribir un programa que posea una función que tenga un argumento de tipo entero y que devuelva la letra P si el número es positivo, y la letra N si es cero o negativo. 8. Escribir un programa que permita deducir si un número N es primo, apoyándose en una función llamada Primo. 9.- Escribir un programa que posea una función lógica de dos argumentos enteros, que devuelva true si si uno es múltiplo del otro y false en en caso contrario. 10.- Escribir una función inversa que recibe una cadena cad como como parámetro y devuelve los caracteres de cad en en orden inverso. Por ejemplo, si cad es es ‘Pablo?’, la función devuelve ‘?olbaP’. 11. Que imprime el siguiente código a)
int mi_fun mi_funcio cion( n( ) { return return 3+2; 3+2; } int int main main( ( ){ cout<<”La cout<<”La function function devuelde”<
78
} d) int mi_fun mi_funcio cion(i n(int nt x) { return return x*x; x*x; } int main(void){ main(void){ int int x=3; x=3; mi_funcion(x); cout<< cout<<“La “La function function devuelde devuelde ”<< mi_funci mi_funcion( on(x)) x)); ; cout cout<< <<”L ”La a vari variab able le vale vale x vale vale”< ”<< < x; } e) int mi_fun mi_funcio cion(i n(int nt x) { x=x*5; return return x; } int int main main( ( ){ int int x=3; x=3; mi_funcion(x); cout<< cout<<” ” functi function on devuel devuelve ve “<< mi_fun mi_funcio cion(x n(x)); )); cout cout<< <<”L ”La a vari variab able le vale vale x vale vale”< ”<< < x; }
Guía de trabajos Prácticos. Vectores y Matrices 1) Leer un vector llamado Z llamado Z de de N N elementos. elementos. A partir de su lectura calcular: a) Generar Generar un vector llamado llamado POSITIVO con POSITIVO con la cantidad y el promedio de elementos positivos. b) Generar Generar un un vector vector llamado llamado NEGATIVO NEGATIVO con la cantidad cantidad y el promedio promedio de elementos elementos negativos. c) Generar Generar un un vector vector llamado llamado ZERO con ZERO con la cantidad y el promedio de elementos igual a 0. 2) Una compañía almacena la información relacionada a sus proveedores en los arreglos: - P(N) arreglo de proveedores, donde cada P(I) es el nombre del proveedor ordenado alfabéticamente - C(N) arreglo de ciudad, donde cada C(I) es el nombre de la ciudad en la que reside el proveedor P(I) - A(N) arreglo de artículos, donde cada A(I) es el número de artículos diferentes del proveedor P(I) Realice un programa en C++ que pueda llevar a cabo las siguientes transacciones: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
79
Dado el nombre del proveedor, informar el nombre de la ciudad en la que reside y el número de artículos que provee. Actualizar el nombre de la ciudad, en caso de que un proveedor cambie de domicilio; los datos serán el nombre del proveedor y el nombre de la ciudad a la que se mudó. Actualizar el número de artículos de un proveedor en caso de que éste aumente o disminuya. La compañía da de baja a un proveedor: actualizar los arreglos. 3) Escribir un programa que lea un vector A de N elementos (N es un dato entero suministrado por el usuario). Una vez leído el vector, el programa debe permitir al usuario elegir a través de un menú la ejecución de las siguientes opciones: a) Volver a leer los datos del vector b) Calcular el elemento mayor y menor del vector c) Calcular la suma de los elementos que componen el vector (ΣA[i]=A[1]+A[2]+…+A[N]) d) Calcular el promedio de los elementos que componen el vector (ΣA[i]/N)
e) Calcular el producto de los elementos que componen el vector f) Crear un nuevo vector que contenga los elementos del array transpuestos, es decir, B[1] contiene el elemento A[N], B[2] contiene el elemento A[N-1], …, B[N] contiene el elemento A[1] g) Crear un nuevo vector que contenga los elementos del vector A pero con una posición corrida, es decir, B[1] contiene el elemento A[2], B[2] contiene el elemento A[3], …, B[N] contiene el elemento A[1] h) Crear un nuevo vector que contenga los elementos del vector A pero con M posiciones corridas (siendo M
80
mina, el programa debe devolver el número de minas que se encuentran en las casillas adyacentes a la casilla en cuestión, entendiendo por adyacentes todas aquellas casillas que se encuentren encima, debajo, a la izquierda, a la derecha, y en las cuatro esquinas. El juego se gana cuando el jugador es capaz de levantar todas las casillas libres del tablero sin haber “explotado” con ninguna mina. 6) Se posee una una matriz de F filas filas y C columnas. columnas. a.- Asignarle Asignarle valores valores a todos sus elementos elementos teniendo teniendo en cuenta que cada elemento elemento a[i,j] está definido como si i*j es par el valor que que se le asigna a la posición posición es i+j si i*j es impar el valor que se le asigna a la posición es i-j . Ejemplo: si f=2 y c=4 b.- Imprimir la matriz. 0 3 -2 5 3 4 5
6
7.- Leer una matriz de NxN elementos enteros llamada tierra. tierra. Generar un vector llamado agua que contenga los elementos de la matriz tierra remplazados tierra remplazados en la siguiente función: 2 3 X *Pi+ 6X . Calcular Calcular el promedio de los elementos elementos que se encuentran encuentran en la diagonal superior superior y generar un vector llamado Aire tal Aire tal que contenga los elementos de tierra multiplicados por aire. Y Generar un vector llamado Fuego llamado Fuego de de tipo char que conten contenga ga los elemen elementos tos de la diagon diagonal al inferior convertidos en cadena de caracteres. Mostrar por pantalla Agua, fuego, tierra y aire. 8.- Ingresar una matriz A(10,8), calcular e informar la suma de sus elementos. 9.- Leer una matriz de F filas y C columnas. (F =C) a.- Calcular el elemento Minimo de la matriz b.- Calcular el promedio de cada una de las filas. c.- Calcular Calcular el promedio de los elementos elementos de la diagonal diagonal principal principal d.- Calcular Calcular el promedio de los elementos elementos de la diagonal diagonal secundaria secundaria.. e.- A cada elemento par de la matriz guardarlo en un vector llamado Pares. llamado Pares. 10. Entrada: Se tienen una matriz de N líneas, y M números para cada uno de estos i números, 0
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
81
Entrada
Salida
1 1 1 1
1 3 5 2
2 1 1 3
2 1 3 1
3 5 5 3
3 3 3 5
8 7 3 2
11. Generar una matriz de NxN (N ingresada por el usuario < 100) con números aleatorios menores a 5000. Guardar Guardar en un Vector Vector todos todos los números números abundantes (función recursiva) que se encuentren en la matriz. Número abundante :
todo número natural que cumpla la condición que la suma de sus divisores propios sea mayor que el propio número. Por ejemplo, 12 es abundante ya que sus divisores son 1, 2, 3, 4 y 6 y se cumple que 1+2+3+4+6=16, que es mayor que el propio 12. Los primeros primeros números números abundantes abundantes son: 12, 18, 20, 24, 30, 36, 40, 42, 48, 54, 56, 60, 66, 70, 72, 78, 80, 84, 88, 90, 96, 100, 102, …
Trabajo Práctico Recursividad. 1.- Diseñar un programa que posea una función recursiva que permita multiplicar dos números enteros M y N. Acumulando su contenido hasta que uno de los dos llegue a 0. 2.- Diseñar un programa que dado un numero decimal lo transforme a uno binario y a otro Hexadecimal. 3.- Escribir las funciones, una recursiva y otra no recursiva, tal que dado el entero positivo X devuelva true(verdadero) si y solo si X es potencia de 2. 4.- Escribir un programa que utilice una función recursiva EscribeBlancos(n) que imprima n caracteres blancos consecutivos. 5.- Diseñar un algoritmo recursivo que imprima los dígitos de un número decimal en orden inverso. 6.- Escribe una función recursiva recursiva que devuelva devuelva la suma de los valores almacenados almacenados en un array de enteros. 7.- Escribe un programa recursivo que calcule la suma de los primeros N números pares naturales. 8.- Imple Implemen mente te un progra programa ma que que utilic utilicee una funció funciónn recurs recursiva iva que que imprima imprima por por pantal pantalla la los valores desde 1 hasta el número introducido desde teclado por el usuario. 9.- Dado un vector de n números enteros, diseñar un algoritmo recursivo que dado el vector devuelva: · La posición posición del último número número par que aparece aparece en el vector · El valor 0 si ningún ningún elemento elemento del vector vector es par
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
82
10.- Diseñe una función recursiva que devuelva cierto si una palabra es palíndroma o falso en caso caso cont contra rari rio. o. Deci Decimo moss que que una una pala palabr braa es palí palínd ndro roma ma si se lee lee igua iguall de dere derech chaa a izquierda que de izquierda a derecha.
Trabajo Práctico archivos 1.- crear un programa que vaya leyendo las frases que el usuario teclea y las guardar en un fichero de texto llamado “registroDeUsuario.txt”. Terminará cuando la frase introducida sea "fin" (esa frase no deberá guardarse en el fichero). 2.-Hacer un programa que pida al usuario que teclee frases, y las almacene en el fichero “frases.txt”. Acabará cuando el usuario pulse -1. Después deberá mostrar el contenido del fichero. 3. Hacer un programa que pregunte un nombre de fichero y muestre en pantalla el contenido de ese fichero 4.- Hacer un programa que pida al usuario que teclee frases, y las almacene en el fichero "registro.txt", que puede existir anteriormente (y que no deberá borrarse, sino añadir al final de su contenido). Cada sesión acabará cuando el usuario pulse -1. 5.- Crear un programa que pida al usuario pares de números enteros y escriba su suma (con el formato "20 + 3 = 23") en pantalla y en un fichero llamado "sumas.txt", que se encontrará en un subdirectorio llamado "resultados". Cada vez que se ejecute el programa, deberá añadir los nuevos resultados a continuación de los resultados de las ejecuciones anteriores.
Trabajo Práctico Punteros Ejerci Ejercicio cio 1: Punter Punteros os ¿Qué ¿Qué imprim imprime?. e?. a) int *punt; *punt; int int x=7; x=7; int int y=5; y=5; punt=&x; *punt=4; Cout<< Cout<
83
d) int *punt; *punt; int int x=7; x=7; int int y=5; y=5; punt=&x; *punt=3; punt=&y; *punt=x; x=9; Cout<< Cout<<*pu *punt< nt<
e) int *punta *punta, , *puntb *puntb; ; int int x=7; x=7; int int y=5; y=5; punta=&x; *punta=3; puntb=&y; *puntb=x; x=9; Cout<< Cout<<*pu *puntb ntb<
f) int *punta *punta, , *puntb *puntb; ; int int x=7; x=7; int int y=5; y=5; punta=&x; *punta=3; puntb=&y; *puntb=x; x=9; Cout<< Cout<<*pu *puntb ntb<
84
punt=x; *punt=9; for(i=0;i<5;i++) Cout Cout<< << x[i] x[i] <<”/ <<”/”< ”<<; <; // ¿qué ¿qué impr imprim ime e este este cout cout? ? i) int *punt, *punt,i; i; int x[5]={1,2,3, x[5]={1,2,3,4,5}; 4,5}; punt=&x[0]; *punt=9; punt[3]=7; for(i=0;i<5;i++) Cout Cout<< << x[i] x[i] <<”/ <<”/”< ”<<; <; // ¿qué ¿qué impr imprim ime e este este cout cout? ? j) int *punt, *punt,i; i; int x[5]={1,2,3, x[5]={1,2,3,4,5}; 4,5}; punt=x; *x=11; *(punt *(punt+3) +3)=9 =9 ; for(i=0;i<5;i++) Cout Cout<< << x[i] x[i] <<”/ <<”/”< ”<<; <; // ¿qué ¿qué impr imprim ime e este este cout cout? ? k) int *punt, *punt,i; i; int x[5]={1,2,3, x[5]={1,2,3,4,5}; 4,5}; punt=x; *(punt+2)=9; *(x+3) *(x+3)=7 =7 ; punt[1 punt[1]=1 ]=11 1 ; for(i=0;i<5;i++) Cout Cout<< << *(pu *(punt nt+i +i) ) <<”/ <<”/”< ”<<; <; // ¿qué ¿qué impr imprim ime e este este cout cout? ? l) int *punt, *punt,i; i; int x[5]={1,2,3, x[5]={1,2,3,4,5}; 4,5}; punt=x+4; *(punt-2)=9; punt--; *(punt *(punt)=7 )=7 ; punt[1 punt[1]=1 ]=11 1 ; for(i=0;i<5;i++) Cout Cout<< << *(pu *(punt nt+i +i) ) <<”/ <<”/”< ”<<; <; // ¿qué ¿qué impr imprim ime e este este cout cout? ? ll) int *punt, *punt,i; i; int x[5]={1,2,3, x[5]={1,2,3,4,5}; 4,5}; punt=&x[0]+3; *(punt-2)=9; punt--; *(punt *(punt)=7 )=7 ; Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
85
punt[1 punt[1]=1 ]=11 1 ; punt=x; for(i=0;i<5;i++) Cout<< Cout<< punt[i punt[i]<< ]<<”/” ”/”<<; <<; // ¿qué ¿qué imprim imprime e este este cout? cout? m) void void suma suma_d _dos os(i (int nt *x, *x, int int *y, *y, int int *z) *z) { *x=*x+2; *y=*y+2; *z=*z+2; } int main() main(){ { int x,y,z; x,y,z; x=3; y=10; z=15; suma suma_d _dos os (&x, (&x, &y, &y, &z); &z); Cout Cout<< << x<<” x<<”/” /”<< << y<<” y<<”/” /”<< << z<<; z<<; // ¿qué ¿qué impr imprim ime e este este cout cout? ? } n) void void dato datos( s(in int t *x, *x, floa float t *y, *y, char char *c) *c) { *x=8; *y=4.2; *c=’g’; } int main() main(){ { int int x=9; x=9; float float y=44.6 y=44.6; ; char char c=’a’; c=’a’; dato datos s (&x, (&x, &y, &y, &c); &c); Cout Cout<< << x<<” x<<”/” /”<< << y<<” y<<”/” /”<< << c<<; c<<; // ¿qué ¿qué impr imprim ime e este este cout cout? ? } ñ) void void dato datos( s(in int t *x, *x, floa float t *y, *y, char char *c) *c) { Cout Cout<< << x<<” x<<”/” /”<< << y<<” y<<”/” /”<< <
86
Cout Cout<< << x<<” x<<”/” /”<< << y<<” y<<”/” /”<< <
87
Cout Cout<< << x<<” x<<”/” /”<< << y<<” y<<”/” /”<< <
r) #include #include void void vect vector or (flo (float at * vp[] vp[], , floa float t v[], v[], int int lon) lon); ; void void main() main(){ { float v[5]={1,2,3, v[5]={1,2,3,4,5}; 4,5}; floa float t * vp[5 vp[5]= ]={N {NUL ULL} L}; ; //ve //vect ctor or de punt punter eros os a floa float t for for (int (int i=0; i=0; i<5; i<5; i++) i++) { vp[i]=&v[i]; } vector vector(vp (vp, , v, 5); } void void vect vector or (flo (float at * vp[] vp[], , floa float t v[], v[], int int lon) lon) { for for (int (int i=0; i=0; i
s) #include #include #include #include void void inve invers rso_ o_ar arra ray y (int (int v[], v[], int int inv[ inv[], ], int int & lon) lon) { for( for(in int t i=0; i=0; i
t) Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
88
#include #include void void vect vector or (flo (float at * vp[] vp[], , floa float t v[], v[], int int lon) lon); ; void void main() main(){ { float v[5]={1,2,3, v[5]={1,2,3,4,5}; 4,5}; floa float t * vp[5 vp[5]= ]={N {NUL ULL} L}; ; //ve //vect ctor or de punt punter eros os a floa float t for for (int (int i=0; i=0; i<5; i<5; i++) i++) { vp[i]=&v[i]; } vector vector(vp (vp, , v, 5); } void void vect vector or (flo (float at * vp[] vp[], , floa float t v[], v[], int int lon) lon) { for for (int (int i=0; i=0; i
u) #include #include #pragma #pragma hdrstop hdrstop #include #include #include #include #include #include #pragma #pragma argsused argsused int int I(ch I(char ar *s); *s); int main() main() { char char *s= *s= "Pab "Pablo lo Abda Abdala la Acha Achava val" l"; ; I(s); cout cout << s; getch(); return return 0; } //----int int I(ch I(char ar *s) *s) { char char *t= *t= s; while while (*t) (*t) t++; t--;
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
89
whil while( e(s s < t) { char char Temp Temp= = *s; *s; *s++= *s++= *t; *t--= *t--= Temp; Temp; } }
Ejercicios Ejercicios Backtracking Backtracking y Archivos 1.- Tom y Jerry Como es usual, el gato Tom persigue a Jerry por las habitaciones de una casa sin ningún éxito, pues el maldito roedor conoce todos los recovecos de la mansión. Harto de esta situación, Tom adquiere un PC con la intención de construir un programa capaz de encontrar el camino más corto hasta su ansiada presa sorteando todos los obstáculos (paredes, armarios, etc.) que pueda encontrarse. Además, para asegurar el éxito de la cacería, Tom desea atacar a Jerry cuando éste duerma. Representaremos la casa por una superficie rectangular de M filas y N columnas, dividida en casillas unitarias:
Tom tan solo puede moverse en horizontal o vertical dentro de la habitación, nunca en diagonal. Supondremos que tanto Tom como Jerry ocupan una casilla dentro de esta superficie. Los obstáculos obstáculos de la habitación habitación serán rectángulo rectánguloss de coordenadas coordenadas válidas válidas dentro dentro de la superficie superficie,, y se representarán con su vértice superior izquierdo y el inferior derecho. Existe la posibilidad que el rectángulo sea en realidad una recta (horizontal o vertical; por ejemplo, las coordenadas (3, 4) y (3, 6) definen una recta horizontal) o incluso un punto (cuando las dos coordenadas son iguales).
Apartado 1 Construir un programa que procese un fichero de entrada, de nombre "TOM1.DAT", que contenga la configuración inicial de la casa, y que la dibuje si es correcta. Los casos de error que consideramos serán: (E0) M o N (o ambas) son igual a 0. (E1) Tom o Jerry no se encuentran en coordenadas válidas de la superficie de la casa. (E2) Tom y Jerry están en la misma casilla. (E3) Algún obstáculo no está situado en coordenadas válidas de la superficie. (E4) Los vértices que representan un obstáculo no cumplen una relación válida entre sí. (E5) Dos o más obstáculos se solapan. (E6) Tom o Jerry están en una casilla ocupada por un obstáculo. El formato del fichero "TOM1.DAT" es el siguiente:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
90
Línea 1: valores de M y de N, separados por un único espacio en blanco (tanto M como N se representan con un único dígito) Línea 2: cuatro valores naturales, separados por un único espacio en blanco, representados cada uno de ellos por un dígito. Los dos primeros valores representan la posición inicial de Tom (fila - columna) y los dos siguientes la de Jerry. Líneas siguientes: cada línea se corresponde a un obstáculo y contiene cuatro valores naturales, separados por un único espacio en blanco, y representados cada uno de ellos por un dígito. Los dos primeros valores representan el vértice superior izquierdo del obstáculo (fila - columna) y los dos restantes el vértice inferior derecho. La salida debe almacenarse en el fichero "TOM1.RES". En caso de encontrarse algún error, el fichero contendrá una única línea con el mensaje "ERROR Ex", siendo la 'x' un número entre 0 y 6 que identifica el tipo del primer error que se encuentre en la entrada. Si hubiese más de un error a la vez, se devolverá aquel con código menor; por ejemplo, si el primer error lo provoca un obstáculo que se solapa con alguno de los anteriores y al mismo tiempo ocupa la casilla de Tom o de Jerry, el código a devolver sería E5. En caso de no encontrarse ningún error, el fichero contendrá M líneas de N caracteres cada una de ellas, siendo cada carácter el contenido de una casilla, que será 'o' para las casillas vacías, 'x' para las casillas que forman parte de un obstáculo, 'T' para la casilla ocupada por Tom y 'J' para la casilla ocupada por Jerry. A continuación, ofrecemos algunos ejemplos de entrada errónea y el mensaje que debe guardarse en el fichero fichero de salida: salida: TOM1.DAT
TOM1.DAT
TOM1.DAT
33 2233 1221
33 2232 1223
TOM1.RES
TOM1.RES
33 3223 1122 1223 TOM1.RES
ERROR E4
ERROR E6
ERROR E5
En cambio, las entradas siguientes generan resultados correctos: TOM1.DAT
TOM1.DAT
55 1153 2133 1444
TOM1.RES
75 1271 2122 2424 4245 6162 6464 TOM1.RES
Tooxo xxxxo xxxxo oooxo
oTooo xxoxo ooooo oxxxx
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
91
ooJoo
oo o o o xxoxo Joooo
Apartado 2 Construir un programa que, para una entrada que no contenga ningún error, devuelva un camino lo más corto posible que lleve de Tom a Jerry. El programa leerá la información del fichero "TOM2.DAT", con el mismo formato que el fichero "TOM1.DAT" del apartado anterior. La salida se almacenará almacenará en el fichero fichero "TOM2.RES", "TOM2.RES", que contendrá contendrá diferentes diferentes líneas con el resultaresultado del algoritmo. En concreto, el fichero contendrá una línea para cada posición que forme parte del camino en el mismo orden en que aparecen en él, siendo pues la primera la posición de Tom y la última la posición de Jerry. Concretamente, cada línea contendrá un par de valores naturales, representados mediante un dígito y separados por un único espacio en blanco; el primer natural representa la fila y el segundo la columna. En caso de que no haya ninguna solución posible, el fichero "TOM2.RES" deberá contener una única línea con la palabra "INALCANZABLE". En caso de que haya más de un camino mínimo, podéis devolver cualquiera de ellos. Así para las entradas del último ejemplo del apartado anterior, para el primero de ellos el fichero "TOM2.RES" debería contener una única línea con la palabra "INALCANZABLE". En cambio, para el segundo, al existir un único camino mínimo, el resultado sería el fichero "TOM2.RES" siguiente: TOM2.RES 12 13 23 33 32 31 41 51 52 53 63 73 72 71
Apartado 3 Construir un programa que, para una entrada que no contenga ningún error, devuelva todos los caminos que lleven de Tom a Jerry, sean lo largos que sean, y tales que no se pasa más de una vez por una misma casilla. Para minimizar el tamaño de la salida, nos limitaremos a decir cuántos caminos hay de cada longitud. La longitud de un camino se define como el número de
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
92
posiciones que lo componen menos uno; en el último ejemplo del apartado anterior, el camino que aparece tiene longitud 13. El programa leerá la información del fichero "TOM3.DAT", con el mismo formato que el fichero "TOM2.DAT" del apartado anterior. La salida se almacenará en el fichero "TOM3.RES", que contendrá diferentes líneas. Cada una de las líneas estará formada por dos valores naturales, representados mediante tantos dígitos como sea necesario y separados por un único espacio en blanco; el primer natural representa la longitud y el segundo el número de caminos existentes de esa longitud. No se debe incluir líneas para aquellas longitudes que no sean longitudes de algún camino de Tom a Jerry. Jerry. Las líneas deben estar ordenadas ordenadas por la longitud. La figura siguiente muestra un ejemplo de entrada y el resultado esperado para ella: TOM3.DAT
TOM3.RES
44 1144 3233 2323
62 82
2.- Buque
La línea marítima "Titanic S.A.", cuya flota consta de un único buque, se ocupa del transporte de mercancías desde el puerto nuevo de Villabajo de Arriba allende los mares. Cada uno de los productos tiene un volumen (por motivos de conservación, las mercancías van siempre embaladas en cajas) y un precio de venta. Ante la convocatoria inminente de una huelga de estibadores, la línea decide efectuar un viaje extraordinario llenando el buque de manera que la mercancía que transporte sea lo más valiosa posible. Se pide construir un programa que, dada la información de las mercancías (volumen, precio y unidades disponibles), determine cuáles deben transportarse en el buque sin desbordar su capacidad (que será una información adicional sumistrada al programa). En caso que existan diversas combinaciones óptimas de mercancía con respecto al precio, se elegira aquélla que ocupe menos volumen; en este caso, sí puede suponerse que existe una única solución óptima al problema. Entrada Residente en el fichero de caracteres "BUQU.DAT": Línea 1: número N de tipos de mercancías, mediante uno o dos caracteres que representan un número entero entre 1 y 99. Línea 2: capacidad del buque, mediante uno, dos, tres o cuatro caracteres que representan un número entero entre 1 y 9999. Líneas de la 3 a la N+2: cada una de las líneas tiene el formato: mercancía volumen coste unidades donde mercancía es una palabra formada exclusivamente por letras minúsculas (y sin signos de puntuación, es decir, ni acentos ni similares) de a lo sumo 20 letras, y los otros tres componentes nentes son enteros enteros representados representados mediante un número de dígitos que oscila oscila entre 1 y 5 (es decir, el entero más grande representable es el 99999). Los componentes de la línea están Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
93
separados por un único carácter blanco, y no existen blancos ni otro tipo de caracteres al principio o final de línea. Salida A guardar en el fichero de caracteres "BUQU.OUT": Línea 1: un par de enteros representados mediante dígitos de la manera habitual, que indican el coste total de la carga transportad transportadaa y el volumen. volumen. Ambos valores valores están separados separados por un único único carácter carácter blanco, y no existen blancos ni otro tipo de caracteres caracteres al principio o final de línea. Líneas siguientes: cada una de ellas contiene un par: mercancía unidades que dice cuantas unidades de una mercancía dada aparecen en la carga transportada. La mercancía debe haber aparecido como tal en el fichero de entrada. Las unidades se representan mediante dígitos de la manera habitual. Ambos valores están separados por un único carácter blanco, y no existen blancos ni otro tipo de caracteres al principio o final de línea. No deben aparecer mercancías con cero unidades transportadas. Las líneas deben estar ordenadas alfabéticamente según el nombre de la mercancía; no deben aparecer mercancías repetidas. Ejemplo de entrada 5 2000 patatas 350 2 7 judias 400 5 4 guisantes 1000 12 4 fresones 1100 17 3 arroz 600 8 1 Ejemplo de salida 27 1900 fresones 1 judias 2 3.- Estampillas
El servicio de correos quiere determinar la combinación óptima de valores de estampillas según ciertas características. Se sabe que la superficie estándar de las cartas permite que pueden pegarse hasta un máximo de h estampillas en el sobre. El servicio de correos está interesado en una emisión de estampillas de k valores diferentes a determinar, múltiplos de 1 $(no se admiten centavos). Dados h y k como se acaban de definir, se pide calcular el valor máximo n de pesos tal que se pueden generar todos los valores entre 1 y n pesos. Por ejemplo, si h = 3 (caben un máximo de 3 pesos en los sobres) y k = 2 (el servicio de correos contempla hasta 2 valores diferentes), el valor n es igual a 7, siendo los dos valores 1 y 3 pesos: 1 $ = 1 estampilla de 1 $ 2 $ = 2 estampillas de 1 $ Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
94
3 $ = 1 estampilla de 3 $ 4 $ = 1 estampilla de 3 $ + 1 estampilla de 1 $ 5 $ = 1 estampilla de 3 $ + 2 estampillas de 1 $ 6 $ = 2 estampillas de 3 $ 7 $ = 2 estampillas de 3 $ + 1 estampilla de 1 $ 8 $ = IMPOSIBLE Entrada Residente en el fichero de caracteres "ESTAM.DAT": varias líneas conteniendo cada una dos valores para h y k. Podéis suponer que los valores de h y k se pueden representar con una única cifra (carácter entre '1' y '9'). Las cifras se separan con un único blanco. No hay ningún otro tipo de caracteres ni al inicio ni al final de la línea. Salida A guardar en el fichero de caracteres "ESTAM.OUT": para cada línea de la entrada, una línea conteniendo: primero, el valor n, y segundo, los valores usados para generar este n, en orden creciente de valor. Estos datos se separan por un único blanco; no hay ningún otro tipo de caracteres ni al inicio ni al final de la línea. Ejemplo de entrada 32 21 Ejemplo de salida 713 21
4. El
salto del caballo
Se dispone de una superficie rectangular "cuadriculada", es decir, formada por un entramado de posiciones o casillas (como ocurre, por ejemplo, con un tablero de ajedrez). Nos interesa buscar buscar caminos caminos dentro de esta superficie superficie que cumplan ciertas condiciones, condiciones, teniendo teniendo en cuenta cuenta que algunas de las casillas no pueden formar parte de dichos caminos (para entendernos, representan obstáculos en la superficie). Objetivo Dada una superficie rectangular de dimensión n x m, realizar un programa que la recorra partiendo de una casilla inicial y llegando a una casilla final según las reglas siguientes:
Todas las casillas casillas deberán ser visitadas visitadas excepto las casillas casillas marcadas marcadas como no visitables. No se podrá visita visitarr más de una una vez cada cada casilla. casilla. El salto de una casilla a otra deberá realizars realizarsee siguiendo las reglas reglas de movimiento del caballo de ajedrez. Esto es, desde una casilla sólo se podrá avanzar a aquellas resultantes de avanzar una posición en línea recta y otra en diagonal en la misma dirección. El siguiente esquema muestra las casillas accesibles (con una cruz) desde la casilla A: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
95
El programa deberá calcular la secuencia de casillas visitadas desde la inicial hasta la final. En caso que no exista ninguna solución, el programa debe detectar esta situación e informar. Entrada La entrada del programa consiste en una secuencia de líneas, que residen en un archivo de texto (ASCII) con nombre CAB.DAT, que tendrá el siguiente formato:
La primera línea línea contiene contiene la dimensión de la superficie, superficie, es decir, el número número n de columnas y el número m de filas. La segunda línea línea contiene contiene la posición inicial inicial y la posición posición final, cada posición posición siendo siendo dos enteros, enteros, la columna columna y la fila respectivame respectivamente. nte. Podéis suponer que las dos posiciones posiciones están dentro de los límites de la superficie. superficie. A continuación, m líneas líneas más. Cada línea representa una fila de la superficie, y contiene n caracteres, uno por columna. Cada uno de estos caracteres puede ser 'V' o 'N', dependiendo de si la posición correspondiente es visitable o no. Los caracteres aparecen separados por un único carácter "espacio".
A efectos de numeración, debe considerarse que q ue las filas van de d e 1 a m y las columnas de 1 a n. Salida La salida del programa ha de grabarse en un archivo de texto (ASCII) con nombre CAB.RES, que contendrá una línea por cada posición que forme parte del camino encontrado como solución que cumpla las condiciones dadas en el enunciado. Cada posición es un par de enteros: la columna y la fila. La primera posición de la solución será la posición inicial, y la última la posición final. Si no hay ninguna solución, el fichero CAB.RES contendrá una única línea con el texto INSATISFACTIBLE. Si existe más de una solución, cualquiera de ellas se considera válida. Ejemplo de entrada 54 11 14 V V V N N V N V V V V V V N V V V V V V Ejemplo de salida 11 23 44 52 Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
96
31 12 24 32 53 34 13 21 42 54 33 14
5.- ANAGRAMAS Dado un conjunto de letras, escribe un programa que genere todas las palabras posibles. Ejemp Ejemplo: lo: De la palab palabra ra 'abc' 'abc' el progr programa ama debe debe produ produci cir, r, explor exploran ando do todas todas las las posib posible less combinaciones de letras, las siguientes palabras: 'abc', 'acb', 'bac', 'bca', 'cab' y 'cba'. En la palabra obtenida del archivo de entrada, algunas letras pueden aparecer más de una vez. Para una palabra dada, el programa no debe producir la misma palabra más de una vez y las palabras deben aparecer ordenadas alfabéticamente. Los datos de entrada están en el archivo de texto ANAGRA.IN que está formado por diversas palabras. La primera línea contiene el número de palabras que siguen. Cada línea contiene una palabr palabra. a. Una palabra palabra está compue compuesta sta por letras letras de 'a' a 'z', del alfa alfabeto beto sajón, sajón, mayúsmayúscula culass y minús minúscu cula las. s. Las Las letra letrass mayú mayúsc scul ulas as y minú minúsc scula ulass deben deben cons conside idera rarse rse difere diferent ntes es.. Los datos de salida estarán en el fichero de texto ANAGRA.OUT, para cada palabra del archi-
vo de entrada, el archivo de salida debe contener todas las diferentes palabras que pueden ser generadas con las letras de la palabra. Las palabras generadas desde una palabra deben mostrarse en orden alfabético. alfabético. Ejemplo:
ANAGRAMA.IN ANAGRA.OUT 2 abc Abc acb acba bac bca cab cba aabc aacb abac abca acab acba baac Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
97
baca bcaa caab caba cbaa 6.-EL JUEGO DE LA VIDA Consideremos una población de K insectos en una tabla (M x N), de modo que en cada celda de la tabla hay, como máximo, un insecto. Por lo tanto, cada insecto tiene, como máximo, 8 vecinos. La población se está desarrollando continuamente debido a los nacimientos y defunciones que se producen. Las reglas de evolución que se observan son las siguientes: 1
Aquello Aqu elloss inse insecctos tos que que tien tienen en 0, 1, 4, 5, 6, 7 u 8 vec vecinos inos mue mueren ren irre irreme medi diaablemente. 2 Los inse insecto ctoss que tienen tienen 2 o 3 vecin vecinos os sobre sobreviv viven. en. 3 En cada celda celda vacía en cuya cuya vecindad vecindad hay exacta exactamen mente te tres insecto insectos, s, nace un nuevo nuevo insecto. 4 Los Los inse insect ctos os que que nace nacenn o muer mueren en no afec afecta tann las las regl reglas as hast hastaa que que se ha comp comple le-tado un ciclo evolutivo, entendiendo por éste un ciclo en el que se ha decidido la supervivencia o muerte de los insectos (vivos al comenzar el ciclo) de acuerdo a las reglas mencionadas. Escribe un programa que simule la evolución de la población y que determine cómo estará la población población después de L ciclos evolutivos. evolutivos. Los datos de entrada están en el archivo de texto VIDA.IN, en la primera línea hay 3 enteros teros separad separados os por un espac espacio io en blan blanco co N, M y L que que repre represe sent ntan an al númer númeroo de filas filas,, de column columnas as y de ciclos, ciclos, respec respectiv tivamen amente. te. Las siguien siguientes tes N línea líneass conti contiene enenn la la ubic ubicaci ación ón de los insectos representados por un asterisco '*' y por un punto '.' las celdas vacías. Los datos de salida estarán en el fichero de texto VIDA.OUT, en el que habrá N líneas con la ubicación de los insectos tras L ciclos. En cada línea un '.' representa a una celda vacía y un '*' a un insecto. Ejemplo: VIDA.IN VIDA.IN VIDA.OU VIDA.OUT T
66 1 ...... ...**. ..**.. ...*.. ...... ......
...... ..***. ..*... ..**.. ...... ......
7.- BIBLIOTECA INFANTIL
En una biblioteca infantil se ha diseñado un sistema para determinar cada día en qué orden elegirá elegiránn los niños niños el libro libro que desean desean leer. Para ello los biblioteca bibliotecarios rios han decidid decididoo seguir seguir la siguiente estrategia: cada día se formará un círculo con todos los chicos. Uno de los chicos es elegido al azar como el número 1 y el resto son numerados en orden creciente hasta N siguiendo el sentido de las agujas del reloj. Comenza Comenzando ndo desde 1 y movién moviéndose dose en sentido sentido horario horario uno de los bibliotec bibliotecari arios os cuenta cuenta k chichicos cos mien mientr tras as el otro otro bibl biblio iote teca cari rioo comi comien enza za en N y se muev muevee en sent sentid idoo anti antiho hora rari rioo contando m chicos. Los dos chicos en los que se paren los bibliotecarios son elegidos; si los dos bibliotecarios coinciden en el mismo niño, ese será el único elegido. Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
98
Cada uno de los bibliotecarios comienza a contar de nuevo en el siguiente chicos que permanezca en el círculo y el proceso continúa hasta que no queda nadie. Tener en cuenta que los dos chicos abandonan simultáneamente el círculo, luego es posible que uno de los bibliotecarios cuente un chico ya seleccionado por el otro. Se pide la construcción de un programa que, dado el número N de chicos y los números k y m que utilizará cada bibliotecario en la selección, indique en qué orden irán siendo seleccionados los chicos. Forma Formato to de la entra entrada da (residente en el fichero de caracteres "BIBLIO.IN"): En cada línea aparecerán tres números (N, k y m, los tres mayores que 0 y menores que 20) separados por un único espacio en blanco y sin blancos ni al comienzo ni al final de la línea. La última línea del fichero fichero contendrá siempre tres ceros. Forma Formato to de la salida salida (a guardar en el fichero de caracteres " BIBLIO.OUT"): Para cada línea de datos del fichero de entrada (excepto, claro está, la última que contiene tres ceros), se generará una línea de números que especifique el orden en que serían seleccionados los chicos para esos valores de N, k y m. Cada número de la línea ocupará tres caracteres en el fiche fichero ro (no (no llev llevará aránn ceros ceros a la izqu izquie ierda rda y será seránn comp comple leta tados dos con blanc blancos os por ese lado lado hasta alcanzar ese tamaño). Cuando dos niños son seleccionados simultáneamente, en el fichero aparecerá primero el elegido por el bibliotecario que cuenta en sentido horario. Los grupos de elegidos (de uno o dos niños cada uno) vendrán separados entre sí por comas (no debe ponerse una coma después del último grupo). La salida correspondiente a la entrada dada como ejemplo tendría que ser exactamente la siguiente; para ver con claridad cuántos blancos deben aparecer, representamos cada carácter blanco con un carácter '*' (en el fichero fichero generado, pues, no aparecen aparecen asteriscos sino espacios espacios en blanco). blanco). Ejemplo: BIBLIO.I BIBLIO.IN N
BIBLIO.O BIBLIO.OUT UT
10 4 3 52 8 13 2 2 00 0
**4**8,**9**5,**3**1,**2**6,*10,**7 **2**3,**5,**4**1 **2*12,**4*10,**6**8,**9**5,*13**1,**7,**3*11
8.- VA DE UNOS Dado cualquier número entero N del rango [1..10000] no divisible por 2 o 5, algún múltiplo de N es un número número que en notación notación decimal decimal es una secuencia secuencia de unos. Hay que encontrar encontrar el número de dígitos que tiene el menor múltiplo de N que está formado solo por unos. Por ejemplo, si N es 3, el menor múltiplo de 3 que está formado solo por unos es 111. Por lo tanto la solución sería 3. Los datos de entrada están en el fichero UNOS.IN, en el que hay una sola línea que contiene un número entero positivo del rango antes mencionado. Los datos de salida estarán estarán en el fichero UNOS.OUT UNOS.OUT que contendrá contendrá una sola línea que contencontendrá el número de unos que tiene el menor múltiplo de N que está formado solo por unos. Ejemplo: UNOS.I UNOS.IN N UNOS.O UNOS.OUT UT 7 6 9.- NOTACIÓN POLACA INVERSA Dada una expresión expresión aritmética aritmética tal como la (a+b)*(c+d) (a+b)*(c+d) se puede representar representar con la notación notación polaca inversa inversa de forma que cada operador operador va después de sus dos operandos de la forma: ab+cd+* Se trata de calcular una expresión dada en notación polaca inversa. Datos de entrada: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
99
El programa debe leer los datos de entrada del archivo NOPOIN.IN. En la primera línea figura la expresión a evaluar. evaluar. Ésta está formada formada por enteros enteros del rango [–32000..3 [–32000..32000 2000]] y por los operadores +, -, * y /. Un espacio en blanco separa a cada operando y a cada operador. La expresión es sintácticamente correcta. Datos de salida: El archivo de salida NOPOIN.OUT consistirá de una sola línea donde aparece el entero que es el valor de la expresión expresión evaluada. evaluada. EJEMPLO: NOPOIN NOPOIN.I .IN N NOPOIN NOPOIN.O .OUT UT 10 8 + 4 2 - * 36 10.- Años Santos En el año 1179 el Papa Alejandro III, a través de la bula “Regis Aeterni”, confirma la gracia del privilegio jubilar, concedida a Compostela por el Papa Calixto II a petición del arzobispo Diego Xelmírez, y establece oficialmente que serán años santos compostelanos todos aquellos en que la conmemoración del martirio de Santiago (el día 25 de julio) coincida en domingo. Desde entonces, ha habido además dos años santos extraordinarios: el 1885 (concedido por el papa León XIII mediante la bula “Deus Omnipotens”) para celebrar el redescubrimiento de los restos del apóstol, y el 1938 para que “pudieran asistir a ganar el jubileo los contendientes de la guerra civil que no hubiesen podido ir el año anterior”. Debe tenerse en cuenta que el actual calendario “gregoriano” fue establecido por el Papa Gregorio XIII en el año 1582 (mediante (mediante la bula “Inter gravissimus”) gravissimus”) para mejorar la preciprecisión del calendario “juliano” vigente en aquel momento. Para ello se corrigió la “regla de los bisiestos” (que indicaba que todos los años múltiplos de 4 tenían un día extra después del 28 de febrero), estableciendo que los múltiplos de 100 que no lo fuesen de 400 no serían, a partir de ese momento, bisiestos. Paracorregir la desviación que había provocado hasta entonces la imprecisión del calendario juliano, ese año se suprimieron los 10 días que van del 5 al 14 de octubre, de modo que al jueves 4 de octubre le siguió el viernes 15. Objetivo Se trata de calcular cuantos años santos hay entre dos años dados (ambos incluidos). Entrada En un archivo de texto con nombre "SANT.IN" se pasarán al programa una lista de pares de años (un par por línea), todos ellos posteriores al año 1179 y anteriores al año 100000. Los dos años de cada par aparecerán separados unicamente por espacios en blanco (uno o más). No habrá otros caracteres caracteres ni al principio ni al final de las líneas. líneas. Salida El programa deberá escribir, en un archivo de texto con nombre "SANT.OUT", una línea por cada línea del archivo de entrada, indicando para cada intervalo, el número de años santos que le corresponde. Ejemplo
SANT.IN .IN 1998 998 200 2000 1998 1998 2004 2004 1999 1999 2005 2005
SANT. NT.OUT OUT 1 2 2
11.- EL RECTÁNGULO DE KUBRIK El rectángulo de Kubrik es una adaptación a dos dimensiones del clásico cubo de Rubik. Se dispone de un rectángulo de 8 casillas, distribuidas en dos filas y cuatro columnas, coloreadas con 8 colores diferentes, que aquí representamos con un número del 1 al 8. Inicialmente, la disposición de los colores en las casillas es la siguiente: Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 00
1234 8765 Se pide, a partir de esta disposición inicial, alcanzar una disposición objetivo caracterizada por una configuración diferente del rectángulo. Un ejemplo podría ser la configuración final: 5183 4762 Para ello deberán aplicarse sobre la disposición inicial una serie de transformaciones hasta alcanzar la disposición objetivo. Existen tres tipos de transformaciones, identificadas por las letras A, B y C. A: intercambia la fila superior y la fila inferior. El efecto se visualiza en la figura siguiente: de la configuración de la izquierda se pasa a la de la derecha: 1234 8765 8765 1234 B: desplazamiento circular derecho del rectángulo: 1234 8765 4123 5876 C: rotación en sentido horario de los cuatro cuadrados del centro: 1234 8765 1724 8635 Concretamente, el programa pide una secuencia mínima de transformaciones que lleve de la configuración inicial a la configuración destino. En caso de haber más de una secuencia mínima, se puede devolver cualquiera de ellas. Formato de la entrada (residente en el fichero de caracteres "KUBRIK.IN"): una línea con ocho caracteres entre '1' y '8', sin repetición y separados exactamente por un blanco (no hay ningún otro tipo de caracteres ni al inicio ni al final de la línea), que representan la configuración final, numeradas numeradas a partir del vértice superior superior izquierdo en el sentido del movimiento movimiento de las agujas del reloj. Formato de la salida (a guardar en el fichero de caracteres "KUBRIK.OUT"): una línea inicial diciendo la longitud de la secuencia mínima y, a continuación, tantas líneas como transformaciones aplicadas, en el orden de aplicación. No debe aparecer ningún otro tipo de información en la línea. Podéis trabajar con la seguridad de que existe una secuencia de movimientos que llevan de la configuración inicial a la configuración final. Ejemplo:
KUBRIK.I K.IN Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
KUB KUBRIK.OUT 1 01
51832674 4 C A B C
Laberinto ajedrecístico Descripción del problema Se tiene un laberinto muy particular que se desarrolla sobre un tablero cuadrado con lados de tamaño N. En cada avance se puede mover como caballo, alfil o torre, con la única restricción de no hacer hacer más que dos movimien movimientos tos de la misma misma especie especie en forma conse consecu cutiv tiva. a. Así por ejemplo, ejemplo, sería ilícito mover como torre, caballo, caballo, caballo, caballo, caballo, alfil. Pero sí sería lícito: torre, caballo, caballo, caballo, caballo, alfil, caballo. caballo. El tablero tablero tiene obstáculos, obstáculos, que limitan limitan los movimientos movimientos máximos cuando cuando se mueve como torre o alfil. Un movimiento movimiento como caballo caballo sólo tiene la restricción restricción de no posarse sobre un obstáculo. Como muchos obstáculos están contiguos y alineados con otros, ya sea horizontal, horizontal, vertical o diagonalmen diagonalmente, te, se los ha descripto descripto dando las ubicacione ubicacioness de los extremos de tales alineaciones. Una secuencia “i, j, i, k” describe una alineación horizontal; “j, i, k, i ” una vertical; y cuando el valor absoluto en la diferencia de las coordenadas extremas es el mismo, la alineación alineación es diagonal. diagonal. Dos alineaciones de obstáculos pueden tener puntos en común. Se cuentan puntos en contra por cada jugada, uno por movimiento al modo de caballo, dos por movimiento al modo de alfil y tres por movimiento al modo de torre. El objetivo es partir del casillero [1, 1] y llegar al [N, N] acumulando acumulando la menor cantidad cantidad de puntos en contra. contra. Los casilleros de salida y llegada nunca tienen obstáculo y se sabe que el laberinto tiene solución. La figura siguiente ilustra dos posibles soluciones para el caso del ejemplo.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 02
Se te pide que escribas un programa ajedrez.cpp, que informe la cantidad de jugadas de una solución óptima del laberinto, y los puntos en contra obtenidos. Datos de entrada Se recibe un archivo ajedrez.in del directorio actual, que contiene: • Primera línea: El tamaño N del tablero ( 3 ≤ N ≤ 1.000 ), la cantidad cantidad c de alineaciones de obstáculos ( 1 ≤ c ≤ 2.000 ), separados por un espacio.
• Un conjunto de c líneas, cada una conteniendo 4 números separados por blanco, correspondientes a una alineación de obstáculos. Datos de salida El programa debe generar el archivo ajedrez.out, en el directorio actual con: • Una línea, conteniendo la cantidad de jugadas de una solución del problema y la penalización obtenida, separadas por blanco.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 03
Luchadores Japoneses
Descripción del problema Una academia dedicada a las difíciles artes de lucha oriental, está organizando un torneo de luchadores luchadores sumo. A los efectos efectos de conformar la grilla de combates, es necesario necesario armar parejas parejas de luchadores que puedan ofrecer un espectáculo atractivo. Como es sabido que los cultores de esta disciplina son hombres de estructura física imponente, los organizadores habitualmente arman duplas de combatientes estableciendo comparaciones relativas a sus alturas y pesos. Por experiencia, los organizadores saben que un combatiente ‘domina’ a otro si lo supera en ambas medidas, o bien si lo iguala en peso y lo supera en altura, o viceversa. En cualquier otro caso, los luchadores no son comparables lo que hace el resultado imprevisible y por lo tanto más atractivo para el público. Sabiendo que no hay luchadores que coinciden en ambas medidas, los organiz organizador adores es quieren quieren saber saber a cuanto cuantoss posible posibless contri contrinca ncante ntess domina domina cada uno uno de ellos, ellos, y por esta esta razón se te pide que escribas escribas un program programaa sumo.c sumo.cpp, pp, que efectú efectúee este recuento. Datos de entrada Se recibe recibe un archivo archivo sumo.in sumo.in con el siguiente siguiente formato: formato: • Una línea que indica indica la cantidad L (1 (1 ≤ L ≤ 100.000) 100.000) de luchadores. luchadores. • L líneas con 2 números números P y H (0 ≤ P,H ≤ 1.000.000) 1.000.000) que indican el peso y la altura de cada
participante, separados por blancos. Datos de salida Se debe generar un archivo archivo sumo.out sumo.out conteniendo conteniendo • L líneas con la cantidad cantidad de luchadores luchadores a quienes domina domina cada participante, participante, en el mismo orden en el que los participantes entraron.
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 04
Desinfectando los archivos Descripción del problema Los archivos de texto de una computadora han sido afectados por un nuevo virus. Este virus daña los archivos de texto de la siguiente manera: elige dos caracteres cualesquiera, luego recorre el texto y cada vez que encuentra dos ocurrencias consecutivas del primer carácter le intercala el segundo carácter. Por ejemplo si el texto original fuera fuera aadabeaa aadabeaa y el virus elige como primer carácter carácter a y como segundo segundo caráct carácter er b, el texto texto infectad infectadoo será abadabe abadabeaba aba.. Si el archivo archivo de texto original original no conten contenía ía la secuen secuencia cia aba entonc entonces es el archiv archivoo se puede desin desinfec fectar tar realiza realizando ndo el proces procesoo inverso. A estos archivos los denominaremos desinfectables. Con el objeto de ayudar a desinfectar los archivos de texto de la computadora se te pide que escriba escribass un program programaa antivirus antivirus.cp .cpp, p, que conoci conociend endoo el texto infecta infectado do y los dos carac caracter teres es elegidos por el virus, realice el proceso de desinfección del mismo. Tu programa sólo recibirá archivos que sean desinfectables. Datos de entrada Se recibe un archivo archivo antivirus.in antivirus.in con con dos líneas:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 05
• La primera línea línea contiene contiene la cantidad de caracteres caracteres del texto infectado, infectado, seguido seguido de los dos caracteres elegidos por el virus, separados por un espacio. • La segunda segunda línea contiene contiene el texto infect infectado. ado. Datos de salida Se debe generar un archivo antivirus.out conteniendo dos líneas: • La primera línea contiene contiene la cantidad cantidad de caractere caracteress del texto desinfectad desinfectado. o. • La segunda segunda línea contiene contiene el texto desinfectado. desinfectado. Restricciones • Tanto Tanto los caracter caracteres es que elige el virus virus como los carac caracter teres es del texto pueden pueden ser cualqui cualquier er letra del del alfabeto, alfabeto, excepto excepto la ñ, en minúscula minúsculass y sin acentos. acentos. • La longitud longitud máxima máxima del del texto a desinfec desinfectar tar es de 255 255 caracter caracteres. es.
Hilera de ladrillos Descripción del problema Recientes hallazgos en ruinas del lejano oriente aportan datos sobre las formas que los esclavos tenían para distraerse durante las arduas jornadas en que se construyó la célebre muralla china. En un viejísimo manual de juego se detallan las siguientes reglas: se construye una hilera de ladrillos y se les asigna a cada uno un número. Pero esto siempre respetando la regla del juego, que indica que un ladrillo tiene que tener un número equivalente a la suma de sus dos ladrillos predecesores en la hilera, si los hubiera. Algunos ladrillos tienen número asignado y otros están vacíos. La idea es que se deben completar con números todos los ladrillos vacíos cumpliendo la regla anteriormente mencionada. Para completar las investiga investigacione ciones, s, los excavador excavadores es nos han pedido escribir escribir un programa ladrillos.cpp llos.cpp que encuentre encuentre a partir de una cantidad cantidad de ladrillos y algunos algunos casilleros casilleros una forma de completar todos los números faltantes en los ladrillos de las hileras. Datos de entrada Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 06
Los ladrillos vacíos los representaremos con un * (asterisco) y los números explícitos o desconocidos de cada ladrillo serán enteros de -1.000.000.000 a +1.000.000.000. Se recibe un archivo ladrillos.in ladrillos.in del directorio directorio actual, que contiene contiene la descripción descripción de una hilera de ladrillos. La misma se describe por una primera línea que contiene contiene un entero M, M, 1 ≤ M ≤
45, que representa la cantidad de ladrillos que componen la hilera. A continuación, en una segunda línea el archivo contiene M datos, separados por blancos, detallando en cada posición los números conocidos o espacios vacíos a completar mediante asteriscos. Datos de salida El programa debe generar el archivo ladrillos.out, en el directorio actual con la hilera de ladrillos completa (con todos sus casilleros definidos, con el formato de la entrada). Los casos con los que será probado el programa tienen solución con números enteros. Si hubiera más de una solución cualquiera vale.
A correr c orrer que es muy saludable … !!! Descripción del problema Una entidad deportiva ha organizado una carrera multitudinaria en el marco de los festejos por el Bicentenario Bicentenario.. Los organizadores organizadores piensan piensan clasificar clasificar a los competidores competidores según su categoría categoría y sexo: Las categorías se asignan según rangos de edades y su cantidad puede variar de una competencia a otra, a criterio de quienes la organizan. Los sexos son naturalmente dos: masculino y femenino. Al inscribirse los corredores informan su edad y reciben un número que deben llevar abrochado abrochado en la remera. Los números de corredor corredor se asignan asignan correlativam correlativamente ente.. A medida medida que los competid competidore oress van arriba arribando ndo uno detrás detrás de otro otro a la meta, meta, los fiscal fiscales es de la compet competenc encia ia registran registran el númer númeroo del corredor corredor.. Se te pide pide que escriba escribass un programa programa carrecarrera.cpp que determine los ganadores de oro, plata y bronce para cada categoría y sexo, para establecer los integrantes de los podios. Datos de entrada Se recibe un archivo carrera.in con el siguiente formato:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 07
• Una línea que indica: la cantidad A ( 1 ≤ A ≤ 1.000.000 ) de competidores inscriptos, cf y cm ( 1 ≤ cf, cm ≤ 60 ) la cantidad de categorías por sexo respectivamente, y L ( 0 ≤ L ≤ Α ) la cantidad de corredores que arribaron a la meta, todos separados por blanco. • cf líneas con los rangos Fn, Fx de edades de cada categoría femenina femenina (10 ≤ Fn ≤ Fx ≤ 80) y cm líneas con con los rangos rangos de edades de cada categoría categoría masculina Mn, Mx (10 ≤ Mn ≤ Mx Mx ≤
80). Las categorías se dan en orden creciente; los rangos obviamente son disjuntos y sus cotas están separadas por blanco. • A líneas con los pares pares E, X correspondientes a la edad ( 10 ≤ E ≤ 80 ) y sexo (M / F) de
los corredores inscriptos, en orden de inscripción (números correlativos, comenzando desde 1), separados por blanco. • L líneas líneas con los números números de los corredores corredores arribados arribados a la meta, meta, por orden de llegada. llegada. Datos de salida Se debe generar un archivo carrera.out conteniendo • cf+cm cf+cm líneas, contenien conteniendo do cada una el número de categoría categoría y los 3 números de los corredores que merecieron merecieron oro, plata y bronce, separados separados por blanco. blanco. Se deben listar listar ordenados por número número de categoría, categoría, primero las cf correspondie correspondientes ntes a las damas y luego las cm de los caballeros. Si en alguna categoría llegaron menos de 3 participantes, los premios correspondientes se declaran desiertos y se debe colocar un 0(cero) como número de corredor.
Contenidos Asignatura:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 08
EJES Nº1
PER ODO
CONTENIDOS
1
Introducción a la Programación Nº2
3
Estructuras de Datos
Ciclos Repetitivos
Nº3
5
Funciones y procedimientos
Nº4
5
Tratamiento de cadenas de caracteres
Nº5
7
Conceptos iniciales Elementos técnicos básicos Lectura por teclado Tipos de soluciones. Abstracciones Abstracciones y modelos. Algoritmos. goritmos. Lógica. Resolución Resolución algorítmica algorítmica.. Estructura de un un programa. Sintaxis y reglas sintácticas. Tipos de datos estánda estándarr en C++. C++. Constantes y variables. Asignación y reglas reglas de asignación. Operadores aritméticos aritméticos y de relación. relación. Entrada y salida de datos. datos. Condicionales simples y múltiples. Control de ciclos condicionales. (while, do while) Control de ciclo exacto.(for) Declaración y utilización de funciones funciones y procediprocedimientos definidos por el usuario. Valores de retorno de una función. Argumentos de una una función. Pasaje de parámetros por valor y por referencia referencia Funciones que modifican parámetros. Copia, inserción y borrado dentro de cadenas de caracteres. Ubicación de caracteres dentro dentro de una una cadena. Tratamiento de cadenas como arreglos de caracteres individuales. Transformación de cadenas. Biblioteca stdlib.h
Estructura de datos de arreglo. arreglo. Manejo de dimensiones de un arreglo. Índices. Técnicas de ordenamiento (Selection Sort, BubbleSort, Inserción Directa, Método Shell, Heap Sort) Búsqueda secuencial y binaria. Arreglos paralelos. Matrices. Diagonal principal y secundaria Cálculo de matrices matrices y vectores Archivos Archivos en en C y CC++. ++. ABM de ficheros. Recursión, concepto. La sucesión de Fibonacci, Fibonacci, factorial de un número. Torres de Hanoi. Backtraking Introducción La vuelta del caballo El problema de las ocho reinas El problema de la mochila (selección óptima) Introducción a las variables puntero Repaso: - operador de dirección: &referencias
Arreglos uni y bidimensionales
Nº6 Archivos
3
Nº7
10
Introducción a la recursión
Nº8 Memoria dinámica - Pun-
4
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 09
teros
Nº9
6
Introducción a la programación orientada a objetos (POO). Librerías en C++ .h
Nº10
6
Constructores y destructores Puntero THIS
Declaración de variables variables de tipo puntero Inicialización de variables de tipo puntero El puntero nulo: NULL Valor apuntado por un puntero: Indirección de punteros Aritmética de punteros Relación entre Vectores y punteros Cadenas y punteros. El Operador Operador NEW NEW y DELETE Las clases Pilares de la Programación Programación Orientada a Objetos Características fundamentales de las clases en C++ Representaciones Gráficas Construcción de una clase Atributos Métodos. Implementación de los métodos métodos de una una clase Creación de objetos Paso de mensajes mensajes Librerías Organización de archivos header #ifndef NOMBRE_CLASE_H
Categorías de los métodos (inicializadores, accedentes ó selectores, mutadores o modificadores, visualizadores y operadores) Inicialización de miembros Métodos constructores Inicialización de objetos con y sin constructores Sobrecarga de funciones constructoras Argumentos implícitos en constructores El constructor por defecto Método destructor ¿Cuándo se ejecuta el destructor?
Puntero This La clase Fraccional Categorías Categorías de los objetos que aparecen en los métodos métodos El puntero this Métodos operadores
Nº11
5
Métodos operadores unarios. unarios. Clases y funciones amigas:
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
Sobrecarga de operadores Métodos de operadores unarios . Operador de incremento (prefijo). Devolución Devolución de objetos objetos en los métodos. métodos. Retorno Retorno por por referencia Clases Amigas
1 10
friend
Nº12
10
Templates
Introducción a las funciones amigas (Funciones (Funciones friend) Funciones amigas Clases amigas Ejemplo: La clase fraccional. Métodos operadores amigos Introducción (Genericidad). Template de funciones o funciones funciones genéricas. genéricas. Sintaxis de Templates. Ejemplos de declaraciones. Un ejemplo ejemplo de Template Template de funciones: funciones: Máximo Máximo de un vector. Sobrecarga de Template. Especialización de funciones funciones genéricas. Punteros a objetos Vectores dinámicos de objetos Uso de objetos dinámicos Atributos dinámicos Creación de objetos con atributos dinámicos dinámicos Destrucción de objetos con parámetros dinámicos Operador de asignación para objetos con parámetros parámetros dinámicos.
Bibliografía
R. Sedgewick. Sedgewick. Algorithms Algorithms in C, C++(Fundam C++(Fundamenta entall Algorithms, Algorithms, Data Structure Structures, s, Sorting, Sorting, Searching). Addison-Wesley,1990. Stroustrup Stroustrup - Bjarne - The C++ C++ Programming Programming Langua Language ge 3rd EditionEdition- Addison Addison Wesley Stroustrup - Programming - Principles and Practice Using C++ (Pearson, 2009). C++ - The Complete Reference (3rd Ed)Herb Schildt. Grady Booch - Object-Oriented Analysis and Design With Applications, 2nd EDITION. Algorithms and Data Structures - Niklaus Wirth 2004 http://www.cplusplus.com http://es.scribd.com/doc/1739233/Ordenamiento-en-C http://www.algoritmia.net http://c.conclase.net http://www.cppreference.com http://www.oia.org.ar http://www.oia.org.ar (Olimpiadas (Olimpiadas Argentina de Informática) http://www.cartagena99.com/recursos/recursos_programacion.php http://www.nebrija.es/~abustind/Informatica/MetodologiaI/MetodologiaI.html http://www.nebrija.es/~abustind/Informatica/MetodologiaII/MetodologiaII.html
Laboratorio de Programación EEST Nº5 – Prof Abdala Pablo
1 11