Domanda

Sono incaricato con l'utente che inserisce n linee contenenti un mese, giorno e anno sotto forma di '12 gennaio 99'.

Devo ordinare l'elenco delle date che utilizzano cronologicamente con QSort prima entro l'anno, quindi di giorno, quindi entro il mese.

Il mio problema è che non sono sicuro di come qsort su più indici.L'ho fatto per l'anno che funziona bene, ma dopo non so come qsort il giorno in cui sicuramente lo ordinerà per giorno, ma gli anni saranno di nuovo confusi?

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

typedef int (*compfn)(const void*, const void*);

struct date
{
    char month[9]; //Maximum of 9 characters in a month
    int day; //The day of the month (e.g. 18)
    int year; //The year of the date    
};

int sortDates(struct date *elem1, struct date *elem2)
{

    if (elem1 -> year < elem2 -> year)
    {
        return -1;
    }
    else 

    if (elem1->year > elem2->year)
        {
        return 1;
    }
    else
        return 0;

}


main()
{
    int n;
    int i;

    scanf("%d", &n);

    struct date *list;

    list = (struct date *)malloc((n * sizeof(struct date)));

    for(i = 0; i < n; i++)
    {
        scanf("%s %d %d", list[i].month, &list[i].day, &list[i].year);
    }

    qsort(list, sizeof(list), sizeof(struct date), (compfn)sortDates);

    for(i = 0; i < n; i++)
    {
        printf("%s %d %d\n", list[i].month, list[i].day, list[i].year);
    }
}
.

Modifica: Così ho il sorta di lavoro, sto solo lottando con la conversione da un numero intero alla rappresentazione di stringa del mese quando si stampa l'elenco ordinato.Ecco il codice, sto ottenendo "Array Encript non è un errore intero".

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

typedef int (*compfn)(const void*, const void*);

struct date
{
    int month;
    int day; //The day of the month (e.g. 18)
    int year; //The year of the date    
};

char* months[]= {
   "January", "February",
   "March", "April",
   "May", "June",
   "July", "August",
   "September", "October",
   "November", "December"};


int getMonth(char tempMonth[])
{
    int i = 0;
    for(i = 0; i<12; i++)
    {
            if(tempMonth == months[i]) return i;
    }
    return 0;
}

char getStringMonth(struct date month)
{
    return months[month];
}

int sortDates(struct date *elem1, struct date *elem2)
{
    if (elem1 -> year < elem2 -> year)
    {
        return -1;
    }
    else 

    if (elem1->year > elem2->year)
        {
        return 1;
    }


    if ( elem1->month < elem2->month )
    {
            return -1;
    }
    else 

    if ( elem1->month > elem2->month )
        {
        return 1; 
    }


    if ( elem1->day < elem2->day )
    {list
            return -1;
    }
        else 

    if ( elem1->day > elem2->day )
        {
        return 1;
    } 
        else

    return 0;
}

main()
{
    int n;
    int i;
    char tempMonth[255]; //Used to store the month until checked

    scanf("%d", &n);list

    struct date *list;

    list = (struct date *)malloc((n * sizeof(struct date)));

    for(i = 0; i < n; i++)
    {
        scanf("%s %d %d", tempMonth, &list[i].day, &list[i].year);
        list[i].month = getMonth(tempMonth);
    }

    qsort(list, sizeof(list), sizeof(struct date), (compfn)sortDates);

    for(i = 0; i < n; i++)
    {
        printf("%s %d %d", getStringMonth(list[i].month), list[i].day, list[i].year);
    }

}
.

È stato utile?

Soluzione

Ricordati di free La memoria malloc'd.

Nel seguente codice ho assunto che il mese è memorizzato come un numero, ma vedo nella tua struttura che questo non è il caso.Convertirei il mese immesso dalla stringa a un numero, per facilitare il processo di ordinamento.

int sortDates(struct date* elem1, struct date* elem2)
{

    if ( elem1->year < elem2->year)
        return -1;
    else if ( elem1->year > elem2->year )
        return 1;


    /* here you are sure the years are equal, so go on comparing the months */

    if ( elem1->month < elem2->month )
        return -1;
    else if ( elem1->month > elem2->month )
        return 1; 

    /* here you are sure the months are equal, so go on comparing the days */

    if ( elem1->day < elem2->day )
        return -1;
    else if ( elem1->day > elem2->day )
        return 1; 
    else
        return 0; /* definitely! */

}
.

Presta anche attenzione a questa Dichiarazione: char month[9];, è vero che Settembre è 9 caratteri, ma è necessario un chiusura di chiusura terminator '\0' in C per chiudere una stringa.Per evitare questo tipo di problemi, dichiarò un array con tutti i mesi, per consentire il controllo e convertire il mese da una stringa a un numero:

char* allMonths[]=
   "January", "February",
   "March", "April",
   "May", "June",
   "July", "August",
   "September", "October",
   "November", "December";

char tmpMonth[255];
scanf("%s %d %d", tmpMonth, &list[i].day, &list[i].year);
/* convert tmpMonth to a number by finding it in the allMonths and throw error if not found */
.

Altri suggerimenti

Invece di tornare 0 quando i due anni sono uguali, basta copiare la logica e applicarlo a mesi.Quindi ancora una volta per giorni.Questo è tutto.

A proposito, se vuoi un tipo cronologico, devi prima ordinare gli anni, poi i mesi, poi i giorni.Non giorni quindi mesi.

E dovresti conservare mesi come numeri, non stringhe: sarà più facile per un tipo cronologico.

Infine, avrei nominato la funzione compareDates, non sortDates.

Invece di tornare 0 sull'ultimo else, confronta un altro campo:

else {
    if (elem1->day < elem2->day) {
        return -1;
    }
    else if (elem1->day > elem2->day) {
        return 1;
    }
    else {
        //compare months
    }
}
.

L'idea di base è:

    .
  1. Controlla gli anni, se non sono lo stesso risultato di ritorno (come fai)
  2. Se gli anni sono gli stessi, controllare i giorni, se non sono lo stesso risultato di ritorno
  3. Se i giorni sono anche lo stesso, controllare il mese.

Quello che hai va bene per l'anno (la chiave principale). Hai solo bisogno di un leggero adattamento per usare il mese (la chiave minore) quando l'anno è uguale e puoi estenderlo a tanti livelli di tasti che vuoi.

Pseudo-codice solo per i compiti, ho paura:

def compare (date1, date2):
    if date1.year > date2.year:
        return 1
    if date1.year < date2.year:
        return -1

    # Years are equal here.

    if date1.month > date2.month
        return 1
    if date1.month < date2.month
        return -1

    # Years and months are equal here.

    if date1.day > date2.day
        return 1
    if date1.day < date2.day
        return -1

    # Years, months and days are all equal here.

    return 0
.

Facendo una singola funzione di confronto "stratificata" come questa, non dovrai preoccuparti per il mese di smistamento del mese che avvita l'ordine degli anni, dal momento che ordina di giorno dentro mesi entro anno.

E, come puoi vedere, non sono un grande fan del:

if condition:
    return something
else:
    carry on
.

idiom. Il else è totalmente inutile e può causare enormi livelli di rientranza in cui nessuno è necessario. Preferisco:

if condition:
    return something

carry on
.

Il metodo effettivo per l'ordinamento è meglio eseguito ruotando i nomi del mese in valori numerici, quindi i confronti funzionano meglio. Probabilmente è meglio rimasto per una domanda diversa ma potresti probabilmente mettere insieme qualcosa con un array di stringa:

char *months[] = {"January", "February", ... "December"};
.

E un anello for per convertire il nome in un valore nella gamma 0 attraverso 11.

È necessario modificare la funzione di confronto, sortDates e prendere la decisione basata sui giorni in cui anni sono uguali e basati sul mese in cui sono uguali giorni e mesi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top