C ฟังก์ชั่นไลบรารีเพื่อดำเนินการจัดเรียง


99

มีฟังก์ชั่นไลบรารีใด ๆ ในไลบรารีมาตรฐาน C เพื่อทำการเรียงลำดับหรือไม่?


22
@Alexandru, จุดรวมของ SO คือการเป็นสถานที่สำหรับทุกคำถามการเขียนโปรแกรมที่เกี่ยวข้องกับการใด ๆระดับทักษะ คุณคิดว่า Google ควรนำผู้คนไปที่ใดเมื่อพวกเขาใช้ข้อความค้นหาของคุณ พลังที่ต้องการให้มาที่นี่ - เมื่อ SO เป็นลิงก์อันดับต้น ๆ ของ Google สำหรับข้อความค้นหานั้นงานของเราก็เสร็จสิ้น
paxdiablo

1
รหัสเดิมของฉันขี้เกียจและอาจแตกต่างจากสิ่งที่คุณจะพบจากการค้นหาโดย Google อย่างไรก็ตามหลังจากการป้อนข้อมูลชุมชนทั้งหมดคุณมีตัวอย่างของการใช้งานที่ดีของวิธีใช้ qsort
ใหม่

@paxdiablo: หากเป็นเช่นนั้นพวกเขาอาจโฮสต์เอกสาร lib มาตรฐานด้วย - ฉันสงสัยว่าคำถามนี้จะเพิ่มอะไรก็ตามที่อยู่เหนือการอ้างอิงที่เป็นบัญญัติที่นี่ สำหรับบางกรณีที่ซับซ้อนบางที - แต่เพียงเพื่อค้นหาฟังก์ชันพื้นฐาน?
Eamon Nerbonne

4
แม้แต่คำถามเช่นนี้ยังช่วยให้ SO สมบูรณ์ในที่สุดในฐานะฐานข้อมูลที่มีประโยชน์สำหรับผู้เขียนโค้ด
littlegreen

7
นอกจากนี้ในหลาย ๆ กรณีผู้คนไม่รู้ว่าจะค้นหาอะไร ถ้าคุณรู้ว่า c มีฟังก์ชัน sort ชื่อ qsort () documentation สามารถเข้าถึงได้ง่ายอย่างไรก็ตามหากคุณไม่รู้ว่าจะค้นหาทรัพยากรใดที่ควรใช้
อีกครั้ง

คำตอบ:


124

qsort()คือฟังก์ชันที่คุณกำลังมองหา คุณเรียกมันด้วยตัวชี้ไปยังอาร์เรย์ของข้อมูลจำนวนองค์ประกอบในอาร์เรย์ขนาดของแต่ละองค์ประกอบและฟังก์ชันเปรียบเทียบ

มันสร้างความมหัศจรรย์และอาร์เรย์ของคุณจะถูกจัดเรียงเข้าที่ ตัวอย่างดังต่อไปนี้:

#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
คุณควรใช้ sizeof (* x) ในกรณีที่คุณเคยเปลี่ยนประเภทในอนาคต แต่ +1 เพื่อให้ตัวอย่าง
paxdiablo

14
ในกรณีทั่วไปความพยายามที่จะเปรียบเทียบ ints โดยการลบหนึ่งออกจากกันจะส่งผลให้เกิดการล้น ควรอยู่ห่างจากนิสัยที่ไม่ดีนั้นตั้งแต่แรกเริ่ม ใช้return (f > s) - (f < s);
AnT

4
โอเคเปลี่ยนแปลงตามคำแนะนำส่วนใหญ่ ฉันลากเส้น @ChrisL ที่ต้องการ size_t เนื่องจากอาร์เรย์ของฉันไม่เคยใหญ่ขนาดนั้น :-) และ @AndreyT ฉลาดแม้ว่าแฮ็คนั้นจะเป็นอย่างไรฉันชอบให้รหัสของฉันอ่านได้ :-)
paxdiablo

2
@paxdiablo: "แฮ็ก" เป็นสำนวนที่มีชื่อเสียง โปรแกรมเมอร์ที่มีค่าเกลือของเขาจะรู้ทันที ไม่มีผลเสียต่อความสามารถในการอ่าน
AnT

2
@JAamish มาตรฐาน ISO C99 N1256 ใน "7.20.5.2 qsortฟังก์ชัน" จุด 4 "ถ้าสององค์ประกอบเปรียบเทียบว่าเท่ากันลำดับขององค์ประกอบในอาร์เรย์ที่เรียงลำดับผลลัพธ์จะไม่ระบุ"
12431234123412341234123

62

ไลบรารีมาตรฐาน C / C ++ <stdlib.h>มีqsortฟังก์ชัน

นี่ไม่ใช่การใช้งานการเรียงลำดับด่วนที่ดีที่สุดในโลก แต่เร็วพอและใช้งานง่ายมาก ... ไวยากรณ์ที่เป็นทางการของ qsort คือ:

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

สิ่งเดียวที่คุณต้องนำไปใช้คือ Compare_function ซึ่งใช้อาร์กิวเมนต์สองประเภท "const void" ซึ่งสามารถส่งไปยังโครงสร้างข้อมูลที่เหมาะสมจากนั้นส่งกลับค่าหนึ่งในสามค่านี้:

  • ลบถ้า a ควรอยู่ก่อน b
  • 0 ถ้าเท่ากับ b
  • บวกถ้า a ควรอยู่หลัง b

1. การเปรียบเทียบรายการของจำนวนเต็ม :

เพียงแค่โยนและ b เพื่อจำนวนเต็มถ้าx < y, x-yเป็นลบx == y, x-y = 0, x > y, x-yเป็นบวก x-yเป็นวิธีลัดที่จะทำมัน :) ย้อนกลับ*x - *yไป*y - *xสำหรับการเรียงลำดับในการลด / ลำดับย้อนกลับ

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

2. การเปรียบเทียบรายการสตริง :

สำหรับการเปรียบเทียบสตริงคุณต้องมีstrcmpฟังก์ชันภายใน<string.h>lib strcmpจะโดยค่าเริ่มต้น return -ve, 0, ve อย่างเหมาะสม ... เพื่อเรียงลำดับย้อนกลับเพียงแค่ย้อนกลับเครื่องหมายที่ส่งคืนโดย strcmp

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

3. การเปรียบเทียบตัวเลขทศนิยม :

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. การเปรียบเทียบบันทึกตามคีย์ :

บางครั้งคุณต้องจัดเรียงเนื้อหาที่ซับซ้อนมากขึ้นเช่นบันทึก นี่คือวิธีที่ง่ายที่สุดในการใช้qsortไลบรารี

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
คำตอบที่ค่อนข้างดี แต่คำอธิบายของค่าส่งกลับของฟังก์ชันเปรียบเทียบนั้นย้อนกลับ นอกจากนี้ในบางตัวอย่างคุณกำลังทำเคล็ดลับ xy ซึ่งอาจให้ผลลัพธ์ที่ผิดพลาด (และเห็นได้ชัดน้อยกว่าการเปรียบเทียบแบบธรรมดา)
Adrian McCarthy

เท่าที่ฉันกังวลตอนนี้ .. มันใช้ได้กับทุกการแข่งขัน;)
whacko__Cracko

5
เคล็ดลับ xy ใช้ไม่ได้หากความแตกต่างระหว่าง x และ y มากกว่าค่า int ที่แทนค่าได้มากที่สุด ดังนั้นจึงเป็นการดีเมื่อเปรียบเทียบจำนวนบวกสองจำนวน แต่จะล้มเหลวในการเปรียบเทียบเช่น INT_MAX และ -10 โหวตขึ้นเพราะฉันชอบตัวอย่างทั้งหมดของการเรียงลำดับประเภทที่แตกต่างกันมาก
ดักลาส

2
เช่นเดียวกับปัญหาการล้นในทั้งตัวเปรียบเทียบจำนวนเต็มและฟังก์ชันตัวเปรียบเทียบคีย์ฟังก์ชันการเปรียบเทียบสตริงไม่ถูกต้อง เมื่อเรียงลำดับอาร์เรย์ของintค่าที่ส่งผ่านไปเปรียบเทียบมีทั้งปลอมตัวเป็นint * void *เมื่อเรียงลำดับอาร์เรย์ของchar *ดังนั้นค่าที่ส่งผ่านไปเปรียบเทียบมีทั้งปลอมตัวเป็นchar ** ดังนั้นรหัสที่ถูกต้องจะต้องมี:void * int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }
Jonathan Leffler

1
สำหรับการเปรียบเทียบจำนวนเต็มที่ทนต่อการล้นให้พิจารณา if (x > y) return +1; else if (x < y) return -1; else return 0;return (x > y) - (x < y);หรือถ้าคุณต้องการการแสดงออกง่ายแล้ว สิ่งนี้จะประเมินการเปรียบเทียบสองรายการที่ระดับ C เสมอ แต่เครื่องมือเพิ่มประสิทธิภาพอาจหลีกเลี่ยงสิ่งนั้นได้ การลบใช้ไม่ได้กับค่าที่ไม่ได้ลงชื่อ เวอร์ชันแรกใช้งานได้ดีเมื่อคุณกำลังจัดการกับชุดการเปรียบเทียบ - เปรียบเทียบสมาชิกจำนวนเต็ม 2 ตัวของโครงสร้างก่อนและถ้ามันเท่ากันสองคู่ตามด้วยสองสตริงเป็นต้นมีวิธีทำมากกว่าหนึ่งวิธี ใน C เช่นเดียวกับ Perl
Jonathan Leffler

9

แน่นอน: qsort()เป็นการใช้งานการจัดเรียง (ไม่จำเป็นต้อง Quicksort เนื่องจากชื่ออาจแนะนำ)

ลอง man 3 qsort หรืออ่านได้ที่http://linux.die.net/man/3/qsort


7
qsortไม่จำเป็นต้องดำเนินการโดยใช้ Quicksort
James McNellis

6

แม้ว่าจะไม่ได้อยู่ในไลบรารีมาตรฐาน แต่https://github.com/swenson/sortมีไฟล์ส่วนหัวเพียงสองไฟล์ที่คุณสามารถรวมไว้เพื่อเข้าถึงเส้นทางการเรียงลำดับที่รวดเร็วอย่างไม่น่าเชื่อที่หลากหลายดังนี้:

#define SORT_NAME int64
# กำหนด SORT_TYPE int64_t
# กำหนด SORT_CMP (x, y) ((x) - (y))
#include "sort.h"
/ * ขณะนี้คุณสามารถเข้าถึง int64_quick_sort, int64_tim_sort ฯลฯ เช่น * /
int64_quick_sort (arr, 128); / * สมมติว่าคุณมี int * arr หรือ int arr [128]; * /

สิ่งนี้ควรเร็วกว่าไลบรารีมาตรฐานอย่างน้อยสองเท่าqsortเนื่องจากไม่ได้ใช้ตัวชี้ฟังก์ชันและมีตัวเลือกอัลกอริทึมการเรียงลำดับอื่น ๆ ให้เลือกมากมาย

มันอยู่ใน C89 ดังนั้นควรทำงานในคอมไพเลอร์ C ทุกตัว




3

มีหลายฟังก์ชั่นการเรียงลำดับ C stdlib.hที่มีอยู่ในที่มี คุณสามารถทำman 3 qsortบนเครื่องยูนิกซ์เพื่อรับรายชื่อ แต่รวมถึง:

  • กองซ้อน
  • Quicksort
  • ผสาน

7
heapsort และ mergesort ไม่อยู่ในมาตรฐาน
Technowise

3
ไม่ใช่ Quicksort มาตรฐานไม่ได้กำหนดว่าจะใช้อัลกอริทึมใด
paxdiablo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.