Eliminar todos los repetidos de una lista

Iniciado por palacio29, 20 Junio 2020, 17:37 PM

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

palacio29

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.

Mecanma

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.

98Fran

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
    }
}