Sắp xếp một vector
hoặc bất kỳ phạm vi áp dụng (trình lặp đầu vào có thể thay đổi) nào khác X
có thể đạt được bằng cách sử dụng các phương pháp khác nhau, đặc biệt là sử dụng các thuật toán thư viện tiêu chuẩn như
Vì hầu hết các kỹ thuật, để có được thứ tự tương đối của X
các yếu tố, đã được đăng, tôi sẽ bắt đầu bằng một số lưu ý về "tại sao" và "khi nào" để sử dụng các phương pháp khác nhau.
Cách tiếp cận "tốt nhất" sẽ phụ thuộc vào các yếu tố khác nhau:
- Là sắp xếp các phạm vi của
X
các đối tượng là một nhiệm vụ phổ biến hoặc hiếm gặp (các phạm vi như vậy sẽ được sắp xếp một vị trí khác nhau trong chương trình hoặc bởi người dùng thư viện)?
- Là sự sắp xếp cần thiết "tự nhiên" (dự kiến) hoặc có nhiều cách để loại có thể được so sánh với chính nó?
- Là hiệu suất là một vấn đề hoặc nên sắp xếp phạm vi của
X
các đối tượng là hoàn hảo?
Nếu sắp xếp các phạm vi X
là một nhiệm vụ phổ biến và sắp xếp đạt được sẽ được dự kiến (nghĩa là X
chỉ bao bọc một giá trị cơ bản duy nhất) thì có thể sẽ bị quá tải operator<
vì nó cho phép sắp xếp mà không có bất kỳ lỗi nào (như chuyển chính xác các bộ so sánh phù hợp) và liên tục mang lại kết quả mong đợi các kết quả.
Nếu sắp xếp là một nhiệm vụ chung hoặc có thể được yêu cầu trong các ngữ cảnh khác nhau, nhưng có nhiều tiêu chí có thể được sử dụng để sắp xếp X
các đối tượng, tôi sẽ tìm Functor ( operator()
hàm quá tải của các lớp tùy chỉnh) hoặc con trỏ hàm (tức là một hàm functor / hàm để đặt hàng từ vựng và một số khác cho trật tự tự nhiên).
Nếu sắp xếp phạm vi loại X
không phổ biến hoặc không có khả năng trong các bối cảnh khác, tôi có xu hướng sử dụng lambdas thay vì làm lộn xộn bất kỳ không gian tên nào có nhiều chức năng hoặc loại.
Điều này đặc biệt đúng nếu cách sắp xếp không "rõ ràng" hoặc "tự nhiên" theo một cách nào đó. Bạn có thể dễ dàng nhận được logic đằng sau việc đặt hàng khi nhìn vào lambda được áp dụng tại chỗ trong khi đó operator<
là điều khó hiểu ngay từ cái nhìn đầu tiên và bạn phải xem định nghĩa để biết logic nào sẽ được áp dụng.
Tuy nhiên, lưu ý rằng một operator<
định nghĩa duy nhất là một điểm thất bại trong khi nhiều lambas là nhiều điểm thất bại và cần thận trọng hơn.
Nếu định nghĩa operator<
không khả dụng khi sắp xếp xong / mẫu sắp xếp được biên dịch, trình biên dịch có thể bị buộc phải thực hiện một cuộc gọi hàm khi so sánh các đối tượng, thay vì nội tuyến logic có thể là một nhược điểm nghiêm trọng (ít nhất là khi tối ưu hóa thời gian liên kết / tạo mã không được áp dụng).
Các cách để đạt được sự so sánh class X
để sử dụng các thuật toán sắp xếp thư viện tiêu chuẩn
Hãy để std::vector<X> vec_X;
vàstd::vector<Y> vec_Y;
1. Quá tải T::operator<(T)
hoặc operator<(T, T)
sử dụng các mẫu thư viện tiêu chuẩn không mong đợi chức năng so sánh.
Thành viên quá tải operator<
:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
hoặc miễn phí operator<
:
struct Y {
int j{};
};
bool operator<(Y const &l, Y const &r) { return l.j < r.j; }
// ...
std::sort(vec_Y.begin(), vec_Y.end());
2. Sử dụng một con trỏ hàm với chức năng so sánh tùy chỉnh làm tham số chức năng sắp xếp.
struct X {
int i{};
};
bool X_less(X const &l, X const &r) { return l.i < r.i; }
// ...
std::sort(vec_X.begin(), vec_X.end(), &X_less);
3. Tạo bool operator()(T, T)
quá tải cho một loại tùy chỉnh có thể được thông qua dưới dạng functor so sánh.
struct X {
int i{};
int j{};
};
struct less_X_i
{
bool operator()(X const &l, X const &r) const { return l.i < r.i; }
};
struct less_X_j
{
bool operator()(X const &l, X const &r) const { return l.j < r.j; }
};
// sort by i
std::sort(vec_X.begin(), vec_X.end(), less_X_i{});
// or sort by j
std::sort(vec_X.begin(), vec_X.end(), less_X_j{});
Các định nghĩa đối tượng hàm có thể được viết chung chung hơn một chút bằng C ++ 11 và các mẫu:
struct less_i
{
template<class T, class U>
bool operator()(T&& l, U&& r) const { return std::forward<T>(l).i < std::forward<U>(r).i; }
};
có thể được sử dụng để sắp xếp bất kỳ loại nào với sự i
hỗ trợ của thành viên <
.
4. Truyền một bao ẩn danh (lambda) làm tham số so sánh cho các hàm sắp xếp.
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
Trong đó C ++ 14 cho phép biểu thức lambda chung hơn nữa:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
mà có thể được bọc trong một macro
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
làm cho việc tạo so sánh thông thường khá trơn tru:
// sort by i
std::sort(v.begin(), v.end(), COMPARATOR(l.i < r.i));
// sort by j
std::sort(v.begin(), v.end(), COMPARATOR(l.j < r.j));