Lista Genérica en c

Iniciado por elProfeta1979, 10 Octubre 2014, 18:25 PM

0 Miembros y 1 Visitante están viendo este tema.

elProfeta1979

que les parece mi implementación?




typedef enum _TIPO
{

 INT = 0,
 FLOAT,
 STRING

} TIPO;

typedef struct _NODO_LISTA
{

 TIPO   tipo;

 int    dato_int;
 float  dato_float;

 char   *dato_s;

 struct NODO_LISTA *sig;

} NODO_LISTA;


typedef NODO_LISTA *ListaGenerica;

ListaGenerica LGListaVacia();

ListaGenerica LGApilarInt(ListaGenerica l, int var);

ListaGenerica LGApilarFloat(ListaGenerica l, float var);

ListaGenerica LGApilarString(ListaGenerica l, char* var);

void LGImprimirEnPantalla(ListaGenerica l);




--


#include <stdio.h>
#include "ListaGenerica.h"

ListaGenerica LGListaVacia()
{
  return NULL;
}

ListaGenerica LGApilarInt(ListaGenerica l, int var)
{
  ListaGenerica p;
  p = (ListaGenerica)malloc(sizeof(NODO_LISTA));
  p->dato_int = var;
  p->tipo = INT;

  if(l==NULL){
    p->sig = NULL;
  }else{
    p->sig = l;
  }

  return p;
}

ListaGenerica LGApilarFloat(ListaGenerica l, float var)
{
  ListaGenerica p;
  p = (ListaGenerica)malloc(sizeof(NODO_LISTA));
  p->dato_float = var;
  p->tipo = FLOAT;

  if(l==NULL){
    p->sig = NULL;
  }else{
    p->sig = l;
  }

  return p;
}

ListaGenerica LGApilarString(ListaGenerica l, char *var)
{
  ListaGenerica p;
  p = (ListaGenerica)malloc(sizeof(NODO_LISTA));
  p->dato_s = var;
  p->tipo = STRING;

  if(l==NULL){
    p->sig = NULL;
  }else{
    p->sig = l;
  }

  return p;
}

void LGImprimirEnPantalla(ListaGenerica l)
{
  putchar('[');
  while(l != NULL)
  {
    if(l->tipo==INT)
      printf("%d", l->dato_int);

    else if(l->tipo==FLOAT)
      printf("%f", l->dato_float);

    else if (l->tipo==STRING)
      printf("%s", l->dato_s);

    if (l->sig != NULL)
      printf(", ");

    l=l->sig;
  }
  putchar(']');
}





#include "ListaGenerica.h"

int main()
{
  ListaGenerica l;
  l = LGListaVacia();
  l = LGApilarInt(l, 2);
  l = LGApilarInt(l, 20);
  l = LGApilarInt(l, 21);
  l = LGApilarInt(l, 12);
  l = LGApilarInt(l, 22);
  l = LGApilarFloat(l, 42.41);
  l = LGApilarFloat(l, 242.41);
  l = LGApilarFloat(l, 342.41);
  l = LGApilarString(l, "Pila");
  l = LGApilarString(l, "Generica");
  l = LGApilarString(l, "Anno 2014");

  LGImprimirEnPantalla(l);

  return 0;
}


rir3760

Cita de: elProfeta1979 en 10 Octubre 2014, 18:25 PMque les parece mi implementación?
Para empezar esta bien pero, como todo en programación, se puede mejorar.

Lo primero es eliminar el valor inicial de la enumeración ya que estas siempre empiezan con el valor cero, salvo una razón de peso se debe preferir el tipo double sobre el tipo float y evitar nombres en mayúsculas reservando estos para las macros y las constantes enumeradas.

Ademas:

* Los distintos tipos se pueden agrupar en una union:
#include <stdio.h>

enum tipo {INT, DOUBLE, STRING};
typedef enum tipo Tipo;

struct nodo {
   union {
      int Int;
      double Double;
      char   *str;
   } val;
   Tipo tipo;
   
   struct nodo *sig;
};
typedef struct nodo Nodo;

typedef Nodo *Lista;


* En lugar de una función por cada tipo puedes utilizar una función con un numero variable de argumentos donde el ultimo argumento con nombre indica el tipo del valor, de esa forma cuando agregues tipos solo debes modificar las sentencias de selección y no crear tantas funciones.

Mas o menos así:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

enum tipo {INT, DOUBLE, STRING};
typedef enum tipo Tipo;

struct nodo {
   union {
      int Int;
      double Double;
      char *String;
   } val;
   Tipo tipo;
   
   struct nodo *sig;
};
typedef struct nodo Nodo;

typedef Nodo *Lista;

/* ... */

Lista LG_Apilar(Lista lst, Tipo tipo, ...);
void LG_Imprimir(FILE *out, Lista lst);

int main(void)
{
   Lista lst = NULL;
   
   lst = LG_Apilar(lst, INT, 1);
   lst = LG_Apilar(lst, INT, 2);
   lst = LG_Apilar(lst, INT, 3);
   
   lst = LG_Apilar(lst, DOUBLE, 1.2);
   lst = LG_Apilar(lst, DOUBLE, 3.4);
   lst = LG_Apilar(lst, DOUBLE, 5.6);
   
   lst = LG_Apilar(lst, STRING, "Hugo");
   lst = LG_Apilar(lst, STRING, "Paco");
   lst = LG_Apilar(lst, STRING, "Luis");
   
   LG_Imprimir(stdout, lst);

   return EXIT_SUCCESS;
}

/* ... */

Lista LG_Apilar(Lista lst, Tipo tipo, ...)
{
   Lista nuevo;
   
   if ((nuevo = malloc(sizeof *nuevo)) != NULL){
      char *str;
      va_list ap;
     
      va_start(ap, tipo);
      switch (tipo){
      case INT:
         nuevo->val.Int = va_arg(ap, int);
         break;
      case DOUBLE:
         nuevo->val.Double = va_arg(ap, double);
         break;
      case STRING:
         str = va_arg(ap, char *);
         nuevo->val.String = malloc(strlen(str) + 1);
         strcpy(nuevo->val.String, str);
         break;
      }
      va_end(ap);
     
      nuevo->tipo = tipo;
      nuevo->sig = lst;
   }
   
   return nuevo;
}

void LG_Imprimir(FILE *out, Lista p)
{
   while (p != NULL){
      switch (p->tipo){
      case INT:
         fprintf(out, "%d", p->val.Int);
         break;
      case DOUBLE:
         fprintf(out, "%.2f", p->val.Double);
         break;
      case STRING:
         fprintf(out, "%s", p->val.String);
         break;
      }
      fputc('\n', out);
     
      p = p->sig;
   }
}


En ambos programas faltan muchas cosas como una validación robusta y la liberación de la memoria antes de finalizar el programa.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

elProfeta1979

ese código esta muy bueno!

pienso que las funciones que implementé tienen cierta ventaja a la hora de exportar el código a otro lenguaje.

validación robusta? no tengo idea que significa.

saludos

rir3760

Cita de: elProfeta1979 en 13 Octubre 2014, 05:03 AMvalidación robusta? no tengo idea que significa.
Significa que se debe verificar que toda entrada este dentro de los parámetros esperados, por ejemplo ponte a pensar que pasara si a la función que crea un nodo se le pasa un valor que no es parte de la enumeración de tipos. También se debe verificar el resultado de toda función que pueda fallar (el mejor ejemplo es la lectura de datos de un archivo y las funciones de reserva de memoria).

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language