Hàm thư viện C để thực hiện sắp xếp


96

Có bất kỳ chức năng thư viện nào có sẵn trong thư viện chuẩn C để thực hiện sắp xếp không?


21
@Alexandru, toàn bộ điểm của SO là trở thành nơi dành cho tất cả các câu hỏi liên quan đến lập trình, ở bất kỳ cấp độ kỹ năng nào . Bạn nghĩ Google nên hướng mọi người đến đâu khi họ sử dụng truy vấn của bạn? Các quyền hạn muốn nó đến đây - khi SO là liên kết hàng đầu của Google cho truy vấn đó, công việc của chúng tôi đã xong.
paxdiablo

1
Mã ban đầu của tôi là lười biếng và có thể rất khác so với những gì bạn sẽ tìm thấy với tìm kiếm trên Google. Tuy nhiên, sau tất cả các đầu vào của cộng đồng, bạn có một ví dụ về việc triển khai tốt cách sử dụng qsort.
chạy lại

@paxdiablo: nếu đúng như vậy, họ cũng có thể chỉ lưu trữ tài liệu lib tiêu chuẩn - Tôi nghi ngờ câu hỏi này sẽ thêm bất cứ điều gì bên trên tham chiếu chuẩn đó, tại đây. Đối với một số trường hợp phức tạp, có lẽ - nhưng chỉ để tìm một hàm cơ bản?
Eamon Nerbonne

4
Ngay cả những câu hỏi như thế này cũng góp phần vào sự hoàn thiện cuối cùng của SO như một cơ sở dữ liệu hữu ích cho các lập trình viên bị mắc kẹt.
thomaspaulb

7
Ngoài ra trong nhiều trường hợp mọi người không biết phải tìm kiếm những gì. Nếu bạn biết rằng c có một hàm sắp xếp có tên qsort (), tài liệu có thể dễ dàng truy cập, tuy nhiên nếu bạn không biết tìm kiếm tài nguyên nào thì nên sử dụng.
chạy lại

Câu trả lời:


119

qsort()là chức năng bạn đang tìm kiếm. Bạn gọi nó bằng một con trỏ đến mảng dữ liệu của bạn, số phần tử trong mảng đó, kích thước của mỗi phần tử và một hàm so sánh.

Nó thực hiện điều kỳ diệu và mảng của bạn được sắp xếp đúng vị trí. Một ví dụ sau:

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

3
Bạn thực sự nên sử dụng sizeof (* x) trong trường hợp bạn thay đổi loại trong tương lai nhưng +1 để cung cấp mẫu.
paxdiablo

12
Trong trường hợp chung, việc cố gắng so sánh các số int bằng cách trừ một số cho một số khác sẽ dẫn đến tràn. Tốt hơn hết bạn nên tránh xa thói quen xấu đó ngay từ đầu. Sử dụngreturn (f > s) - (f < s);
AnT

4
Được rồi, đã thay đổi theo hầu hết các đề xuất. Tôi vẽ đường, @ChrisL, tại cần size_t vì mảng của tôi không bao giờ nhận được rằng lớn :-) Và, @AndreyT, thông minh mặc dù có hack là, tôi thích mã của tôi để có thể đọc :-)
paxdiablo

2
@paxdiablo: "Hack" đó là một thành ngữ đã có cơ sở. Bất kỳ lập trình viên nào đáng giá muối của mình đều nhận ra nó ngay lập tức. Nó không có tác động tiêu cực đến khả năng đọc.
AnT

2
@JAamish ISO C99 Standard N1256, trong "7.20.5.2 qsortHàm" Điểm 4 "Nếu hai phần tử so sánh bằng nhau, thứ tự của chúng trong mảng đã sắp xếp kết quả là không xác định."
12431234123412341234123

60

Thư viện chuẩn C / C ++ <stdlib.h>chứa qsorthàm.

Đây không phải là cách triển khai sắp xếp nhanh nhất trên thế giới nhưng nó đủ nhanh và RẤT DỄ DÀNG được sử dụng ... cú pháp chính thức của qsort là:

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

Điều duy nhất bạn cần triển khai là hàm so sánh, có hai đối số kiểu "const void", có thể được ép kiểu đến cấu trúc dữ liệu thích hợp, rồi trả về một trong ba giá trị sau:

  • phủ định, nếu a phải trước b
  • 0, nếu a bằng b
  • dương, nếu a phải sau b

1. So sánh danh sách các số nguyên :

chỉ đơn giản là cast a và b để số nguyên nếu x < y, x-ylà tiêu cực, x == y, x-y = 0, x > y, x-ylà tích cực x-ylà một cách phím tắt để làm điều đó :) đảo ngược *x - *yđể *y - *xđể phân loại trong việc giảm / thứ tự ngược lại

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

2. So sánh danh sách các chuỗi :

Để so sánh chuỗi, bạn cần strcmphàm bên trong <string.h>lib. strcmpmặc định sẽ trả về -ve, 0, ve thích hợp ... để sắp xếp theo thứ tự ngược lại, chỉ cần đảo ngược dấu hiệu được trả về bởi strcmp

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

3. So sánh số dấu phẩy động :

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. So sánh các bản ghi dựa trên một khóa :

Đôi khi bạn cần sắp xếp những thứ phức tạp hơn, chẳng hạn như bản ghi. Đây là cách đơn giản nhất để làm điều đó bằng cách sử dụng qsortthư viện.

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
Một câu trả lời khá hay, nhưng lời giải thích về giá trị trả về của hàm so sánh là ngược. Ngoài ra, trong một số ví dụ, bạn đang thực hiện thủ thuật xy, có thể đưa ra kết quả bị lỗi (và ít rõ ràng hơn so với phép so sánh đơn giản).
Adrian McCarthy

Chà, theo như tôi quan tâm bây giờ .. điều này phù hợp với mọi cuộc thi;)
whacko__Cracko

5
Thủ thuật xy không hoạt động nếu sự khác biệt giữa x và y lớn hơn giá trị int lớn nhất có thể biểu diễn. Vì vậy, nó là tốt khi so sánh hai số dương, nhưng sẽ thất bại khi so sánh, ví dụ: INT_MAX và -10. Đã ủng hộ mặc dù vì tôi thích tất cả các ví dụ về sắp xếp các loại rất khác nhau.
Douglas

2
Cũng như sự cố tràn trong cả hàm so sánh số nguyên và hàm so sánh khóa, hàm so sánh chuỗi không chính xác. Khi sắp xếp một mảng int, các giá trị được chuyển đến bộ so sánh đều được int *ngụy trang dưới dạng void *. char *Do đó, khi sắp xếp một mảng , các giá trị được chuyển đến bộ so sánh đều được char **ngụy trang dưới dạng void *. Do đó, mã chính xác cần phải được: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
Jonathan Leffler

1
Đối với các so sánh số nguyên có khả năng chống tràn, hãy xem xét if (x > y) return +1; else if (x < y) return -1; else return 0;hoặc nếu bạn muốn một biểu thức đơn giản return (x > y) - (x < y);. Điều này luôn đánh giá hai so sánh ở cấp độ C, nhưng trình tối ưu hóa có thể tránh được điều đó. Phép trừ không hoạt động trên các giá trị không dấu. Phiên bản đầu tiên hoạt động tốt khi bạn xử lý một loạt phép so sánh - trước tiên so sánh 2 phần tử nguyên của một cấu trúc và nếu chúng bằng nhau, thì hai phần nhân đôi, sau đó là hai chuỗi, v.v. Có nhiều cách để làm điều đó, trong C cũng như Perl.
Jonathan Leffler


6

Mặc dù không nằm trong thư viện chuẩn chính xác, https://github.com/swenson/sort chỉ có hai tệp tiêu đề mà bạn có thể đưa vào để có quyền truy cập vào một loạt các quy trình sắp xếp cực kỳ nhanh chóng, như vậy:

#define SORT_NAME Int64 #define SORT_TYPE int64_t #define SORT_CMP ( x , y ) (( x ) - ( y )) #include "sort.h" / * Bây giờ bạn có thể truy cập int64_quick_sort, int64_tim_sort vv, ví dụ * / 
int64_quick_sort ( arr , 128 ); / * Giả sử bạn có một số int * arr hoặc int arr [128]; * /

   
 
  

Điều này phải nhanh hơn ít nhất hai lần so với thư viện tiêu chuẩn qsort, vì nó không sử dụng con trỏ hàm và có nhiều tùy chọn thuật toán sắp xếp khác để lựa chọn.

Nó nằm trong C89, vì vậy về cơ bản sẽ hoạt động trong mọi trình biên dịch C.



4

Sử dụng qsort()trong <stdlib.h>.

@paxdiablo qsort()Chức năng này tuân theo ISO / IEC 9899: 1990 (`` ISO C90 '').


3

Có một số chức năng sắp xếp C có sẵn trong stdlib.h. Bạn có thể thực hiện man 3 qsorttrên máy unix để lấy danh sách nhưng chúng bao gồm:

  • đống
  • sắp xếp nhanh chóng
  • hợp nhất

7
heapsort và mergeort không có trong tiêu chuẩn.
Technowise

3
Quicksort cũng không. Tiêu chuẩn không bắt buộc thuật toán nào được sử dụng.
paxdiablo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.