Nó ổn định và có độ phức tạp thời gian là O (n). Nó phải nhanh hơn các thuật toán như Quicksort và Mergesort, nhưng tôi hầu như không bao giờ thấy nó được sử dụng.
Nó ổn định và có độ phức tạp thời gian là O (n). Nó phải nhanh hơn các thuật toán như Quicksort và Mergesort, nhưng tôi hầu như không bao giờ thấy nó được sử dụng.
Câu trả lời:
Không giống như sắp xếp cơ số, quicksort là phổ quát, trong khi sắp xếp cơ số chỉ hữu ích cho việc sửa các khóa số nguyên có độ dài.
Ngoài ra, bạn phải hiểu rằng O (f (n)) thực sự có nghĩa là theo thứ tự K * f (n), trong đó K là một hằng số tùy ý. Đối với sắp xếp cơ số, K này xảy ra khá lớn (ít nhất là thứ tự số bit trong số nguyên được sắp xếp), mặt khác quicksort có một trong những K thấp nhất trong số tất cả các thuật toán sắp xếp và độ phức tạp trung bình của n * log (n). Do đó, trong kịch bản đời thực, quicksort sẽ rất nhanh hơn so với radix sort.
Hầu hết các thuật toán sắp xếp là mục đích chung. Với một chức năng so sánh, chúng hoạt động trên mọi thứ và các thuật toán như Quicksort và Heapsort sẽ sắp xếp với bộ nhớ phụ O (1).
Phân loại Radix là chuyên ngành hơn. Bạn cần một khóa cụ thể theo thứ tự từ điển. Bạn cần một thùng cho mỗi ký hiệu có thể có trong khóa và các thùng cần chứa nhiều hồ sơ. (Cách khác, bạn cần một mảng lớn sẽ chứa mọi giá trị khóa có thể.) Bạn có thể sẽ cần nhiều bộ nhớ hơn để thực hiện sắp xếp cơ số và bạn sẽ sử dụng nó một cách ngẫu nhiên. Cả hai điều này đều không tốt cho các máy tính hiện đại, vì bạn có thể gặp lỗi trang như Quicksort sẽ bị lỗi bộ nhớ cache.
Cuối cùng, mọi người nói chung không viết các thuật toán sắp xếp của riêng họ nữa. Hầu hết các ngôn ngữ đều có các phương tiện thư viện để sắp xếp, và điều đúng đắn thường làm là sử dụng chúng. Vì loại radix không được áp dụng phổ biến, thường phải được điều chỉnh theo mục đích sử dụng thực tế và sử dụng nhiều bộ nhớ bổ sung, thật khó để đưa nó vào chức năng thư viện hoặc mẫu.
O(n^2)
bộ nhớ trong trường hợp xấu nhất do n
các cuộc gọi đệ quy trên các phân vùng bên trái và bên phải. Nếu việc triển khai sử dụng tối ưu hóa đệ quy đuôi, điều đó có thể được hạ xuống chỉ O(n)
vì các lệnh gọi đến phân vùng bên phải sẽ không cần thêm dung lượng. ( en.wikipedia.org/wiki/Quicksort#Space_complexity )
S(n) \in O(n)
không gian để sắp xếp với cơ số, tức là tương tự như cho heap hoặc sắp xếp nhanh.
n^2
quicksort nữa, nhưng O(log n)
...
Thật hiếm khi các khóa bạn sắp xếp thực sự là các số nguyên trong một phạm vi thưa thớt, đã biết. Thông thường bạn có các trường chữ cái, trông giống như chúng sẽ hỗ trợ sắp xếp không so sánh, nhưng vì các chuỗi trong thế giới thực không được phân bổ đều trên bảng chữ cái, nên về mặt lý thuyết, nó không hoạt động tốt như vậy.
Những lần khác, tiêu chí chỉ được xác định một cách vận hành (được đưa ra hai bản ghi, bạn có thể quyết định cái nào đến trước, nhưng bạn không thể đánh giá mức độ "xa" của một bản ghi bị cô lập). Vì vậy, phương pháp này thường không được áp dụng, ít áp dụng hơn bạn có thể tin hoặc không nhanh hơn O (n * log (n)).
Tôi sử dụng nó mọi lúc, thực tế nhiều hơn các loại dựa trên so sánh, nhưng tôi thừa nhận là một kẻ kỳ quặc hoạt động với số lượng nhiều hơn bất kỳ thứ gì khác (tôi hầu như không bao giờ làm việc với các chuỗi, và chúng thường được thực hiện nếu tại thời điểm đó radix sắp xếp có thể hữu ích một lần nữa để lọc ra các bản sao và tính toán các giao điểm thiết lập; tôi thực tế không bao giờ thực hiện so sánh từ điển).
Một ví dụ cơ bản là các điểm sắp xếp cơ số theo một thứ nguyên nhất định như là một phần của phân chia tìm kiếm hoặc phân chia trung bình hoặc một cách nhanh chóng để phát hiện các điểm trùng khớp, phân đoạn độ sâu hoặc sắp xếp một chuỗi các chỉ mục được sử dụng trong nhiều vòng để cung cấp quyền truy cập thân thiện hơn vào bộ đệm các mẫu (không quay đi quay lại trong bộ nhớ chỉ để quay lại lần nữa và tải lại cùng bộ nhớ vào một dòng bộ đệm). Có một ứng dụng rất rộng ít nhất là trong miền của tôi (đồ họa máy tính) chỉ để sắp xếp trên các phím số 32 bit và 64 bit có kích thước cố định.
Một điều tôi muốn nói và nói rằng loại radix có thể hoạt động trên các số và dấu phẩy động, mặc dù rất khó để viết một phiên bản FP dễ mang theo nhất có thể. Ngoài ra, trong khi đó là O (n * K), K chỉ phải là số byte có kích thước khóa (ví dụ: một triệu số nguyên 32 bit thường sẽ có các đường truyền có kích thước 4 byte nếu có 2 ^ 8 mục trong nhóm ). Mẫu truy cập bộ nhớ cũng có xu hướng thân thiện với bộ đệm hơn rất nhiều so với quicksorts mặc dù nó cần một mảng song song và một mảng xô nhỏ (thứ hai thường có thể vừa vặn trên ngăn xếp). QS có thể thực hiện 50 triệu giao dịch hoán đổi để sắp xếp một mảng gồm một triệu số nguyên với các mẫu truy cập ngẫu nhiên lẻ tẻ. Sắp xếp cơ số có thể làm điều đó trong 4 tuyến tính, thân thiện với bộ nhớ cache vượt qua dữ liệu.
Tuy nhiên, việc thiếu nhận thức về việc có thể làm điều này với một K nhỏ, trên các số âm cùng với dấu phẩy động, rất có thể đóng góp đáng kể vào việc thiếu sự phổ biến của các loại cơ số.
Theo ý kiến của tôi về lý do tại sao mọi người không sử dụng nó thường xuyên hơn, có thể phải làm với nhiều tên miền thường không có nhu cầu sắp xếp số hoặc sử dụng chúng làm khóa tìm kiếm. Tuy nhiên, chỉ dựa trên kinh nghiệm cá nhân của tôi, nhiều đồng nghiệp cũ của tôi cũng đã không sử dụng nó trong trường hợp nó hoàn toàn phù hợp, và một phần vì họ không biết rằng nó có thể được tạo ra để làm việc trên FP và phủ định. Vì vậy, ngoài việc nó chỉ hoạt động trên các loại số, nó thường được cho là thậm chí ít được áp dụng hơn so với thực tế. Tôi cũng sẽ không sử dụng nó nhiều như vậy nếu tôi nghĩ nó không hoạt động trên các số có dấu phẩy động và số nguyên âm.
Một số điểm chuẩn:
Sorting 10000000 elements 3 times...
mt_sort_int: {0.135 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
mt_radix_sort: {0.228 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
std::sort: {1.697 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
qsort: {2.610 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
Và đó chỉ là với cách triển khai ngây thơ của tôi ( mt_sort_int
cũng là sắp xếp cơ số nhưng với một nhánh mã nhanh hơn được cho rằng nó có thể giả sử khóa là một số nguyên). Hãy tưởng tượng một triển khai tiêu chuẩn được viết bởi các chuyên gia có thể nhanh như thế nào.
Trường hợp duy nhất mà tôi thấy loại radix có giá thấp hơn so với dựa trên so sánh rất nhanh của C ++ std::sort
là cho một số phần tử rất nhỏ, ví dụ 32, tại thời điểm đó tôi tin rằng std::sort
bắt đầu sử dụng các loại phù hợp hơn cho số lượng phần tử nhỏ nhất như heapsorts hoặc chèn các loại, mặc dù tại thời điểm đó việc thực hiện của tôi chỉ sử dụng std::sort
.
Thêm một lý do: Ngày nay việc sắp xếp thường được thực hiện với thói quen sắp xếp do người dùng cung cấp kèm theo logic sắp xếp do trình biên dịch cung cấp. Với một loại cơ số, điều này sẽ phức tạp hơn đáng kể và thậm chí còn tệ hơn khi thói quen sắp xếp hành động theo nhiều khóa có độ dài thay đổi. (Nói, tên và ngày sinh.)
Trong thế giới thực, tôi đã thực sự thực hiện một loại cơ số một lần. Đó là vào thời xưa khi bộ nhớ bị hạn chế, tôi không thể mang tất cả dữ liệu của mình vào bộ nhớ cùng một lúc. Điều đó có nghĩa là số lượng truy cập vào dữ liệu quan trọng hơn nhiều so với O (n) so với O (n log n). Tôi đã thực hiện một lần chuyển dữ liệu phân bổ từng bản ghi vào một thùng (theo danh sách các bản ghi trong đó có thùng, không thực sự di chuyển bất cứ thứ gì.) Đối với mỗi thùng không trống (khóa sắp xếp của tôi là văn bản, sẽ có rất nhiều thùng rỗng) Tôi đã kiểm tra xem tôi có thực sự có thể mang dữ liệu vào bộ nhớ hay không - nếu có, hãy mang dữ liệu vào và sử dụng quicksort. Nếu không, xây dựng tệp tạm thời chỉ chứa các mục trong thùng và gọi đệ quy thường quy. (Trong thực tế, một số thùng sẽ tràn ra.) Điều này gây ra hai lần đọc hoàn chỉnh và một lần ghi hoàn chỉnh vào bộ lưu trữ mạng và khoảng 10% trong số này cho bộ nhớ cục bộ.
Ngày nay, những vấn đề dữ liệu lớn như vậy rất khó chạy, tôi có thể sẽ không bao giờ viết bất cứ điều gì như vậy nữa. (Nếu tôi phải đối mặt với cùng một dữ liệu hiện nay, tôi chỉ cần chỉ định HĐH 64 bit, thêm RAM nếu bạn gặp sự cố trong trình chỉnh sửa đó.)
Nếu tất cả các tham số của bạn đều là số nguyên và nếu bạn có hơn 1024 tham số đầu vào, thì sắp xếp cơ số luôn nhanh hơn.
Tại sao?
Complexity of radix sort = max number of digits x number of input parameters.
Complexity of quick sort = log(number of input parameters) x number of input parameters
Vì vậy, sắp xếp radix nhanh hơn khi
log(n)> max num of digits
Số nguyên tối đa trong Java là 2147483647. Dài 10 chữ số
Vì vậy, sắp xếp radix luôn nhanh hơn khi
log(n)> 10
Do đó, sắp xếp radix luôn nhanh hơn khi
n>1024