Mostrando entradas con la etiqueta Estructura de datos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Estructura de datos. Mostrar todas las entradas

Programación dinámica y la sucesión de Fibonacci

(Wikipediazo)En informática, la programación dinámica es un método para reducir el tiempo de ejecución de un algoritmo mediante la utilización de subproblemas superpuestos y subestructuras óptimas.

Decir que un problema tiene subproblemas superpuestos es decir que se usa un mismo subproblema para resolver diferentes problemas mayores. Por ejemplo, en la sucesión de Fibonacci (F3 = F1 + F2 y F4 = F2 + F3) calcular cada término supone calcular F2. Como para calcular F5 hacen falta tanto F3 como F4, una mala implementación para calcular F5 acabará calculando F2 dos o más veces.

Esto se puede evitar guardando las soluciones que ya hemos calculado. Entonces, si necesitamos resolver el mismo problema más tarde, podemos obtener la solución de la lista de soluciones calculadas y reutilizarla. Este acercamiento al problema se llama memoización (no confundir con memorización; en inglés es llamado memoization, véase en). Si estamos seguros de que no volveremos a necesitar una solución en concreto, la podemos descartar para ahorrar espacio.

Comenzando con el pseudocódigo:
FUNC Fibonacci (↓n: NATURAL): NATURAL
VARIABLES
tabla: ARRAY [0..n] DE NATURALES
i: NATURAL
INICIO
SI n = 0 ENTONCES
DEVOLVER 0
SINOSI n = 1 ENTONCES
DEVOLVER 1
SINO
tabla[0] := 0
tabla[1] := 1
PARA i = 2 HASTA n HACER
tabla[i] := tabla[i-1] + tabla[i-2]
FINPARA
DEVOLVER tabla[n]
FINSI
FIN

Una implementación en C de este algoritmo es la siguiente (he cambiado los tipos de dato para que se puedan calcular valores más grandes):
long long fibonacciArreglo(int n) {
long long * lista;
if(n == 0) return 0;
if(n == 1) return 1;
lista = (long long *) malloc(sizeof(long long) * n);
lista[0] = 0;
lista[1] = 1;
int i;
for (i = 2; i <= n; i++) {
lista[i] = lista[i-1] + lista[i-2];
}
return lista[n];
}
Como podemos ver, se reservan n espacios de memoria para almacenar todos los valores de la sucesión, aunque solamente se emplean dos de estos valores a la hora de cálcular el siguente número. Lo cual deriva en un "desperdicio" de memoria. 

Es por eso que basándome en el enunciado que está más arriba en negritas, pensé que implementar una cola sería una opción para ahorrar espacio, podemos agregar dinámicamente los nuevos valores y quitar los que ya no usaremos, de tal manera solo tendríamos en memoria los valores necesarios para calcular el siguiente número en la sucesión. El código queda como sigue:
long long fibonacciCola(int n) {
Cola cola;
if (n == 0) return 0;
if (n == 1) return 1;
creaLista(&cola);
formar(&cola, 0);
formar(&cola, 1);
int i;
for (i = 2; i <= n; i++) {
// Quitamos el elemento menos reciente
long long fi1 = atender(&cola);
// Obtenemos el valor del siguiente más reciente
long long fi2 = valorPrincipio(&cola);
// Almacenamos el resultado en la cola
formar(&cola, fi1 + fi2);
}
return valorFinal(&cola);
}
De esta forma aseguramos que para cualquier tamaño de n solo se ocupen a lo más 3 espacios de memoria.

El código está disponible en la sección de extras del proyecto analizando-algo

¡Saludos!
@fferegrino :)

Ruta más corta entre dos puntos

Como nuestro ulimo proyecto en la unidad de aprenizaje "Estructura de Datos" ( :( sí, el ultimo :'( ) realizamos un programa que, usando la teoría de grafos calcula la distancia más corta entre dos estaciones del metro, hablando solamente de distancia en metros entre las estaciones. Para dicho cálculo se usa el algoritmo de Floyd-Warshall.

Claro que se puede mejorar y probablemente se haga en el futuro, pero por el momento es lo que hay.


¡Gracias gracias!


Descargas:

Reporte de la práctica
Aplicación
Código fuente

¡Saludos! @fferegrino :)

Árboles AVL

El objetivo es leer un archivo "csv" que contendrá los números que queremos insertar en un árbol AVL, sus tres recorridos y su altura serán impresos en un nuevo archivo junto con el camino de un número que se desee buscar.



Descarga del código y más información en 'Leer más' (LOL)

Nuestro programa, abre un archivo del tipo CSV, previamente definido dentro del programa, lee los datos enteros del mismo y los inserta en un árbol AVL presentando en pantalla cada inserción y rotación que realiza en caso de ser necesaria. Muestra, además al finalizar de insertar los datos, los tres recorridos.

La única interacción con el usuario es cuando se solicita que ingrese un entero para buscarlo dentro del árbol. De este muestra el camino que se siguió para buscarlo y en caso de encontrarlo lo presenta.

El archivo de salida, también definido previamente en el código, presenta la altura del árbol, los tres recorridos y el camino que se siguió para buscar el último dato solicitado por el usuario.

Nuevamente gracias a mi amiga y compañera de equipo Iraís :D


Descarga los archivos con el código y el reporte detallado de la práctica.

¡Saludos! @fferegrino :S

¡No al plagio!

De CSV a int *

Esta es nuestra solución para leer datos del tipo entero de un archivo CSV:

Nuestra fución devuelve un apuntador y recibe una cadena; primero definimos y asignamos valores a las variables que ocuparemos.

int * leerDatos(char * arc){
int * resultado = NULL;//Aquí guardaremos el resultado
int numelem = 0;//El número de elementos en el archivo, necesario para reservar memoria dinámicamente
int n=1;
FILE * fp = fopen(arc, "r");//Arbimos el archivo 'arc' solo para lectura.
char * linealeida = (char *)calloc(tamano,sizeof(char));
char * auxlinea = (char *)calloc(tamano,sizeof(char));
/* 'tamano' es el numero aproximado de caracteres en nuestro archivo recomendamos, definirlo previamente */
char * tokens;
También, es recomendable tomar alguna acción si nuestro archivo no pudo ser abierto correctamente.

Leemos la línea, y la copiamos a un auxiliar dado que la función que usaremos para separar los valores de las comas destruye la cadena y la necesitaremos dos veces. La función más importante es strtok(), de la cual, en el vínculo encontrarás más información.

// :)
fgets(linealeida, tamano, fp);
strcpy(auxlinea,linealeida);
tokens = strtok(linealeida, "," );//Comenzamos a separar los valores entre las comas.
while((tokens = strtok( NULL, "," )) != NULL )//Continuamos hasta que no haya más que separar.
numelem++;//Aumentamos la cantidad de elementos que hay.

Reservamos memoria para guardar todos los elementos, más uno, dado que dentro del arreglo también guardaremos la cantidad de dígitos que leímos del archivo. En otras palabras dentro del arreglo guardaremos el tamaño del arreglo menos uno.

En este bloque de código, también usamos el auxiliar de cadena ya que en el bloque anterior la cadena inicial linealeida quedó vacía gracias a la función strtok(). Información acerca de atoi()

resultado=(int *)malloc(sizeof(int)*(numelem+1));
resultado[0] = numelem;//La entrada 0 de nuestro arreglo, guardará la longitud del mismo menos 1
tokens = strtok(auxlinea, "," );//Comenzamos a separar los valores de nuevo
do{//Con atoi() convertiremos de char * a int.
resultado[n++]=atoi(tokens);
}while((tokens = strtok( NULL, "," )) != NULL );
fclose(fp);//Cerramos nuestro archivo para evitar problemas posteriores
return resultado;//Por último, regresamos el arreglo con los datos
}

Si, parte de nuestro proyecto de Estructura de datos. (descarga el código completo)


Agradecimientos a mi querida compañera de equipo Iraís con quien hacer tarea hasta da gusto :)

¡Saludos! @fferegrino :)

Listas con dos estructuras.

Una propuesta para trabajar con listas simplemente enlazadas, usando dos estructuras. Contiene las siguientes funciones:

lista *crear_l();
bool vacia_l(lista *);
bool insertar_vac_l(lista *, tipodato);
bool insertar_inicio_l(lista *, tipodato);
bool insertar_final_l(lista *, tipodato);
bool insertar_cualquiera(lista *, tipodato, int);
tipodato sacar_inicio_l(lista *);
tipodato sacar_final_l(lista *);
tipodato sacar_cualquiera_l(lista *, int);
int buscar_l(lista *, tipodato);
int n_elementos_l(lista *);
void mostrar_l(lista *);

Descargas:
listas.h
listas.c

Basado en una excelente guía de Kioskea, hecho para mi clase de sepultura de batos con la profesora @bellims

!Saludos! @fferegrino :(

Banco - Aplicación con colas (B)

También para linux

Igual requiere de: pilas.h y pilas.c que encuentras en en la entrada anterior.

/* 
* Archivo: Banco.c
* Autores: Rodrigo y Antonio
*
* Creado el 17 de febrero de 2011, 09:30 PM
*/

#include "colas.h"

int main() {

cola *Fila_Banco = crear_c();//Creamos una nueva pila
int tiempo_espera = 0;//Esta variable controlará el tiempo de espera.
int menu = 0;//Variable para el menu principal
do{
printf("Banco Bonito :D\n");
printf("Menú de administrador:\n\t1)Llegada de cliente\n\t2)Salida de cliente\n\t3)Salir\n");
printf("Elige: ");
scanf("%d",&menu);
switch(menu)//Opciones de administrador
{
case 1://Recibimos al cliente
printf("\n\n\n\tNuevo cliente\n");
tipodato nuevo_cliente;//Creamos una nueva estructura
printf("Introduce el nombre del cliente: ");
getchar();//Evitar retorno de carro, Linux ;)
nuevo_cliente.nombre =(char *) calloc(51,sizeof(char));//Reservar memoria para el nombre del cliente
gets(nuevo_cliente.nombre);//Obtener el nombre del cliente
int tiempo_operaciones = 0;//Aquí se guardará el tiempo de operaciones del nuevo cliente
int submenu = 0;//Variable para el submenu
do{
printf("\nElija la(s) operacion(es) que %s realizará:\n",nuevo_cliente.nombre);
printf("\t1)Depósito\n\t2)Retiro\n\t3)Cobro de cheques\n\t4)Depósito a terceros\n\t5)Consulta de saldo\n\t6)Nada");
printf("\nElige: ");
scanf("%d",&submenu);
switch(submenu)//Se acumula el tiempo de operaciones del nuevo cliente
{
case 1: tiempo_operaciones += 5; break;
case 2: tiempo_operaciones += 6; break;
case 3: tiempo_operaciones += 8; break;
case 4: tiempo_operaciones += 4; break;
case 5: tiempo_operaciones += 2; break;
default: break;
}
}while(submenu != 6);
nuevo_cliente.tiempo = tiempo_operaciones;//Se guarda en la estructura el tiempo total de operaciones de el cliente nuevo
if(introducir_c(nuevo_cliente,Fila_Banco))
{
printf("\n\n\t%s está formado y va a esperar %d minutos para ser atendido\n\n",nuevo_cliente.nombre,tiempo_espera);//Desplegar información
}
tiempo_espera += tiempo_operaciones;//Se suma el tiempo de operaciones al tiempo de espera global
break;
case 2://Atendemos al cliente
if(vacia_c(Fila_Banco))//Si la cola está vacía
{
printf("\t\nLa fila está vacía, ya atendiste a todos tus clientes... o nunca has tenido clientes :P\n");
}
else
{
tipodato cliente_atendido = sacar_c(Fila_Banco);//Se saca el cliente de la cola
if(!(cliente_atendido.nombre == NULL)){
printf("\t\nWoha! se ha atendido a %s\n", cliente_atendido.nombre);
tiempo_espera -= cliente_atendido.tiempo;//Un cliente sacado de la cola es un cliente atendido, se resta su tiempo de atención al tiempo global de espera
}
}
break;
case 3: break;
default: break;
}
}while(menu != 3);
return (EXIT_SUCCESS);
}

¡Saludos! @fferegrino :)

Banco - Aplicación con colas.

Para Windows

Requerimos el uso de las funciones básicas de colas, que están en estos links: colas.h colas.c Código fuente:
/* 
* File: main.cpp
* Author: Rodrigo y ToñoGates
*/

#include
#include "colas.h"

void imprimemenu();
void menu_transacciones();
int calcular_tiempo(int []);
int tiempo_espera(Cola *c);

int main(int argc, char** argv) {
char ch;
int num=0;
//clrscr();
printf("\n\t\t\t Toño&Rod´s Bank \n\n\n ¿Deseas hacer una Cola de clientes? S/N\n");
scanf("%c",&ch);
if((ch == 'N')||(ch == 'n')){
printf("Salgo del programa\n");
return (EXIT_SUCCESS);
}
int t_espera=0;
int i=0;

int trans[10]={0};
Cola *c;
c=crear();
TipoDato p1;
p1.nombre=(char *)calloc(100,sizeof(char));
do{
imprimemenu();
scanf("%d",&num);
switch (num)
{
case 1:
i=0;
printf("\n\tNombre:");
getchar();
gets(p1.nombre);
printf("\n\n\tTransaccion(es)a realizar(10 max):");
do{
menu_transacciones();
scanf("%d",&trans[i]);
printf("\n¿Desea realizar otra transacción? S/N");
getchar();
scanf("%c",&ch);
if((ch == 'N')||(ch == 'n')){
printf("Listo");
num=7;
}else i++;
}while(num!=7);
t_espera=tiempo_espera(c);
printf("\nFaltan %d",t_espera);
printf(" minutos.");
p1.tiempo=calcular_tiempo(trans);
if(insertar(c,p1))
printf("\n\n\nCliente introducido con éxito");
else
printf("\n\n\nLo sentimos tu Cliente no se pudo insertar...");
break;
case 2:
if(vacia(c)) printf("\nLa Cola esta vacía. \n");
else{
printf("\nAtendiendo a ...");
TipoDato dat=eliminar(c);
printf("\n %s",dat.nombre);
}
break;
case 3:
if(vacia(c)) printf("\nCola vacía");
else{
printf("\nEstos son tus clientes en espera...\n");
mostrar(c);
}
break;
}
}while (num!=4);
return EXIT_SUCCESS;
}
Las funciones básicas son desarrolladas:
int calcular_tiempo(int trans[]){
int t,suma=0;
for(int i=0;i<11;i++){
switch(trans[i]){
case 1: t=5; break;
case 2: t=6; break;
case 3: t=8; break;
case 4: t=4; break;
case 5: t=2; break;
default: t=0; break;
}
suma=suma+t;
}
return suma;
};

int tiempo_espera(Cola *c){
int suma=0;
Nodo *aux=c->frente;
while(aux!=NULL){
suma+=aux->dato.tiempo;
aux=aux->atras;
}
return suma;
};
¡Saludos! @fferegrino :)

Infijo => Postfijo

Hacer un programa en C que mediante el uso de pilas, transforme una expresión infija a una postfija, nada complicado(en teoría).

Requiere el uso de estos 2 archivos:

pilas.h
pilas.c

Algoritmo y código:
/* 
* Archivo: main.c
* Autores: Antonio Feregrino y Rodrigo Benavides
*
* Creado el 14 de febrero de 2011, 08:22 PM
*/

#include "pilas.h"

int comprobar(char);
int precedencia(char);

/*
*
*/
int main() {
char primera_expresion[50];//Cadena inicial
char *cadenita_auxiliar = calloc(50+1,sizeof(char));//Cadena final
pila *operadores = crear();//Se crea la pila de los operadores
printf("Introduce la expresión a convertir: \n\n");
gets(primera_expresion);//Se lee la expresion principal
int i = 0, i_cadenita = 0;//Variables usadas para recorrer los arreglos de caracteres
while(primera_expresion[i] != '\0'){//Mientras que la expresión principal no se termine

switch(comprobar(primera_expresion[i])){//Comprobación del tipo de caracter 1 a 1
case 1://En este caso el caracter es un parentesis de apertura (
push(primera_expresion[i],operadores);
break;
case 2://En este caso el caracter es un parentesis de cierre )
while(muestra_ultimo(operadores) != '('){//Mientras que el último elemento de la pila no sea (
cadenita_auxiliar[i_cadenita] = pop(operadores);//Saca los operadores de la pila y colocalos en la cadena final
i_cadenita++;//Aumenta el índice de la cadena final para no sobreescribirla
}
pop(operadores);//Saca el paréntesis de apertura (
break;
case 3://En este caso el caracter es un operando [a-zA-Z0-9]
cadenita_auxiliar[i_cadenita] = primera_expresion[i];//Se introdue directamente a la cadena final
i_cadenita++;//Aumenta el índice de la cadena final para no sobreescribirla
break;
case 4://En este cuarto y último caso, el caracter es un operador [+-/%^]
if(vacia(operadores)){//Si la pila esta vacía
push(primera_expresion[i],operadores);//Introduce el operador
}else{//Si no está vacía
int operador_nv = precedencia(primera_expresion[i]);//Se calcula la precedencia del caracter a evaluar
int operador_ol = precedencia(muestra_ultimo(operadores));//Se calcula la precedencia de la cima
if( operador_nv > operador_ol)//Si la precedencia del nuevo es mayor a la de la cima
{
push(primera_expresion[i],operadores);//Introduce el operador
}
else//Si es menor o igual
{
do{
cadenita_auxiliar[i_cadenita] = pop(operadores);//Saca la cima e introducela en la cadena final
i_cadenita++;//Aumenta el índice de la cadena final para no sobreescribirla
operador_ol = precedencia(muestra_ultimo(operadores));//Calcula la precedencia de la nueva cima
}while(!(operador_nv > operador_ol));//Repite esto hasta que la precedencia del nuevo sea mayor a la de la cima
push(primera_expresion[i],operadores);//Introduce el nuevo operador en la cima de la pila
}
}
break;

}
i++;//Recorre en uno el índice de la expresión inicial
}
printf("Tu expresión postfija es: %s\n",cadenita_auxiliar);//Muestra la cadena final
return (EXIT_SUCCESS);
}

int comprobar(char t){
/* Función que comprueba que caracter es, regresa valores enteros segun sea el caso */
if( t == '(' ) return 1;
if( t == ')' ) return 2;
if(( t <= 90 && t >=65 ) || ( t <= 122 && t >= 97 ) || ( t <= 57 && t >=48 )) return 3;
if( t == '*' || t == '+' || t == '^' || t == '/' || t == '-') return 4;
else return 0;
}

int precedencia(char t){
/* Aquí es calculada la precedencia personalizada de los operadores */
if( t == '^' ) return 3;
if( t == '*' || t == '/' || t == '%' ) return 2;
if( t == '+' || t == '-' ) return 1;
if( t == '(' || t == ')' ) return 0;
else return 0;
}



No es el mejor algoritmo pero es lo más que pudimos hacer mi compañero y amigo @frescasandia y yo.


Igual no se si esté permitido por la profesora @bellims hacer esto ;$

¡No al plagio!

¡Saludos! @fferegrino :)