martes, 29 de diciembre de 2020

Cambio de base

Vimos en la explicación del operador MOD un ejemplo de hacer un cambio de base de un número decimal a un binario. En esta oportunidad lo que haremos es generalizar este ejemplo y hacer un programa en C++ que haga el cambio de base del decimal a uno cualquiera que introduzcamos por pantalla.

Un ejemplo de ejecución sería el siguiente:



Lo que vemos en este ejercicio es el uso de:

  • El operador MOD (%)
  • El iterador do-while
  • El iterador for con índice creciente y decreciente

A continuación os dejo el código y podríamos pensar algunas variantes como la representación en base hexadecimal teniendo en cuenta las letras.


int main(int argc, char** argv) {

int base10;

int baseN;

char res[50]; //array que almacena los residuos según los va calculando

int nRes = 0;

char res2[50]; //array que almacena los residuos con la lectura inversa (resultado final)

printf("Ingresa un numero en base decimal:");

scanf("%d", &base10);

printf("\nIngresa la base a la que quieres cambiar:");

scanf("%d", &baseN);

int q = base10;

int r = 0;

//calcula residuos hasta que el cociente es 0

do{

r = q % baseN; //calcula residuo

q = q / baseN; //recalcula la nueva "q" para la siguiente iteración

res[nRes] = r; //concatena el residuo al resultado

nRes++; //número de cifras del resultado

}while(q > 0);


//invierte el resultado (la lectura de los residuos es invertida)

for(int i = (nRes - 1); i >= 0; i--) res2[nRes - i - 1] = res[i];

//imprime  resultado en pantalla

printf("\n%d en base %d es: ", base10, baseN);

for(int i = 0; i < nRes; i++) printf("%i", res2[i]);

return 0;

}

jueves, 17 de diciembre de 2020

Subconjunto ordenado de array

El siguiente ejemplo pide ingresar una lista de números positivos y guardarlos en un array, para luego leerlos y copiar a otro array de forma ordenada sólo aquellos que son múltiplos de 5.

Un ejemplo de ejecución:



¿Qué cambiarías en el programa para que extraiga los múltiplos de otro número?

¿Qué cambiarías para que el orden sea ascendente?

¿Qué otras variaciones añadirías al programa?


#include <iostream>

int main(int argc, char** argv) {

int fin = 0;

int numero;

int listaNumeros[20];

int totalNumeros = 0;

int listaOrdenada[20];

int totalOrdenada = 0;

//lectura por teclado de un conjunto de números positivos, como máximo 20 números

while(!fin && totalNumeros<20){

printf("ingrese un numero:");

scanf("%d", &numero);

if(numero > 0) {

listaNumeros[totalNumeros] = numero;

totalNumeros++;

}else{

fin++;

}

}

//imprimir la lista

for(int i = 0; i<totalNumeros; i++) printf("%d ", listaNumeros[i]);

//seleccionar los múltiplos de 5 ordenados descendente

for(int i = 0; i<totalNumeros; i++){

if( (listaNumeros[i]%5) == 0 ){

int encuentra = 0;

int indice; //indice que recorre la lista ordenada para encontrar la posición donde insertar

int multiploInsertar = listaNumeros[i];//número a insertar en la lista ordenada

indice = totalOrdenada - 1;

//recorremos la lista ordenada de forma descendente y vamos desplazando hasta qu encontramos la posición correcta

while(!encuentra && indice >= 0){

//comparo el número a ubicar con el elemento en la ListaOrdenada en la posición índice

if(multiploInsertar > listaOrdenada[indice]){

//como es mayor muevo el valor de lista ordenada al siguiente índice

listaOrdenada[indice + 1 ] = listaOrdenada[indice];

}

else{

listaOrdenada[indice+1] = multiploInsertar;

totalOrdenada++;

encuentra = 1;

}

indice--;

}

if(!encuentra) {//en el caso que recorra todo el arrayOrdenado y sea mayor a todos, se coloca en el primer elemento

listaOrdenada[0] = multiploInsertar;

totalOrdenada++;

}


}

}

//imprimir la lista

printf("\nNumero de multiplos encontrados %d\n", totalOrdenada);

for(int i = 0; i<totalOrdenada; i++) printf("%d ", listaOrdenada[i]);

return 0;

}

lunes, 14 de diciembre de 2020

Problema de los rombos

El siguiente problema lo he venido encontrado a menudo en diferentes clases, el objetivo es el correcto manejo de la sentencia FOR y el printf.

Lo que busca es ingresar el valor de un número que representa el lado de un rombo e imprimir en pantalla el rombo. un ejemplo de ejecución:


Lo he resuelto utilizando un función para imprimir cada línea, de esta forma el programa me parece más ordenado.

Os dejo el código:

#include <iostream>

void imprimirFila(int fila, int lado)

{

//calculo de fila en el caso de estar en el triangulo inferior

if(fila>lado) fila = (lado * 2) - fila;

//calcular el número de blancos a imprimir

int blancos = (lado * 2) - fila;

//calcular el número de caracteres a imprimir

int impreso = (fila * 2) - 1;

//impresion de blancos

for(int i=1; i<=blancos; i++) printf(" ");

//impresion de caracteres

for(int i=1; i<=impreso; i++) printf("X");

//imprime salto de linea

printf("\n");

}


int main(int argc, char** argv) {

//ingresa el valor del rombo

int lado = 0;

printf("ingrese el lado del rombo:");

scanf("%d", &lado);

printf("el valor del lado ingresado es: %d\n", lado);

//calculamos el número de lineas a imprimir

int lineas = (lado * 2) - 1;

//un for para imprimir cada linea

for(int fila = 1; fila<=lineas; fila++)

{

imprimirFila(fila, lado);

}

return 0;

}



sábado, 17 de septiembre de 2016

Mostrar un menú de sistema

Después de unas largas "vacaciones" vuelvo recargada de energía para empezar un nuevo curso, estos últimos meses he podido empezar mi web de docente que aún está en construcción, la voy avanzando poco a poco y ya os daré el enlace cuando esté terminada.

Mientras tanto quiero compartir que hoy empecé con la primera alumna en este curso 2016-2017 y vimos un problema que se repite mucho, sobretodo en la facultad de Gestión Aeronáutica de la UAB (que últimamente son con los que más trabajo), se trata de mostrar un menú de sistema con distintas opciones:

1. Empezar reserva
2. Modificar reserva
3. Facturar reserva
4. Cancelar reserva
5. Salir

El menú se debe mostrar, realizar las acciones que el usuario seleccione y al terminar de ejecutar cada acción volver a mostrar el menú hasta que el usuario marque salir.

El objetivo de este ejercicio es:

- Reconocer que es necesario el uso de un bloque de instrucciones iterativas (while/for/do-while) para mostrar el menú hasta que el usuario decida salir
- Reconocer que es más práctico utilizar el bloque de instrucciones switch en lugar de if's anidados

A continuación muestro el código comentado en C++

int main(int argc, char** argv) {
//define una variable que guarde la opción seleccionada por el usuario
int opcion =0;
//escogemos do-while para asegurar que el menú se muestre al menos la primera vez
do 
{
                //imprimimos las opciones disponibles del menú
printf (" 1. Hacer reserva\n 2.Modificar reserva\n 3.Facturar reserva\n 4.Cancelar reserva\n 5.Salir\n");

                //leer de teclado la opción seleccionada por el usuario
printf ("Seleccione una opcion\n");
scanf ("%d",&opcion);

                //utiliza el bloque switch para decidir que acción realiza según la opción seleccionada
switch (opcion) 
{
case 1: printf ("Haciendo reserva\n");
break;
case 2: printf ("Modificando reserva\n");
break;
case 3: printf ("Facturando reserva\n");
break;
case 4: printf ("Cancelar reserva\n");
break;
case 5: printf ("Salir\n");
break;

default: printf ("Opcion incorrecta\n");
break;
}
}
while (opcion !=5);//en caso que seleccione la opción 5 termina de ejecutar la iteración

return 0;
}

A continuación muestro unas capturas de pantalla de la ejecución:









domingo, 3 de julio de 2016

Cursores Programación SQL

Para variar un poco, veremos algo de SQL, en este caso serán los cursores.

¿Qué es un cursor?
De forma sencilla podemos decir que es una especie de tipo de variable que se genera a partir de una select y cuyos datos son dinámicos, dependerán de los parámetros que se le pase.
Los cursores son similares a las estructuras, son tipos de datos que podemos crearlos, pero si no los usamos no servirán de nada.

Un ejemplo de declaración de un cursor es:
DECLARE MiCursor CURSOR  
    FOR SELECT campo2 FROM miTabla WHERE campo1 = @valorCampo1 

MiCursor: Es el nombre del nuevo tipo de datos
miTabla: es el nombre de la tabla que estamos consultando
campo1 y campo 2: son campos de la tabla miTabla
@valorCampo1: es el parámetro que se le pasa al cursos para poder obtener la información de forma dinámica

Si ningún programa utiliza el cursor MiCursor que hemos creado entonces será un tipo de datos inservible.
Para utilizarlo debemos recordar la lectura de ficheros, era como la lectura de un vinilo, el cursor es de la misma forma, el resultado de la select es un conjunto de registros en donde cada registro será similar a una linea leída en el fichero. De la misma forma forma como hacemos con un fichero, un cursor debe abrirse y cerrarse, para leer el registro primero nos posicionamos en él mediante la instrucción FETCH, luego de posicionarnos podemos leerlo.
El algoritmo sería el siguiente:
1. Inicializamos los parametros que necesite el cursor
2. Abrimos el cursor
3. Nos posicionamos en el primer registro
4. Leemos registro a registro hasta que lleguemos al último, en este caso el FETCH devolverá un estado de finalización.
5. Cerramos el cursor

Aplicamos el algoritmo al ejemplo:
@valorCampo1 = 1 --inicializamos el parámetro 
OPEN MiCursor --abrimos el cursor
FETCH NEXT FROM MiCursor INTO @registro --se posiciona en el primer registro, la variable @registro debe tener el mismo formato que campo2
WHILE @@FETCH_STATUS = 0  --lee hasta encontrar el estado de finalización
    BEGIN
        FETCH NEXT FROM MiCursor INTO @registro --lectura de siguiente registro
    END
CLOSE MiCursor --cierre de cursor

Para tener claro el funcionamiento de cursores es necesario tener claro el concepto de estructuras, de lectura de ficheros, y por supuesto de sentencias SQL y procedimientos.

martes, 24 de mayo de 2016

Ordenamiento de una lista simplemente enlazada

El ordenamiento de una lista simplemente enlazada es similar al ordenamiento de vectores con la gran diferencia de que en una lista simplemente enlazada no disponemos del concepto del “índice” que nos ayuda a acceder directamente a un elemento de la lista, en este caso para acceder a un elemento debemos recorrer desde el inicio hasta hallar el elemento que nos interese.

Un algoritmo sencillo es el del Intercambio, consiste en lo siguiente:

1. Situar un puntero al inicio de la lista que nos irá indicando a medida que vayamos ordenando, cuánto de la lista ya está ordenada, es la variable más importante del algoritmo porque nos servirá para saber que hemos acabado de ordenar la lista.

Elemento * elemBase = elemInicio;
while(elemBase != NULL)
{
//en este proceso vamos ordenando la lista a partir del nodo elemBase hasta el final
elemBase = elemBase->next;
}

2. En el caso que el ordenamiento sea de menor a mayor, necesitamos encontrar el menor de los elementos a partir del elemento base hasta el final de la lista.
En el caso del ordenamiento de Vectores obteníamos la posición, en este caso obtendremos un puntero al menor elemento.

Elemento* buscarMenor(Elemento* ptrInicial)

Esta función tendría que utilizarse en cada iteración

Elemento * elemBase = elemInicio;
Elemento* elemMenor; //puntero que nos sirve para apuntar al menor elemento encontrado
while(elemBase != NULL)
{
elemMenor = buscarMenor(elemBase);
elemBase = elemBase->next;
}

3. Intercambiar el elemento menor con el elemento que se encuentra apuntando el puntero base. Para hacer este intercambio es necesario que el elemento anterior al elemento base apunte al elemento menor, para eso necesitamos un puntero que apunte al anterior del elemento base.

Como es una lista simplemente enlazada, no podemos retroceder para hallar al puntero anterior al puntero base, por tanto, crearemos una función que nos sirva para ubicarnos en el elemento anterior que queramos. Esta función es necesaria para luego poder hacer el intercambio de nodos.

Elemento * getElemAnterior(Elemento* elemInicio, Elemento* elem);

Utilizaremos esta función para obtener el elemento anterior al base y al menor y de esta forma poder realizar el intercambio

Elemento * elemAnteBase = NULL;//puntero que apunta al anterior de elemento base
Elemento * elemBase = elemInicio;
Elemento* elemAnteMenor; //puntero que apunta al anterior del elemento menor
Elemento* elemMenor; //puntero que nos sirve para apuntar al menor elemento encontrado
while(elemBase != NULL)
{
elemMenor = buscarMenor(elemBase);
elemAnteBase = getElemAnterior(elemInicio, elemBase);
elemAnteMenor = getElemAnterior(elemInicio, elemMenor);
elemBase = elemBase->next;
}

Teniendo el puntero anterior al base ya podemos hacer el intercambio:

void intercambio(Elemento* elemAnteBase, Elemento* elemBase,
Elemento* elemAnteMenor, Elemento* elemMenor);

Incorporamos el intercambio en cada iteración y asignamos el nodo menor como el nuevo elemento base:

Elemento * elemAnteBase = NULL;//puntero que apunta al anterior de elemento base
Elemento * elemBase = elemInicio;
Elemento* elemAnteMenor; //puntero que apunta al anterior del elemento menor
Elemento* elemMenor; //puntero que nos sirve para apuntar al menor elemento encontrado
while(elemBase != NULL)
{
elemMenor = buscarMenor(elemBase);
elemAnteBase = getElemAnterior(elemInicio, elemBase);
elemAnteMenor = getElemAnterior(elemInicio, elemMenor);
intercambio(elemAnteBase, elemBase, elemAnteMenor, elemMenor);
elemBase = elemMenor;
elemBase = elemBase->next;
}

4. Finalmente desarrollamos las funciones:

Elemento* buscarMenor(Elemento* ptrInicial)
{
Elemento* elemMenor = ptrInicial;
Elemento* ptr = ptrInicial;//puntero que sirve para recorrer la lista
int menorValor = elemMenor.valor;//inicializamos el primer valor menor
//recorremos toda la lista y dejamos el puntero elemMenor en el de menor valor
while(ptr!=NULL)
{
if(ptr.valor < menorValor)
{
elemMenor = ptr;
menorValor = ptr.valor;
}
ptr = ptr->next;
}
return elemMenor;
}

void intercambio(Elemento* elemAnteBase, Elemento* elemBase,
Elemento* elemAnteMenor, Elemento* elemMenor)
{
Elemento* aux = elemBase->next; //nos sirve para hacer el intercambio sin perder punteros
elemBase->next = elemMenor->next;
elemMenor->next = aux;
elemAnteBase->next = elemMenor;
elemAnteMenor->next = elemBase;
}

Elemento * getElemAnterior(Elemento* elemInicio, Elemento* elem)
{
Elemento*anterior = NULL;
Elemento*ptr = elemInicio;
int finBusqueda = 0;
while(ptr!=NULL && ptr->next!=NULL && !finBusqueda)
{
if(ptr->next.valor == elem.valor)
{
finBusqueda = 1;
}
anterior = ptr;
ptr = ptr->next;
}
return anterior;


}




lunes, 28 de marzo de 2016

Lectura de fichero de texto

En este post veremos los pasos para realizar la lectura de un fichero de texto, para esto es necesario saber que es similar a escuchar música en un vinilo, se deben realizar  pasos:

1- Poner el disco y la aguja al inicio del disco.
2- Escuchar la música.
3- Levantar la aguja cuando ya no se quiera escuchar o esperar a que termine de reproducirlo todo.

La aguja en el disco viene a representar un puntero de tipo FILE* que se prepara al inicio del fichero, avanza con cada caracter que lee y finalmente debemos cerrarlo.

Fichero que leeremos:


Primer Paso: Abrir Fichero
FILE* abrirFichero () {
      FILE* fptr = NULL; //puntero que abre al inicio del fichero y sirve para recorrerlo
      fptr = fopen ("fichero_prueba.txt", "rt"); //apertura de fichero con permiso de lectura
      return fptr;
}

Invocación de la función abrirFichero:
FILE* ptrFichero; //declaramos una variable de tipo puntero
ptrFichero = abrirFichero (); //invocamos a la función y guardamos el resultado en la variable puntero

Segundo Paso: Leer Fichero
Esta función leerá el fichero hasta el final

void leerFichero(FILE* fptr )
{
  char palabra1 [BUFSIZ];
  char palabra2 [BUFSIZ];
  int numero;
  //La función eof = End Of File devuelve true cuando el puntero llega al final del fichero
  while(!feof(fptr))
  {
      //leemos palabra a palabra (se sabe previamente el formato del fichero)
      //sabemos que leemos 2 palabras y un número por registro
      //cada iteración del while leerá un registro
      fscanf (fptr, "%s", palabra1);
      fscanf (fptr, "%s", palabra2);
      fscanf (fptr, "%i",&numero);
      //imprimimos por pantalla lo que hemos leído
      printf("palabra 1: %s, palabra 2: %s, numero: %i \n", palabra1, palabra2, numero);
   }
}

Invocación de la función leerFichero:
Sólo puede realizarse si el fichero se llego a abrir (ptrFichero != NULL)
FILE* ptrFichero;
ptrFichero = abrirFichero ();
if(ptrFichero != NULL)
{
  leerFichero(ptrFichero);
}

Tercer Paso: Cerrar Fichero
void cerrarFichero (FILE* fptr) {
     fclose(fptr);
}

Invocación de la función leerFichero:
Sólo puede realizarse si el fichero se llego a abrir (ptrFichero != NULL)
FILE* ptrFichero;
ptrFichero = abrirFichero ();
if(ptrFichero != NULL)
{
  leerFichero(ptrFichero);
  cerrarFichero(ptrFichero);
}

El resultado de la ejecución es el siguiente: