Sıralama gerçekleştirmek için C kütüphanesi işlevi


99

C standart kitaplığında sıralama yapmak için herhangi bir kitaplık işlevi var mı?


22
@Alexandru, SO'nun tüm noktası , herhangi bir beceri düzeyindeki programlama ile ilgili tüm sorular için bir yer olmaktır . Sorgunuzu kullandıklarında Google'ın insanları nereye yönlendirmesi gerektiğini düşünüyorsunuz? Buraya gelmesini isteyen güçler - SO bu sorgu için en iyi Google bağlantısı olduğunda, işimiz bitmiş demektir.
— paxdiablo

1
Orijinal kodum tembeldi ve muhtemelen bir Google aramasında bulacağınızdan çok farklıydı. Ancak tüm topluluk girdilerinin ardından, qsort'un nasıl kullanılacağına dair iyi bir uygulama örneğiniz var.
— yeniden göster

@paxdiablo: Eğer durum buysa, standart kitaplık belgelerini de barındırabilirler - bu sorunun burada bu kanonik referansın üstüne herhangi bir şey ekleyeceğinden şüpheliyim. Bazı karmaşık durumlar için, belki - ama sadece temel bir işlevi bulmak için?
— Eamon Nerbonne

4
Bunun gibi sorular bile sıkışmış kodlayıcılar için yararlı bir veritabanı olarak SO'nun nihai bütünlüğüne katkıda bulunur.
— littlegreen

7
Ayrıca çoğu durumda insanlar ne arayacaklarını bilemezler. C'nin qsort () adında bir sıralama işlevi olduğunu biliyorsanız, belgelere kolayca erişilebilir, ancak hangi kaynağı kullanacağınızı bilmiyorsanız hangi kaynağı kullanacağınızı bilmiyorsanız.
— yeniden göster

Yanıtlar:


124

qsort()aradığınız işlev. Onu veri dizinize, o dizideki elemanların sayısına, her bir elemanın boyutuna ve bir karşılaştırma fonksiyonuna bir işaretçi ile çağırırsınız.

Sihrini yapar ve diziniz yerinde sıralanır. Bir örnek aşağıdaki gibidir:

#include <stdio.h>
#include <stdlib.h>
int comp (const void * elem1, const void * elem2) 
{
    int f = *((int*)elem1);
    int s = *((int*)elem2);
    if (f > s) return  1;
    if (f < s) return -1;
    return 0;
}
int main(int argc, char* argv[]) 
{
    int x[] = {4,5,2,3,1,0,9,8,6,7};

    qsort (x, sizeof(x)/sizeof(*x), sizeof(*x), comp);

    for (int i = 0 ; i < 10 ; i++)
        printf ("%d ", x[i]);

    return 0;
}

4
İleride türü değiştirirseniz gerçekten sizeof (* x) kullanmalısınız, ancak bir örnek sağlamak için +1 kullanmalısınız.
— paxdiablo

14
Genel durumda, birbirlerinden birini çıkararak girişleri karşılaştırma girişimi taşmaya neden olacaktır. Bu kötü alışkanlıktan en başından uzak durmak daha iyidir. Kullanımreturn (f > s) - (f < s);
— AnT

4
Tamam, çoğu öneriye göre değiştirildi. Dizilerim asla bu kadar büyük olmayacağından size_t'ye ihtiyaç duyarak @ChrisL çizgisini çiziyorum :-) Ve @AndreyT, bu hack akıllıca olsa da, kodumun okunabilir olmasını tercih ederim :-)
— paxdiablo

2
@paxdiablo: Bu "hack" köklü bir deyimdir. Zevkine değecek herhangi bir programcı bunu hemen tanır. Okunabilirlik üzerinde olumsuz bir etkisi yoktur.
— AnT

2
@JAamish ISO C99 Standardı N1256, "7.20.5.2 qsort" Nokta 4 "işlevi İki eleman eşit olarak karşılaştırılırsa, sonuçta ortaya çıkan sıralı dizideki sırası belirtilmez."
— 12431234123412341234123

62

C / C ++ standart kitaplığı işlevi <stdlib.h>içerir qsort.

Bu dünyadaki en iyi hızlı sıralama uygulaması değil, ancak yeterince hızlı ve kullanımı ÇOK KOLAY ... qsort'un resmi sözdizimi:

qsort(<arrayname>,<size>,sizeof(<elementsize>),compare_function);

Gerçekleştirmeniz gereken tek şey, uygun veri yapısına dönüştürülebilen "const void" türünde iki bağımsız değişken alan ve ardından şu üç değerden birini döndüren karşılaştırma_işlevidir:

  • negatif, eğer a b'den önce olmalıysa
  • 0, eğer a eşitse
  • pozitif, eğer a, b'den sonra olmalıysa

1. Tam sayılar listesinin karşılaştırılması :

sadece, eğer tam sayılara a ve b dökme x < y, x-ynegatif olduğu x == y, x-y = 0, x > y, x-ypozitiftir x-ybu ters :) yapmak için bir kısayol yöntemdir *x - *yiçin *y - *xazalan sıralama için / geri sipariş

int compare_function(const void *a,const void *b) {
int *x = (int *) a;
int *y = (int *) b;
return *x - *y;
}

2. Bir dizi listesinin karşılaştırılması :

Dizgeyi karşılaştırmak için lib strcmpiçinde işleve ihtiyacınız var <string.h>. strcmpvarsayılan olarak -ve, 0, ve uygun bir şekilde dönecektir ... ters sırayla sıralamak için, strcmp tarafından döndürülen işareti ters çevirmek yeterlidir

#include <string.h>
int compare_function(const void *a,const void *b) {
return (strcmp((char *)a,(char *)b));
}

3. Kayan noktalı sayıların karşılaştırılması :

int compare_function(const void *a,const void *b) {
double *x = (double *) a;
double *y = (double *) b;
// return *x - *y; // this is WRONG...
if (*x < *y) return -1;
else if (*x > *y) return 1; return 0;
}

4. Kayıtları bir anahtara göre karşılaştırma :

Bazen kayıt gibi daha karmaşık şeyleri sıralamanız gerekir. qsortKitaplığı kullanarak yapmanın en basit yolu burada .

typedef struct {
int key;
double value;
} the_record;

int compare_function(const void *a,const void *b) {
the_record *x = (the_record *) a;
the_record *y = (the_record *) b;
return x->key - y->key;
}

2
Oldukça iyi bir cevap, ancak karşılaştırma işlevinin dönüş değerinin açıklaması geriye doğrudur. Ayrıca, bazı örneklerde xy numarasını yapıyorsunuz, bu da hatalı sonuçlar verebilir (ve basit bir karşılaştırmadan daha az açıktır).
— Adrian McCarthy

Şimdi endişelendiğim kadarıyla .. bu her yarışma için geçerli;)
— whacko__Cracko

5
Xy numarası, x ve y arasındaki fark gösterilebilir en büyük int değerinden büyükse işe yaramaz. Dolayısıyla, iki pozitif sayıyı karşılaştırırken sorun yok, ancak örneğin INT_MAX ve -10'u karşılaştırmada başarısız olacaktır. Yine de olumlu oy verildi çünkü çok farklı türleri sıralamanın tüm örneklerini seviyorum.
— Douglas

2
Hem tamsayı karşılaştırıcı hem de anahtar karşılaştırıcı işlevlerindeki taşma sorununun yanı sıra, dize karşılaştırma işlevi yanlıştır. Bir diziyi sıralarken int, karşılaştırıcıya iletilen değerlerin her ikisi de olarak int *gizlenir void *. Bu char *nedenle, bir dizi sıralarken , karşılaştırıcıya iletilen değerlerin her ikisi de olarak char **gizlenir void *. Bu nedenle, doğru kod olması gerekiyor: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
— Jonathan Leffler

1
Taşmaya dirençli tamsayı karşılaştırmaları için, düşünün if (x > y) return +1; else if (x < y) return -1; else return 0;veya basit bir ifade istiyorsanız, o zaman return (x > y) - (x < y);. Bu her zaman C düzeyinde iki karşılaştırmayı değerlendirir, ancak optimize edici bundan kaçınabilir. Çıkarma, işaretsiz değerlerde çalışmaz. İlk sürüm, bir dizi karşılaştırma ile uğraşırken iyi çalışır - önce bir yapının 2 tam sayı üyesini ve eşitlerse, sonra iki çift, sonra iki dizgiyi karşılaştırır. Bunu yapmanın birden fazla yolu vardır, C ve Perl olarak.
— Jonathan Leffler


6

Tam olarak standart kitaplıkta olmasa da, https://github.com/swenson/sort , çok çeşitli inanılmaz hızlı sıralama rotalarına erişmek için ekleyebileceğiniz yalnızca iki başlık dosyasına sahiptir, örneğin:

#define SORT_NAME int64
#define SORT_TYPE int64_t
# tanımla SORT_CMP (x, y) ((x) - (y))
#include "sort.h"
/ * Artık int64_quick_sort, int64_tim_sort vb. Erişiminiz var, örneğin, * /
int64_quick_sort (dizi, 128); / * Bazı int * arr veya int arr [128] 'a sahip olduğunuzu varsayar; * /

Bu, standart kitaplığın en az iki katı hızlı olmalıdır qsort, çünkü işlev işaretçileri kullanmaz ve aralarından seçim yapabileceğiniz birçok başka sıralama algoritması seçeneği vardır.

C89'da, bu nedenle temelde her C derleyicisinde çalışmalıdır.



4

Kullan qsort()içinde <stdlib.h>.

@paxdiablo qsort()ISO / IEC 9899 fonksiyon uygundur: 1990 ( `` ISO C90 '').


3

İçinde kullanılabilen birkaç C sıralama işlevi vardır stdlib.h. man 3 qsortBunların bir listesini almak için bir unix makinesinde yapabilirsiniz , ancak şunları içerir:

  • yığın
  • hızlı sıralama
  • birleşme

7
heapsort ve mergesort standartta değildir.
— Technowise

3
Hızlı sıralama da değil. Standart, hangi algoritmanın kullanıldığını belirlemez.
— paxdiablo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.