Sort linked list in C

2

My problem involves reading data from a text file, where the CPF is provided, name, email, age, order save using list sort in ascending order through age, if you have the same age sort by cpf. But I'm having trouble sorting the linked list, so far I've done this

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Dado{
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
    struct Dado* proximo;
}Dado;

int ler_string_arq(FILE* arq, char *campo_destino){
    int letra = 0;
    char ch;
    if (fscanf(arq,"%c",&ch) == EOF)
    {
        return 1;       
    }
    while( ch != ',') 
    {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Dado{
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
    struct Dado* proximo;
}Dado;

int ler_string_arq(FILE* arq, char *campo_destino){
    int letra = 0;
    char ch;
    if (fscanf(arq,"%c",&ch) == EOF)
    {
        return 1;       
    }
    while( ch != ',') 
    {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '%pre%';
return 0;
}

int main()
{
FILE *arq, *arqout;
char ch,teste;

arq = fopen("read.txt","r");

Dado *inicio = NULL, *fim = NULL;

while (1)
{
    Dado *pessoa = malloc(sizeof(Dado));
    pessoa->proximo = NULL;
    if (inicio == NULL){
        inicio = pessoa;
    }
    if (fim != NULL){

        fim->proximo = pessoa;
    }
    fim = pessoa;

    if (ler_string_arq(arq, pessoa->CPF)){
        free(pessoa);
        break;
    }
    ler_string_arq(arq, pessoa->nome);
    ler_string_arq(arq,pessoa->email);
    fscanf(arq,"%d", &pessoa->idade);
    fscanf(arq,"%c", &ch);
}
fclose(arq);


arqout = fopen("write.txt","w");
Dado* pessoa = inicio;
while (pessoa->idade != 0){
    fprintf(arqout,"%s,%s,%s,%d\n", pessoa->CPF, pessoa->nome, pessoa->email, pessoa->idade);
    pessoa= pessoa->proximo;
}
fclose(arqout);
return 0;
}
'; return 0; } int main() { FILE *arq, *arqout; char ch,teste; arq = fopen("read.txt","r"); Dado *inicio = NULL, *fim = NULL; while (1) { Dado *pessoa = malloc(sizeof(Dado)); pessoa->proximo = NULL; if (inicio == NULL){ inicio = pessoa; } if (fim != NULL){ fim->proximo = pessoa; } fim = pessoa; if (ler_string_arq(arq, pessoa->CPF)){ free(pessoa); break; } ler_string_arq(arq, pessoa->nome); ler_string_arq(arq,pessoa->email); fscanf(arq,"%d", &pessoa->idade); fscanf(arq,"%c", &ch); } fclose(arq); arqout = fopen("write.txt","w"); Dado* pessoa = inicio; while (pessoa->idade != 0){ fprintf(arqout,"%s,%s,%s,%d\n", pessoa->CPF, pessoa->nome, pessoa->email, pessoa->idade); pessoa= pessoa->proximo; } fclose(arqout); return 0; }

I'm starting to study lists, someone could indicate a good way to sort what I've done and how that would change the print

    
asked by anonymous 18.09.2018 / 03:28

1 answer

1

Ordering with copy of values

The simplest way to demonstrate this for the code you have is through an bubble sort algorithm with the copy of the values of each structure between them. The difference is mostly in the list, which is done through the proximo pointers.

Implementation:

Dado *pessoa1 = inicio;

while (pessoa1 != NULL){
    Dado *pessoa2 = pessoa1->proximo;
    while (pessoa2 != NULL){
        if (pessoa1->idade > pessoa2->idade){ //se maior troca o conteudo das duas pessoas
            int temp_idade = pessoa1->idade; 
            pessoa1->idade = pessoa2->idade;
            pessoa2->idade = temp_idade;
            troca_string(pessoa1->CPF, pessoa2->CPF, 12);
            troca_string(pessoa1->nome, pessoa2->nome, 41);
            troca_string(pessoa1->email, pessoa2->email, 31);
        }
        pessoa2 = pessoa2->proximo;
    }

    pessoa1 = pessoa1->proximo;
}

The first while cycles through the list from start to finish, and the second while will go further, and every time you find a person of a greater age, you change all of that person's values. Since there are several strings to be exchanged I chose to create a function that makes the exchange of string up to a certain amount of characters in order to simplify. Since there was only one field of the integer type to be exchanged I did no function for this exchange.

The function troca_string would be:

void troca_string(char *str1, char *str2, size_t tamanho){
    static char temp[50];
    memcpy(temp, str1, tamanho);
    memcpy(str1, str2, tamanho);
    memcpy(str2, temp, tamanho);
}

In this case, static prevents the temp string from being created every time the function is called, and is created only once, which is ideal for this scenario. For the exchange of the string itself I used the memcpy function that already exists to copy the whole string, but could have done the same at the expense of a normal loop copying letter to letter.

This implementation in spite of working is not very good because the exchange of each element of the structure is very heavy. On my machine sizeof(Dado) gives 92, which is 92 bytes, which means that each switch has to copy 92 bytes 3 times. And it can still be worse depending on the quantity and size of the fields of the structure, as well as the quantity of elements to order. The solution to this problem is pointers.

Sorting by pointer switching

With change of pointers we can avoid copying the various values, but this solution usually means changing the original structure and consequently a lot of the code and so it becomes a little annoying.

In this case the structure would have a pointer to the data and another to the next node in the list as it already had:

typedef struct Info { //informação de cada pessoa
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
} Info;

typedef struct Dado {
    Info* info; //agora ponteiro em vez de os campos diretamente
    struct Dado* proximo;
} Dado;

The structure Dado actually corresponds to each node in the list whereas the Info structure corresponds to each person's information.

With this change the reading of the file information would have to be different because not only must it also allocate space for the Info as the read must become on the Info :

int main() {
    ... 
    Dado *inicio = NULL, *fim = NULL;

    while (1) {
        Dado *pessoa = malloc(sizeof(Dado));
        pessoa->info = malloc(sizeof(Info)); //alocar também o info

        pessoa->proximo = NULL;
        if (inicio == NULL) {
            inicio = pessoa;
        }
        if (fim != NULL) {
            fim->proximo = pessoa;
        }

        if (ler_string_arq(arq, pessoa->info->CPF)) { //agora ->info->CPF
            free(pessoa->info); //liberar tambem o info
            free(pessoa);
            fim->proximo = NULL;
            break;
        }
        fim = pessoa;

        ler_string_arq(arq, pessoa->info->nome); //->info->nome
        ler_string_arq(arq,pessoa->info->email); //->info->email
        fscanf(arq,"%d", &pessoa->info->idade); //->info->idade
        fscanf(arq,"%c", &ch);
    }
    fclose(arq);

The ordering is now simpler and more efficient because when it is necessary to change two people of order, just change the pointer to the information of each node:

Dado *pessoa1 = inicio;

while (pessoa1 != NULL){
    Dado *pessoa2 = pessoa1->proximo;
    while (pessoa2 != NULL){
        if (pessoa1->info->idade > pessoa2->info->idade){
            Info *temp = pessoa1->info; //agora troca só o info
            pessoa1->info = pessoa2->info;
            pessoa2->info = temp;
        }
        pessoa2 = pessoa2->proximo;
    }

    pessoa1 = pessoa1->proximo;
}

The show also has to switch to ->info :

arqout = fopen("write.txt","w");
Dado* pessoa = inicio;
while (pessoa != NULL) {
    fprintf(arqout,"%s,%s,%s,%d\n", pessoa->info->CPF, pessoa->info->nome, pessoa->info->email, pessoa->info->idade);
    pessoa= pessoa->proximo;
}
fclose(arqout);

Complete code for reference:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Info {
    char CPF[12];
    char nome[41];
    char email[31];
    int idade;
} Info;

typedef struct Dado {
    Info* info;
    struct Dado* proximo;
} Dado;

int ler_string_arq(FILE* arq, char *campo_destino) {
    int letra = 0;
    char ch;
    if (fscanf(arq,"%c",&ch) == EOF) {
        return 1;
    }
    while( ch != ',') {
        campo_destino[letra] = ch;
        fscanf(arq,"%c", &ch);
        letra++;
    }
    campo_destino[letra] = '
Dado *pessoa1 = inicio;

while (pessoa1 != NULL){
    Dado *pessoa2 = pessoa1->proximo;
    while (pessoa2 != NULL){
        if (pessoa1->idade > pessoa2->idade){ //se maior troca o conteudo das duas pessoas
            int temp_idade = pessoa1->idade; 
            pessoa1->idade = pessoa2->idade;
            pessoa2->idade = temp_idade;
            troca_string(pessoa1->CPF, pessoa2->CPF, 12);
            troca_string(pessoa1->nome, pessoa2->nome, 41);
            troca_string(pessoa1->email, pessoa2->email, 31);
        }
        pessoa2 = pessoa2->proximo;
    }

    pessoa1 = pessoa1->proximo;
}
'; return 0; } int main() { FILE *arq, *arqout; char ch,teste; arq = fopen("read.txt","r"); Dado *inicio = NULL, *fim = NULL; while (1) { Dado *pessoa = malloc(sizeof(Dado)); pessoa->info = malloc(sizeof(Info)); pessoa->proximo = NULL; if (inicio == NULL) { inicio = pessoa; } if (fim != NULL) { fim->proximo = pessoa; } if (ler_string_arq(arq, pessoa->info->CPF)) { free(pessoa->info); free(pessoa); fim->proximo = NULL; break; } fim = pessoa; ler_string_arq(arq, pessoa->info->nome); ler_string_arq(arq,pessoa->info->email); fscanf(arq,"%d", &pessoa->info->idade); fscanf(arq,"%c", &ch); } fclose(arq); Dado *pessoa1 = inicio; while (pessoa1 != NULL){ Dado *pessoa2 = pessoa1->proximo; while (pessoa2 != NULL){ if (pessoa1->info->idade > pessoa2->info->idade){ Info *temp = pessoa1->info; pessoa1->info = pessoa2->info; pessoa2->info = temp; } pessoa2 = pessoa2->proximo; } pessoa1 = pessoa1->proximo; } arqout = fopen("write.txt","w"); Dado* pessoa = inicio; while (pessoa != NULL) { fprintf(arqout,"%s,%s,%s,%d\n", pessoa->info->CPF, pessoa->info->nome, pessoa->info->email, pessoa->info->idade); pessoa= pessoa->proximo; } fclose(arqout); return 0; }
    
18.09.2018 / 13:20