En esta asignatura soy responsable de
un grupo de teoría y de dos de prácticas.
En mi
grupo de teoría utilizo estos apuntes.
Además
he preparado una colección de problemas cuyos enunciados están
disponibles aquí. Dada la
importante cantidad de ejercicios de examen de que se dispone, se
hará un uso marginal de este documento.
Para trabajar
en casa puedes utilizar dev-cpp
como Entorno Integrado de Desarrollo. Es gratuito y ocupa menos de
20MB. He preparado unos apuntes que
explican a nivel introductorio el funcionamiento de este programa. No
imprimir este documento, se ampliará a lo largo del curso. Las
capturas de pantalla se ven mucho mejor en la versión
en html del mismo documento.
Aquí iré
publicando los ejercicios que se hagan en clase y cualquier otro
material que vaya surgiendo a lo largo del curso.
Exámenes de otros años.
Luis
Junco tiene en su página
los exámenes de otros años recopilados en varios
ficheros comprimidos.
En la misma página hay
materiales interesantes en la zona de
descargas.
2003-2004.
2004-2005.
2005-2006.
Prácticas.
Primera práctica:
Consiste en resolver dos ejercicios que formaban parte de algún examen correspondiente a cursos anteriores.
A.- El enunciado de la conjetura de Goldbach es "Todo número par mayor que 2 puede escribirse como suma de dos números primos". Considerándola cierta, escribir un programa que descomponga un número par en suma de dos números primos.
Utilizar el siguiente esquema:
Pedir el número asegurando que sea par..
Descomponer el número en suma de otros dos.
Para cada pareja de números: averiguar si los dos números son primos
Un número es primo si sólo es divisible entre 1 y el propio número, pero es más fácil escribir el código que detecta cuando un número NO es primo: cuando al menos existe un divisor.
Si los dos números son primos mostrarlos por la pantalla
NOTA: Como primera aproximacion, escribir un programa que muestre todas las posibles descomposiciones de un número en suma de otros dos, mayores que cero, completando este código:
#include<iostream>
using namespace std;
int main()
{
int n,a,b;
cin>>n;
//cuales son los limites del bucle?
for (int i=...;i...;i++)
//cuales son los numeros que suman n?
cout<<...<<'+'<<...<<endl;
}
Después escribir un programa que averigüe si un número es o no primo, completando este código:
#include<iostream>
using namespace std;
int main()
{
int n;
//cual es el valor inicial de es_primo?
bool es_primo=...;
cin>>n;
//cuales son los limites del bucle?
for (int i=...;i...;i++)
//cual es la condicion que se cumple si i es
//divisor de n?
if (...)
//si hay al menos un divisor, que valor toma es_primo?
es_primo=...;
//mostrar si es o no primo
if (...)
cout<<"Es Primo"<<endl;
else
cout<<"No es Primo"<<endl;
}
Finalmente fundir los dos programas en uno para hacer el que se pide.
B.- Escribir un programa que muestre si un número es o no narcisista. Un número es narcisista si es igual a la suma de sus dígitos elevado al número de cifras.
Ejemplo: 153=13+53+33.
Los ejemplos de referencia de la clase de teoría son sumacifras.cpp, reves.cpp, capicua.cpp.
Utilizar el siguiente esquema:
Pedir el número por el teclado.
Calcular la longitud del número (número de cifras).
Para cada cifra:
Obtener su valor:
Elevarla al número de cifras, es decir, multiplicarla por si misma tantas veces como cifras tenga el número.
Acumular el valor obtenido.
Cuando no queden más cifras, comparar el valor acumulado con el valor inicial del número
Mostrar un mensaje adecuado en función de si el número es o no narcisista.
Cuando termine este ejercicio, realizar el siguiente:
Escribir un programa en C++ que muestre los n primeros números narcisistas, n se pide por el teclado.
Ejemplo de referencia ncapicua.cpp.
Segunda práctica:
Consiste en estructurar los programas anteriores utilizando funciones.
A.- Reescribir el programa que descomponía un entero par en suma de dos primos. Utilizar una función que devuelva true si un número es primo y false en caso contrario.
B.- Reescribir el programa que analizaba si un número era o no narcisista. Utilizar las siguientes funciones:
int ncifras(int). Recibe un entero y devuelve el número de cifras del entero.
int potencia(int,int). Recibe dos enteros, devuelve el primero elevado al segundo. El segundo es positivo.
int suma_potencias(int). Recibe un entero, devuelve la suma de sus cifras elavadas al numero de cifras. Obviamente esta función llama a las otras dos.
C.- Escribir un programa que muestre los n primeros números narcisistas, n se pide por el teclado.
Tercera práctica:
Problema 2 de Septiembre de 2006.
Buscar el mayor número entero (menor que 45000 por cuestiones de rango) cuyo cuadrado se escriba con dígitos distintos. Ejemplos de cuadrados que cumplen esa condición:
13^2 = 169 286^2=81796 320432=102675384^9
Por indicación de Su Santidad :-), se incluye un esquema alternativo para la función mayor_blabla más respestuoso con la inviolabilidad del sacrosanto bucle for.
int mayor_blabla(void) {
vector<int> digitos;
//inicializar y declarar i
...;
do {
//actualizar i
...;
//calcular el cuadrado de i y pasarlo a vector
...;
//mientras existan repetidos
}while (...);
return i;
}
Cuarta práctica:
Versa sobre operaciones con matrices y vectores.
Tomando como punto de partida el ejercicio de clase matop.cpp, ampliarlo, añadiendo operaciones.
Suma de matrices, operador.
Resta de matrices, operador.
Traspuesta de una matriz, función.
Tipificar una matriz (sustituir cada elemento de una fila por la media de los elementos de esa fila), función.
Escribir un programa que utilice las operaciones anteriores para efectuar el siguiente cálculo:
tipifica(A*B+C')
En donde A, B, C son matrices de dimensiones 3x4, 4x3, 3x3, respectivamente. Comprobar el resultado utilizando Matlab o calculadora.
Si apetece, añadir las operaciones básicas con vectores.
Quinta práctica:
Trata sobre la ley Dont, el método que se utiliza para asignar escaños o concejales a las candidaturas en unas elecciones, en función de los votos recibidos. Cayó en un examen del plan antiguo.
La ley electoral utiliza el sistema
DONT para el cálculo del número de candidatos electos
de cada una de las candidaturas presentadas.
En primer lugar se
eliminan aquellas candidaturas que obtengan menos del 5% del número
total de votos.
Seguidamente se construye una tabla en la cual
cada columna contiene el número de votos de la candidatura
dividido entre 1,2,3... y así sucesivamente, hasta completar P
columnas, siendo P el número de candidatos electos. De entre
todos estos números se seleccionan los P mayores.
En un pueblo de Asturias con 11
concejales se presentaron 7 candidaturas y cada una de ellas obtuvo
los votos reflejados en la columna N de la tabla. Supongamos que no
existen votos nulos o blancos. El número total de votos fue
pues de 9140, así que se eliminan las candidaturas que
obtuvieron menos de 457 votos, para ellos se hacen cero sus votos.
Los 11 mayores
números que aparecen en la tabla son: 3505 2692
1753 1465 1346 1168
897 876
733 701 693 con lo que la candidatura 0 obtuvo cinco
concejales, la 2 uno, la 3 tres y
la 5 dos concejales.
NOTA:
En
lugar de construir una tabla como la de arriba, es mejor utilizar un
vector en el que se almacenen los datos de la primera columna y en
cada iteración, se actualizan las casillas correspondientes,
es decir, se parte de lo siguiente (después de eliminar los
votos de las candidaturas que obtuvieron menos del 5% de los votos):
3505 |
0 |
693 |
2692 |
0 |
1465 |
492 |
El mayor es 3505, entonces se suma un concejal a la
candidatura 0 y se divide 3505 entre 2 (en la tabla aparece
redondeado hacia arriba, en la práctica divida entre 2 sin
mas). La siguiente vez que se dividan los votos de esta candidatura
se hará entre 3. La tabla ahora queda:
1753 |
0 |
693 |
2692 |
0 |
1465 |
492 |
El mayor ahora es 2692, se suma un
concejal a la candidatura 3 y se divide 2692 entre 2, 3505 entre 3 y
asi sucesivamente.
En resumen:
Se pide el número
de candidaturas y de concejales.
Se pide el número de votos
de cada candidatura, se almacenan en un vector.
Se calcula el
número total de votos.
Se hace cero el número de
votos de las candidaturas que obtienen menos del 5% de votos.
Se
repite P veces:
Incrementar en uno el número de
concejales de la candidatura con mayor número de
votos.
Actualizar la cantidad entre la que se divide
Dividir
los votos de cada candidatura entre la cantidad que corresponda.
Utilizar las siguientes funciones para estructurar el ejercicio:
Escribir la función de protipo int suma(const vector<int>&); que recibe un vector de enteros y que devuelve la suma de sus elementos.
Escribir la función de prototipo void purga(vector<int>&); que recibe un vector de enteros conteniendo el número de votos recibido por cada candidatura y lo modifica de modo que hace cero los votos de las candidaturas que reciben menos del 5% de los emitidos. Esta función llama a suma.
Escribir la función de prototipo int mayor(const vector<int>&); que recibe el vector con los votos divididos entre los divisores correspondientes y devuelve el índice del vector en donde está el mayor de sus elementos.
Escribir la función de prototipo void calcula_concejales(const vector<int>&, vector<int>&, int); que recibe los votos que ha recibido cada candidatura y el número de concejales que se reparten. Devuelve los concejales que recibe cada candidatura. Esta función llama a mayor.
De este modo el programa podría quedar así (no se incluye la declaración y definición de las funciones):
#include <iostream> #include <vector> using namespace std; //declaraciones y definiciones de funciones //... //o bien (ver el final) int main() { int i,ncand,P; //pedir el numero de candidaturas y concejales cout << "Numero candidaturas : "; cin >> ncand; cout << "Numero de concejales : "; cin >> P; vector<int> votos(ncand), concejales(ncand,0); //pedir los votos de cada candidatura for (i=0; i<ncand; i++) { cout << "Votos candidatura " << i << " : "; cin >> votos[i]; } //purgar las candidaturas que reciben menos del 5% purga(votos); //llamada a la funcion calcula_concejales calcula_concejales(votos,concejales,P); //mostrar resultados for (i=0; i<ncand; i++) cout << "Candidatura " << i << ": " << concejales[i] << " concejales" << endl; } //puede usar prototipos y poner las definiciones aqui //...
Sexta práctica:
Tres ejercicios propuestos, en función de hasta donde se haya estudiado o visto en clase, escoger dos de ellos.
Escribir un función recursiva que devuelva true si un número entero está entre los elementos de un vector, false en caso contrario.busca_r_guion.cpp. Inspirarse en los ejemplos de recursividad que hay mas abajo
Escribir una función que calcule la longitud de una ruta tomando como datos las coordenadas proporcionadas por un GPS. ruta_f_guion.cpp. La semana que viene lo convertiremos en uno de los ejercicios de examen del año pasado.
Añadir métodos y operadores a la clase complejo vista en clase. guion_practica_complejos_clases.cpp
Séptima práctica:
Resolver el mismo problema de la ruta codificándola como una clase. Seguir este guión.
Octava (y última, que ganas tenía!) práctica:
Resolver el mismo problema de la ruta definiendo la clase punto y la clase ruta (problema de examen). Seguir este guión.
Teoría.
Ejemplos
de if, if else y switch.
Resolver un sistema lineal de ecuaciones de orden dos, considerando todos los casos posibles. sistema2ecc.cpp
Mostrar la hora siguiente a una dada, en hh:mm. hora_siguiente.cpp
Pedir tres números por el teclado y ordenarlos. ordena3.cpp
Resolver una ecuación de segundo grado, considerando todos los casos posibles. segundogrado.cpp
Mostrar el día siguiente a uno dado, considerando el caso de los años bisiestos (problema de examen). diasiguiente.cpp
Implementar una calculadora de números complejos con las operaciones +,-,*,/. Cuidar la representación en pantalla de los complejos, utilizar la notación cartesiana. calculadoracomplejos.cpp
Ejemplos iniciales de bucles.
Sumar las cifras de un número entero. sumacifras.cpp
Invertir el orden de las cifras de un número entero. reves.cpp
Averiguar si un número es capicúa o no. capicua.cpp
Convertir un número de decimal a binario. d2b.cpp
Obtener los 20 primeros términos de la sucesión de Fibonacci. fibo20.cpp
Aproximación de e^x por una serie, finaliza cuando se alcanza un máximo número de iteraciones o una determinada precisión, lo que suceda antes. Intentar realizar el mínimo número de cálculos posible. ex.cpp
Ejemplos con bucles anidados.
Mostrar los n primeros capicúas, n se pide por el teclado. ncapicua.cpp
Determinar los números menores que 1000 tales que aparecen al final de su cuadrado (ejercicio de examen). xy2xyz.cpp
Determinar cual es la fracción que se aproxima más a PI con el numerador y el denominador menores que 500 (ejercicio de examen). PI1.cpp
Descomponer un número en factores primos.factoresprimos.cpp
Buscar el mayor número
entero (menor que 45000 por cuestiones de rango) cuyo cuadrado se
escriba con dígitos distintos. (Ejercicio de examen)
Ejemplos
de cuadrados que cumplen esa condición : 13^2 = 169
286^2=81796 32043^2=1026753849. cuadrado_digitos_distintos.cpp
Un número perfecto es aquel que coincide con la suma de todos sus divisores, incluyendo el 1 pero no el propio número (por ejemplo 6 = 1+2+3, 28 = 1+2+4+7+14). Escribir un programa que muestre por la pantalla los números perfectos menores que 100. (Ejercicio de examen) perfectos.cpp
Todos los ejemplos anteriores en un pdf a dos columnas ejercicios_clase_1.pdf
Ejemplos introductorios de funciones.
Mostrar los n primeros capicúas, n se pide por el teclado. ncapicua_f.cpp
Mostrar los n primeros números que contienen la cifra x. ncontienex_f.cpp
Buscar el mayor número entero (menor que 45000 por
cuestiones de rango) cuyo cuadrado se escriba con dígitos
distintos. (Ejercicio de examen, versión con
funciones)
Ejemplos de cuadrados que cumplen esa condición
: 13^2 = 169 286^2=81796 32043^2=1026753849.
cuadrado_digitos_distintos_f.cpp
Más ejemplos de funciones, relacionados con los temas de los apuntes "Mecanismos de paso de argumentos" y "Semántica del paso de argumentos". De alguna forma todos han caído en algún examen.
Escribir una función que expurgue las repeticiones de los elementos de un vector de enteros. Varias versiones, usando o no push_back, devolviendo el resultado con return o a través de una referencia no constante. unicos.cpp
Sobrecarga de los operadores *, >> y << para matrices. matop.cpp
Mezcla (merge) de dos vectores ordenados produciendo un tercer vector, también ordenado. mezcla.cpp
Máximo de la suma de elementos contiguos de un vector. suma_maxima_segmento.cpp
Función que comprime un vector de enteros "casi vacío" y su contrapartida, descomprime un vector "casi vacío" (ejercicio de examen). Un vector "casi vacío" es aquel que contiene mayoritariamente elementos nulos. Para ahorrar espacio se guarda el tamaño del vector y (alternativamente) la posición y el contenido de los elementos no nulos en un vector de enteros convencional. Por ejemplo el vector {0,0,0,1,0,0,-7,0,0} se podría guardar como {9,3,1,6,-7}. La función comprime se ha escrito usando push_back y sin usarla. comprime.cpp
Función que devuelve true si la paridad de un vector de booleanos es par, false en caso contrario. La paridad es par si el número de elementos a true es par. vector_par.cpp
Los ejercicios anteriores en un mismo pdf a dos columnas. ejercicios_clase2.pdf
Ejemplos de recursividad.
Ordenación por el método merge-sort.
Los fuentes en un mismo pdf.
Ejemplos de funciones template.
Expurgar los elementos repetidos de un vector, versión template.
Ordenación por el método de la burbuja, versión template con argumento procedural para especificar el orden (de mayor a menor o viceversa).
Los fuentes en un mismo pdf.
Ejemplo de estructuras y enumeraciones.
Programa que muestra las 40 cartas de la baraja española en orden aleatorio (barajadas). Se definen enumeraciones para la figura y para el palo y cada carta es una estructura cuyos campos son enumeraciones de los tipos anteriores. barajaf.cpp. El ejercicio tal y como se llevó a clase baraja.pdf.
Ejemplos de clases.
Esquema general de implementación y uso de una clase, sin utilizar y utilizando el operador de resolución de ámbito, es decir definiendo las funciones miembro dentro de la clase esquema_clase.pdf y declarando las funciones dentro y definiéndolas fuera esquema_clase_scope.pdf.
Ejemplos de un problema resuelto sin funciones (complejos_pelado.cpp), con funciones (complejos_con_funciones.cpp), con estructuras (complejos_con_estructuras.cpp) y con clases (complejos_con_clases.cpp). Este último se irá refinando en clases sucesivas, a medida que se impartan los conocimientos necesarios para ello. El objetivo es comprender la ventaja que proporciona al programador/a el uso de clases.
Los ejercicios tal y como se llevaron a clase complejos_gradual.pdf.
Puntero this. explica_this.pdf
Ejemplos para ilustrar el concepto de interfaz pública de una clase. complejos_interfaz_publica.pdf
Ejercicios de examen sencillos. Enunciados enunciados_clases_sencillos.pdf y soluciones ejercicios_clases_sencillos.pdf.
Ejemplos y explicación para destructores, operador de asignación, constructor de copia, cuando se usa memoria dinamica.
Ejemplo de tipo paramétrico (template) clase par de T1 y T2.
Ejemplo de composición (examen), clase punto2d y clase segmento.
Ejemplo de composición (examen), clase punto2d y clase circunferencia.
Ejemplo de composición (examen), intervaloR e intervaloR2.
Ejemplo explicativo de herencia. Clase electrodoméstico. Probablemente esté basado en algún ejemplo de los apuntes de la Universidad de Navarra que no es pública, "Aprenda C++ como si estuviera en primero".
Ejemplo con algo más de sentido, por supuesto se le ocurrió a Luis Junco. Clase abstracta función con un método que calcula la integral definida entre dos valores numéricamente. De ella deriva la función polinomio de segundo grado.