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.