Test Foro de elhacker.net SMF 2.1

Programación => Programación C/C++ => Mensaje iniciado por: palacio29 en 20 Junio 2020, 17:37 PM

Título: Eliminar todos los repetidos de una lista
Publicado por: palacio29 en 20 Junio 2020, 17:37 PM
Buenos Dias.
Queria consultar como podia hacer para eliminar todos los elementos repetidos de una lista.
En este caso lo que hice fue crear una lista que contenga a una estructura y lo que tengo que hacer es que elimine todos los nodos cuyo apellido sea "Lopez".
Lo intento hacer y elimina algunos elementos pero no todos,  el problema esta en la función eliminar pero no se como modificarla para que elimine todos y no algunos.

#include <stdio.h>
#include <stdlib.h>
struct s_datos
{
    char*nombre;
    char*apellido;
    int dni;
};
typedef struct s_datos t_dato;
struct s_nodo
{
    t_dato dato;
    struct s_nodo*sig;
};
typedef struct s_nodo*t_nodo;
void agregar(t_nodo*,t_dato);
void imprimir(t_nodo);
void eliminar(t_nodo*,char*);
t_dato cargarstruct();
char*cargatexto();
int main()
{
    t_nodo lista=NULL;
    agregar(&lista,cargarstruct());
    agregar(&lista,cargarstruct());
    agregar(&lista,cargarstruct());
    agregar(&lista,cargarstruct());
    agregar(&lista,cargarstruct());
    imprimir(lista);
    eliminar(&lista,"Lopez");
    printf("\nLista con eliminados\n");
    imprimir(lista);

    return 0;
}
t_dato cargarstruct()
{
    t_dato datito;
    ///CARGAR ESTRUCTURA
    printf("\nIngrese Nombre:\n");
    datito.nombre=cargatexto();
    printf("\nIngrese Apellido:\n");
    datito.apellido=cargatexto();
    printf("\nIngrese DNI:\n");
    scanf("%d",&datito.dni);
    return datito;
}
void agregar(t_nodo*nodo,t_dato datito)
{
    if(*nodo==NULL)
    {
        *nodo=(t_nodo)malloc (sizeof(struct s_nodo));
        (*nodo)->dato=datito;
        (*nodo)->sig=NULL;
    }
    else
    {
        agregar(&(*nodo)->sig,datito);
    }
}
void imprimir(t_nodo lista)
{
    if(lista!=NULL)
    {
        printf("\nNombre: %s - Apellido: %s - DNI: %d",lista->dato.nombre,lista->dato.apellido,lista->dato.dni);
        imprimir(lista->sig);
    }
}
void eliminar(t_nodo*nodo,char*texto)
{
    t_nodo aux=NULL;
    if(*nodo==NULL)
    {
        return;
    }
    else if((strcmp((*nodo)->dato.apellido,texto))==0)
    {
        aux=(*nodo);
        *nodo=(*nodo)->sig;
        free(aux);
        eliminar(&(*nodo)->sig,texto);
    }
    else
    {
          eliminar(&(*nodo)->sig,texto);
    }
}
char*cargatexto()
{
    char letra;
    int i=0;
    char*txt=NULL;
    txt=malloc(sizeof(char));
    letra=getche();
    while(letra!='\r')
    {
        *(txt+i)=letra;
        i++;
        txt=realloc(txt,(i+1)*sizeof(char));
        letra=getche();
    }
    *(txt+i)='\0';
    return txt;

}


Muchas gracias.
Título: Re: Eliminar todos los repetidos de una lista
Publicado por: Mecanma en 28 Junio 2020, 09:56 AM
Hola, creo que deberías hacer la comparación fuera de la función así solo se encarga de borrar el nodo. También veo que en la linea 81 y 85 llamas la función de manera recursiva, no sé si tu profesor te lo pidió explicitamente de esta forma.
Título: Re: Eliminar todos los repetidos de una lista
Publicado por: 98Fran en 3 Julio 2020, 12:25 PM
No se de C pero puede que la nomenclatura en punteros sea la misma que en C++ asíi que por si acaso te dejo aquí unos consejos (si funcionan en C xD).

Primero: Yo usaría más los espacios, cuesta de leer el código:

char *nombre;
//o
char* nombre;


Se leen mejor que:

char*nombre;


y eso se aplicaría para las funciones o cualquier declaración con punteros.

Segundo: para hacer typedef de struct(al menos en C++) no hace falta poner struct

char *nombre
//o
char* nombre


Tercero: Cuando pasas un t_nodo estas pasando el puntero del nodo, por tanto no hace falta que lo desreferencies para luego pasar la dirección de memoria en el main y lo mismo. Si lo declaras asi:

void agregar(t_nodo &, t_dato);


Te evitas poner & en el main y queda más fácil de leer.

Cuarto: Por lo que he visto, podrías usar un puntero fin para evitar el coste de O(n) que supone recorrer toda la lista. Como no hay clases en C podrias crear una struct extra:

struct s_nodo_ini
{
    t_dato dato;
    struct s_nodo*sig;
    struct s_nodo *fin;
}

para el nodo cabeza y cuando añades un nodo al fin lo haces desde fin y luego actualizas el nodo fin y si quieres recorrer toda la lista lo haces desde el nodo sig.



En cuestión a tu problema: usa el nodo aux para moverte, no hace falta usar recursividad de forma innecesaria. 


void eliminar(t_nodo*nodo,char*texto)
{
    t_nodo aux= &nodo; //siendo nodo la cabeza/inicio

    while(aux != NULL) //recorres todo la lista
    {
        //Aqui haces la comprobación y en caso positivo lo eliminas
         
        aux = aux->sig; //no se si se escribe asi en C pero el concepto es el mismo
    }
}