Функція бібліотеки C для здійснення сортування


97

Чи є в стандартній бібліотеці С якась функція бібліотеки для сортування?


21
@ Александру, вся суть проекту повинна бути місцем для всіх питань, пов'язаних з програмуванням, будь- якого рівня кваліфікації. Куди, на вашу думку, Google повинен направляти людей, коли вони використовують ваш запит? Повноваження, які хочуть, щоб він прийшов сюди - коли SO - це головне посилання Google для цього запиту, наша робота виконана.
paxdiablo

1
Мій оригінальний код був ледачим і, ймовірно, набагато іншим, ніж те, що ви знайшли б при пошуку Google. Однак, після всіх даних спільноти, ви маєте приклад гарної реалізації способу використання qsort.
повтор

@paxdiablo: якщо це так, вони можуть просто розмістити стандартну документацію до бібліотеки - я сумніваюся, це питання додасть щось вище цього канонічного посилання, тут. Можливо, для деяких складних випадків - але просто для пошуку основної функції?
Еймон Нербонна

4
Навіть подібні запитання сприяють повній повноті SO як корисної бази даних для застряглих кодерів.
thomaspaulb

7
Також у багатьох випадках люди не знають, що шукати. Якщо ви знаєте, що c має функцію сортування з назвою qsort (), документація легко доступна, однак якщо ви не знаєте, що шукати, який ресурс слід використовувати.
повтор

Відповіді:


120

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

3
Ви дійсно повинні використовувати sizeof (* x) на випадок, якщо в майбутньому коли-небудь зміните тип, але +1 для надання зразка.
paxdiablo

12
Взагалі, спроба порівняти 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

60

C / C ++ стандартна бібліотека <stdlib.h>містить qsortфункцію.

Це не найкраща реалізація швидкого сортування у світі, але вона досить швидка і ДУЖЕ ЛЕГКА для використання ... формальний синтаксис qsort:

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

Єдине, що вам потрібно реалізувати, це функція compare_, яка приймає два аргументи типу "const void", які можна передати у відповідну структуру даних, а потім повернути одне з цих трьох значень:

  • негативний, якщо a має бути перед b
  • 0, якщо дорівнює b
  • позитивний, якщо a має бути після b

1. Порівняння списку цілих чисел :

просто кинути а й Ь в цілі числа , якщо це 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за замовчуванням поверне -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, який може дати неправильні результати (і менш очевидний, ніж просте порівняння).
Адріан Маккарті,

Ну, що стосується мене зараз ... це працює на кожен конкурс;)
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)); }.
Джонатан Леффлер,

1
Для цілих порівнянь, стійких до переповнення, розгляньте if (x > y) return +1; else if (x < y) return -1; else return 0;, або якщо ви хочете простого виразу, то return (x > y) - (x < y);. Це завжди оцінює два порівняння на рівні С, але оптимізатор може цього уникнути. Віднімання не працює для беззнакових значень. Перша версія добре працює, коли ви маєте справу з низкою порівнянь - порівняння спочатку 2 цілочисельних елементів структури, а якщо вони рівні, то дві подвійні, а потім дві рядки і т. Д. Існує більше одного способу зробити це, в C, а також Perl.
Джонатан Леффлер,


6

Хоча це не в стандартній бібліотеці, https://github.com/swenson/sort має лише два файли заголовків, які ви можете включити, щоб отримати доступ до широкого кола неймовірно швидких маршрутів сортування, наприклад:

#define SORT_NAME int64SORT_NAME int64
#define SORT_TYPE int64_t#define SORT_TYPE int64_t
#define SORT_CMP (x, y) ((x) - (y))#define SORT_CMP ( x , y ) (( x ) - ( y ))   
#include "sort.h"#include "sort.h" 
/ * Тепер у вас є доступ до int64_quick_sort, int64_tim_sort тощо, наприклад, * // * Тепер у вас є доступ до int64_quick_sort, int64_tim_sort тощо, наприклад, * /
int64_quick_sort (arr, 128); / * Припускає, що у вас є int * arr або int arr [128]; * /( обр. , 128 ); / * Припускає, що у вас є якийсь int * arr або int arr [128]; * /  

Це повинно бути принаймні вдвічі швидшим за стандартну бібліотеку qsort, оскільки вона не використовує покажчики функцій і має безліч інших варіантів алгоритму сортування.

Це в C89, тому в основному повинен працювати кожен компілятор C.



4

Використовуйте qsort()в <stdlib.h>.

@paxdiablo qsort()Функція відповідає ISO / IEC 9899: 1990 (`` ISO C90 '').


3

Є кілька C сортуванні функції , доступної в stdlib.h. Ви можете зробити це man 3 qsortна машині Unix, щоб отримати їх список, але вони включають:

  • грона
  • швидкий кіркот
  • злиття

7
сортовий сорт і злиття не входять у стандарт.
Technowise

3
Також не є швидким сортуванням. Стандарт не вимагає, який алгоритм використовується.
paxdiablo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.