2016-12-04 4 views
1

配列の偶数だけをソートするために、qsort()関数を使用しようとしています(オッズはその位置に残ります)。例えばqsort():配列の偶数のみをソートする

私が配列している場合:1はなるだろうソート後

5 122 3 26 48 

を:

5 26 3 48 122 

私の直感はabによって指さ両方の数字が偶数のとき、ソートを作ることだけでした。

これは私の試みです:

#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

これは、 'qsort'のような一般的な比較ベースのソートでは考えられません。 – melpomene

+1

copy => sort => writeback – BLUEPIXY

+0

'6 5 4 3 2 1'はどのようにソートされると思いますか? '2 4 6 5 3 1'または' 2 5 4 3 6 1'?つまり、配列内のすべての奇数が同じインデックスになければなりませんか?または、彼らはお互いに同じ相対的なソートが必要なだけですか? – Schwern

答えて

1

あなたのために、比較関数を設計することが不可能だが、あなたはソートそのqsortで、偶数のコピーを作成し、オーバーソートされたサブセットを派遣することができます

#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; 
} 

元の比較関数では、大きな値に失敗した整数を比較するためにトリックを使用しています。 2つの整数の差は、intの範囲外である可能性があります。したがってl - rを返すと、lrの多くの値が正しくない可能性があります。例えばl=INT_MINr=1について

INT_MIN-1が返され、減算が未定義の動作を呼び出し、現在の2の補数アーキテクチャにおいて、INT_MAXINT_MIN < 1であるが正の値を評価する算術オーバーフローを引き起こします。

3

残念ながら、qsortはそのようなものをサポートしていません。最初の引数は、前に、その第二の終わるべきであることを意味し、

  • 負の整数;任意の二つの要素のために、比較関数は、3つの結果のいずれかを返す必要があります
  • 正の整数で、その最初の引数は後を終わるべきであることを意味し、その二。いずれかの順序が罰金であることを意味
  • ゼロ
  • は、(その場合にはqsortは、要素が、他の前に終わるかについて保証するものではありません)。

重要なことに、関数は2つの引数の値のみを使用してこれを行う必要があります。それらが出た配列インデックスを知らない。 、配列に

  • コピーしてもすべての要素を単純な比較関数を使用してその配列をソートし、その後、バック超えるその配列の要素をコピーします。

    代わりに、次の2つのいずれかの方法を取ることができます元の配列の要素さえも含みます。

  • int[][2]を作成して、配列の値だけでなく元のインデックスも保存します。どちらかの値が奇数の場合は、元の索引が小さい要素が先頭になるように要素をソートできます。
+0

比較関数は、要素へのポインタを受け取るので、要素がどの配列インデックスから来るのかを実際に見つけることができます。しかし、この情報を利用することは許されません。たとえば、 'a = {2、3、2}'の配列の場合、 '(&a [0] 、&​​a [1]) 'vs'(&a [2]、&a [1]) ';異なる結果を返す場合、その振る舞いは未定義であり、実際にはソートされていない配列または無限ループになる可能性があります。 – Gilles

+0

@ Gilles:あなたのコメントの後半(正しい)はあなたのコメントの前半と矛盾しています(そうではありません)。比較関数がその引数の位置を考慮することができない理由と、もしそうであれば奇妙な結果を得ることができるのは、引数の位置が常に配列内のそれらの要素の元の位置を表していないからです。並べ替えが進むにつれて、要素が移動し、当然のことながら、比較関数には常に現在の*位置が与えられます。 – ruakh

+0

確かに、比較関数は、最初の位置ではなく要素が現在ある位置を見つけ出します。実際には、要素が一時記憶域にコピーされていないという保証はありませんが、実際にはほとんどの実装でポインタは配列要素にあります。しかし、あなたの答えを読んでいる人は、「ねえ、ポインタの値を利用し、 'qsort'に要素が奇数であれば要素を移動しないように指示する値を常に返します。 'qsort'が要素をとにかく動かすかもしれないし、すでにそれらを動かしたかもしれないので、うまくいかないでしょう。 – Gilles

関連する問題