2012-07-01 10 views
6

sagen, dass ich eine Menge von Datenpunkten, die als ein Array von Arrays von Doppel vertreten sind, soSortieren ein Array von Arrays von verschiedenen Indizes in C

double **data; 

Nun, wenn ich durch die die Daten sortieren wollte einige Feld in jedem der Datenpunkte, sagen die 2 nd Feld, würde ich einen Komparator schreiben, die so etwas wie tun würde: qsort sie durch die 2 nd fi

int compare_data_second_field(void *a, void *b) { 
    double da = ((double *) a)[1]; 
    double db = ((double *) b)[1]; 
    if (da < db) return -1; 
    else if (da > db) return 1; 
    return 0; 
} 

und verwenden sie dann zu sortieren Feld

Meine Frage ist, wie verallgemeinere ich das, wenn ich nicht vorher weiß, welches Feld ich sortieren möchte? Wie ich vielleicht nach dem Feld manchmal sortieren möchte und manchmal auch wollen, dass es threadsicher ist, also möchte ich keine globale Variable verwenden, um den Überblick zu behalten Feld, nach dem sortiert werden soll, da mehrere davon gleichzeitig ausgeführt werden können.

In C++ würde ich einfach eine benutzerdefinierte Sortierklasse verwenden und eine Instanzvariable in der Klasse haben, um zu verfolgen, nach welchem ​​Feld sortiert werden soll. Ich weiß nicht, wie man so etwas in C. macht.

+6

Sie greifen tatsächlich den _third_ Artikel. Bist du dir dessen bewusst? –

+2

Eigentlich ist 'double ** data;' 'double data **;' –

+3

Edited für beide.Während sie wahr sind, sind sie für die Diskussion völlig irrelevant und fügen nichts wirklich hinzu, aber was auch immer. – pjreddie

Antwort

7

Der beste Weg wäre, qsort_r zu verwenden, wenn es auf Ihrer Plattform verfügbar ist. qsort_r akzeptiert ein zusätzliches Argument, das an Ihren Vergleicher übergeben wird, damit Sie das Feld übergeben können, nach dem Sie Ihre Daten sortieren möchten.

Wenn das auf Ihrer Plattform nicht verfügbar ist, dann gibt es wirklich keine einfache Möglichkeit, dies zu tun. Sie können das Problem mit globalen Variablen umgehen, indem Sie Ihre Daten in eine Struktur einfügen, die Informationen zum Sortierfeld enthält, oder Ihre eigene qsort_r ähnliche Funktion ausführen.

0

Sie könnten eine ganze Reihe von compare_data_field_N Funktionen für N = 0,1,2 ... deklarieren und dann ein compare_data Array von Funktionszeigern deklarieren, die mit den entsprechenden Funktionen initialisiert wurden. Dann, zu qsort auf einem bestimmten Feld, ziehen Sie den Funktionszeiger aus dem Array, um an qsort übergeben. Sie können Makros verwenden, um die Erzeugung der Funktionen und Anordnung einfacher zu machen:

#define REP10(M) M(0) M(1) M(2) M(3) M(4) M(5) M(6) M(7) M(8) M(9) 
#define DECLARE_COMPARE(N)           \ 
    int compare_data_field_##N(void *a, void *b) {     \ 
     double da = ((double *) a)[N];        \ 
     double db = ((double *) b)[N];        \ 
     if (da < db) return -1;         \ 
     else if (da > db) return 1;        \ 
     return 0;             \ 
    } 
#define REF_COMPARE(N) compare_data_field_##N, 

REP10(DECLARE_COMPARE) 
int (*compare_data_field[])(void *, void *) = { REP10(REF_COMPARE) }; 

Sie müssen die REP10 Makro nur ändern, wenn Sie mehr als 10 Potentialfelder wollen.

+0

Vielleicht irre ich mich, aber ich denke, das OP will den Index des Feldes nach _run-time_ sortieren. –

4

Eigentlich gibt es eine ziemlich saubere Lösung dafür mit verschachtelte Funktionen (die eine GCC-Erweiterung sind).
Was Sie tun können, ist eine generische Komparator machen:

int my_comparator(const void* a, const void* b, int n) 
{ 
    double da = ((double*)a)[n]; 
    double db = ((double*)b)[n]; 
    return (da > db) ? 1 : ((da < db) ? -1 : 0); /* Awesome */ 
} 

und eine benutzerdefinierte Sortierfunktion, die die ursprüngliche qsort() wickelt:

void my_qsort(void* base, size_t num, size_t size, 
    int (*comparator)(const void *, const void *, int), int field) 
{ 
    /* Internal comperator */ 
    int my_qsort_comperator(const void* a, const void* b) 
    { 
     return comparator(a, b, field); 
    } 

    /* Invoke the base qsort function */ 
    qsort(base, num, size, my_qsort_comperator); 
} 

Diese Funktion verhält sich genau wie das Original qsort(), außer es ein dauert zusätzliches Argument field, das den Index des Felds angibt, nach dem sortiert werden soll.

Verwandte Themen