Hàm qsort() (Quick Sort) trong thư viện chuẩn C (<stdlib.h>) sắp xếp mảng bất kỳ kiểu dữ liệu nào nhờ con trỏ void* và hàm so sánh do người dùng cung cấp.
Chữ ký hàm so sánh
int comparator(const void *p1, const void *p2);
Quy tắc trả về
| Trả về | Ý nghĩa | Thứ tự |
|---|---|---|
< 0 | Phần tử *p1 nhỏ hơn *p2 | p1 đứng trước p2 |
== 0 | Hai phần tử bằng nhau | Giữ nguyên thứ tự (không ổn định) |
> 0 | Phần tử *p1 lớn hơn *p2 | p1 đứng sau p2 |
Triển khai cho các kiểu cơ bản
Số nguyên (int)
int cmp_int(const void *a, const void *b) {
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
// Hoặc gọn: return (arg1 > arg2) - (arg1 < arg2); // Tránh tràn số
}
Số thực (double)
int cmp_double(const void *a, const void *b) {
double arg1 = *(const double*)a;
double arg2 = *(const double*)b;
return (arg1 > arg2) - (arg1 < arg2);
}
Chuỗi (char*)
int cmp_str(const void *a, const void *b) {
const char *arg1 = *(const char**)a;
const char *arg2 = *(const char**)b;
return strcmp(arg1, arg2);
}
Ví dụ: Sắp xếp struct Sách theo giá
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char title[50];
int pages;
float price;
} Book;
int compare_book(const void *a, const void *b) {
Book *b1 = (Book*)a;
Book *b2 = (Book*)b;
// Sắp xếp tăng dần theo price
if (b1->price < b2->price) return -1;
if (b1->price > b2->price) return 1;
return 0;
}
int main() {
Book books[5] = {
{"C Programming", 260, 450.0},
{"DBMS Guide", 850, 775.0},
{"Learn C++", 350, 520.0},
{"Data Structures", 380, 430.0},
{"Learn Python", 500, 300.0}
};
int n = 5;
qsort(books, n, sizeof(Book), compare_book);
printf("%-20s %5s %10s\n", "Tieu de", "Trang", "Gia");
for (int i = 0; i < n; i++) {
printf("%-20s %5d %10.2f\n", books[i].title, books[i].pages, books[i].price);
}
return 0;
}
Kết quả
Tieu de Trang Gia Learn Python 500 300.00 Data Structures 380 430.00 C Programming 260 450.00 Learn C++ 350 520.00 DBMS Guide 850 775.00
Lưu ý quan trọng
- Luôn ép kiểu
const void*về kiểu thực tế bên trong comparator. - Tránh trừ trực tiếp
return *a - *bcho số nguyên — có thể tràn số (overflow) khi giá trị lớn. Dùng so sánh điều kiện hoặc(a>b)-(a. qsortkhông ổn định (unstable): các phần tử bằng nhau có thể đổi chỗ thứ tự.- C++ nên dùng
std::sortvới lambda/comparator functor — an toàn kiểu, nhanh hơn, ổn định (stable_sort).
Nắm vững comparator là chìa khóa để dùng qsort linh hoạt cho mọi cấu trúc dữ liệu.