2016-12-04 7 views
1

Ich versuche die qsort() Funktion zu verwenden, um nur die geraden Zahlen eines Arrays zu sortieren (die Chancen bleiben in ihren Positionen).qsort(): Nur gerade Zahlen eines Arrays sortieren

Zum Beispiel, wenn ich das Array haben:

5 122 3 26 48 

Nach dem Sortieren würde man erhalten:

5 26 3 48 122 

Meine Intuition war nur eine Art zu machen, wenn beide von a und b wies Zahlen sind sogar .

Dies ist mein Versuch:

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

int comp_even(const void *a, const void *b) { 
    int l = *(int *)a; 
    int r = *(int *)b; 

    if (!(l&1) && !(r&1)) //if both are even, then sort them in ascending order 
     return (l-r); 

    return 0; 
} 

int main() { 
    int i, n; 
    int a[1001]; 

    scanf("%d", &n); 

    for (i = 0; i < n; i++) { 
     scanf("%d", &a[i]); 
    } 

    qsort(a, n, sizeof(int), comp_even); 

    for (i = 0; i < n; i++) { 
     printf("%d ", a[i]); 
    } 
    return 0; 
} 
+2

Ich denke nicht, dass das mit einer allgemeinen Vergleichssortierung wie 'qsort' möglich ist. – melpomene

+1

copy => sort => zurückschreiben – BLUEPIXY

+0

Wie erwarten Sie, dass '6 5 4 3 2 1' sortiert wird? '2 4 6 5 3 1' oder' 2 5 4 3 6 1'? Das heißt, muss jede ungerade Zahl auf dem gleichen Index im Array bleiben? Oder müssen sie nur relativ zueinander sortiert werden? – Schwern

Antwort

1

Es scheint unmöglich, eine Vergleichsfunktion für Ihre Zwecke zu entwerfen, aber Sie können eine Kopie der geraden Zahlen zu machen, zu sortieren, dass mit qsort und versenden die sortierte Teilmenge über die geraden Zahlen des ursprünglichen Arrays:

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

int comp_int(const void *a, const void *b) { 
    const int *ap = a; 
    const int *bp = b; 
    return (*ap > *bp) - (*ap < *bp); 
} 

int main(void) { 
    int i, j, n, n_even; 
    int a[1001]; 
    int even[1001]; 

    if (scanf("%d", &n) != 1 || n <= 0 || n > 1001) 
     return 1; 

    n_even = 0; 
    for (i = 0; i < n; i++) { 
     scanf("%d", &a[i]); 
     if ((a[i] & 1) == 0) { 
      even[n_even++] = a[i]; 
     } 
    } 

    qsort(even, n_even, sizeof(int), comp_int); 

    for (i = j = 0; i < n; i++) { 
     if ((a[i] & 1) == 0) { 
      a[i] = even[j++]; 
    } 
    for (i = 0; i < n; i++) { 
     printf("%d ", a[i]); 
    } 
    printf("\n"); 
    return 0; 
} 

Beachten Sie auch, dass Ihre ursprüngliche Vergleichsfunktion einen Trick verwendet ganze Zahlen zu vergleichen, die für große Werte ausfallen. Die Differenz von 2 ganzen Zahlen kann außerhalb des Bereichs von int liegen. Daher kann die Rückgabe l - r für viele Werte von l und r falsch sein.

Zum Beispiel l=INT_MIN und r=1 wird INT_MIN-1 zurückzukehren, bewirkt die Subtraktion einen arithmetischen Überlauf, der undefinierten Verhalten aufruft und in aktuellen 2s ergänzen Architekturen ausgewertet INT_MAX, einen positiven Wert, obwohl INT_MIN < 1.

3

Leider unterstützt qsort nichts dergleichen; für zwei beliebige Elemente, muß die Vergleichsfunktion einer der drei Ergebnisse zurück:

  • eine negative ganze Zahl ist, was bedeutet, dass der erste Parameter vor seinem zweiten Ende sollte;
  • eine positive ganze Zahl, was bedeutet, dass der erste Parameter nach sollte am Ende des zweiten;
  • Null, was bedeutet, dass entweder Ordnung in Ordnung ist (in diesem Fall qsort nimmt keine Garantie über dem Element vor dem anderen landet).

Und entscheidend, die Funktion muss dies nur mit den Werten der beiden Argumente tun; Es kennt die Array-Indizes, aus denen sie stammen.

Stattdessen können Sie einen von zwei Ansätzen nehmen:

  • Kopie alle geraden Elemente in ein Array, sortieren das Array eine einfache Vergleichsfunktion, und kopieren Sie dann die Elemente dieses Arrays zurück über die gerade Elemente im ursprünglichen Array.
  • schaffen ein int[][2], dass Geschäfte nicht nur die Werte im Array, aber ihren ursprünglichen Indizes auch. Sie können die Elemente dann so sortieren, dass, wenn einer der Werte ungerade ist, das Element mit dem kleineren ursprünglichen Index zuerst kommt.
+0

Die Vergleichsfunktion kann tatsächlich herausfinden, aus welchen Array-Indizes die Elemente stammen, da sie Zeiger auf die Elemente erhält. Es ist jedoch nicht erlaubt, diese Information zu verwenden: Beispielsweise kann die Vergleichsfunktion für ein Array 'a = {2, 3, 2} 'keine anderen Ergebnisse zurückgeben, wenn sie aufgerufen wird' (& a [0] , & a [1]) 'vs' (& a [2], & a [1]) '; Wenn es andere Ergebnisse zurückgibt, ist das Verhalten undefiniert, und in der Praxis kann es zu einem unsortierten Array oder einer Endlosschleife führen. – Gilles

+0

@Gilles: Die zweite Hälfte Ihres Kommentars (was korrekt ist) widerspricht der ersten Hälfte Ihres Kommentars (was nicht ist). Der Grund dafür, dass die Vergleichsfunktion die Positionen ihrer Argumente nicht berücksichtigen darf und dass sie bizarre Ergebnisse erhalten kann, besteht darin, dass die Positionen ihrer Argumente * nicht * immer die ursprünglichen Positionen dieser Elemente im Array darstellen . Wenn die Sortierung fortschreitet, werden die Elemente verschoben, und natürlich erhält die Vergleichsfunktion immer ihre * aktuellen * Positionen. – ruakh

+0

Sicher, die Vergleichsfunktion ermittelt die Position, an der sich das Element gerade befindet, nicht die Anfangsposition. (Eigentlich nicht - es gibt keine Garantie, dass das Element nicht in den temporären Speicher kopiert wurde - aber in der Praxis ist der Zeiger bei den meisten Implementierungen ein Array-Element.) Aber jemand, der Ihre Antwort liest, könnte zu dem Schluss kommen "hey, ich ' Ich benutze die Pointer-Werte und sorge dafür, dass immer ein Wert zurückgegeben wird, der 'qsort' anweist, die Elemente nicht zu verschieben, wenn eine von ihnen ungerade ist." Das würde nicht funktionieren, weil 'qsort' die Elemente sowieso verschieben oder bereits verschoben haben könnte. – Gilles

Verwandte Themen