Qsort sulla base di una colonna in un c-string?
Domanda
Un progetto di classe coinvolge ordinare un array di stringhe, con ogni stringa contenente un numero uguale di colonne così:
Cartwright Wendy 93 Williamson Mark 81 Thompson Mark 100 Anderson John 76 Turner Dennis 56
Il programma accetta un argomento della riga di comando per il quale colonna per ordinare, e dovrebbe stampare le stringhe ordinate non modificato.
Vorrei utilizzare strtok per spezzare copie di ogni stringa in colonne, e rendere le strutture per ogni linea in questo modo:
struct line {
char * line;
char column_to_sort_on[MAX_COLUMN];
}
Il mio problema è nel puntatore a funzione di confronto che qsort prende come un ARG. Se ho capito bene, la funzione di confronto deve prendere due puntatori void const alle voci da ordinare , e restituire un int. Ciò significa che non posso passare puntatori per le strutture in funzione di confronto, perché non è quello che qsort saranno ordinamento. Non posso passare il numero di colonna per ordinare al funzione di confronto, perché può avvenire solo due args. Come posso ottenere intorno a questo per ordinare queste stringhe in base a specifiche colonne?
modifica L'ordinamento è limitato a qsort o il mio, se voglio davvero. Dare la scelta, scelgo qsort. :)
Modifica # 2: Il consenso sembra essere o utilizzare una variabile globale per il numero di colonna, o semplicemente usare qsort per ordinare un array di strutture. Non avevo pensato di appena l'ordinamento le struct, e utilizzando il puntatore a loro di stampare la stringa originale. Credo che questo sia quello che farò. Grazie per l'aiuto tutti!
Soluzione
È possibile passare le struct in questo modo:
struct line {
char * line;
char column_to_sort_on[MAX_COLUMN];
}
...
line* Lines[max_lines]; // here you store the structs
int
cmp_lines( const void *elem1, const void *elem2 )
{
line* line1 = *(line**)elem1;
line* line2 = *(line**)elem2;
// do the comparisons
}
qsort(Lines, max_lines, sizeof(line*), cmp_lines);
Altri suggerimenti
Supponendo che non si è limitati ad usare qsort, è possibile utilizzare std :: sort, con un oggetto funtore che memorizza il numero di colonna. Se si deve usare qsort, una soluzione rapida e sporca potrebbe essere quella di memorizzare il numero di colonna in una variabile globale e l'uso che nella funzione comparisson.
funzioni comparatori differenti, ognuno dei quali prendono tutta struct, ma ognuno usa solo una colonna per comparazione.
C ++ o C? Sulla base delle vostre etichette, presumo che sia C ++. Proviamo modo STL.
Si dovrebbe usare std::sort
invece di qsort
. std::sort
può avvenire non solo puntatore alla funzione (rispetto alla sua alternativa C), ma qualsiasi oggetto che può essere chiamato come una funzione. Si può sapere che le istanze di classe possono essere chiamati come funzioni con operator()
. Allora la soluzione è semplice: creare una classe "funtore" che creerà funzioni differenti su di costruzione. La chiamata sorta sarebbe quindi simile che:
std::sort(array, array+size, comparator(2 /* sort by column #2 */));
La classe funtore crea effettivamente una cosiddetta "chiusura": un oggetto funzionale creato in modo dinamico che ha variabili locali, ma non li condivide con altri oggetti funzionali creati in questo modo. Si sarebbe simile a questa:
class comparator{
private: unsigned int field_n;
public: comparator(unsigned int _field_n) : field_n(_field_n) {};
public: int operator () (char const * lhs, char const * rhs)
{ /* compare here fields with index field_n */ };
};
Si noti che, invece di vuoto confronto puntatori "funzione" (vale a dire l'istanza della classe si crea) ha char *
parametri, quindi non ci si preoccupano con il tipo di getto.
In C, purtroppo, non è possibile fare questo il contrario rispetto alla creazione di una variabile globale.