Thuật toán sắp xếp nào hoạt động tốt nhất trên hầu hết các dữ liệu được sắp xếp?
Thuật toán sắp xếp nào hoạt động tốt nhất trên hầu hết các dữ liệu được sắp xếp?
Câu trả lời:
Dựa trên phương pháp rất khoa học để xem các gif hoạt hình, tôi sẽ nói các loại Chèn và Bong bóng là những ứng cử viên sáng giá.
Chỉ một vài mặt hàng => SẮC XÁC NHẬN
Các mục hầu hết đã được sắp xếp => SẮC XÁC NHẬN
Quan tâm đến các tình huống xấu nhất => HEAP SORT
Quan tâm đến kết quả trung bình tốt => NHANH CHÓNG
Các vật phẩm được rút ra từ một vũ trụ dày đặc => BucksET SORT
Mong muốn viết càng ít mã càng tốt => SẮC XÁC NHẬN
Timsort là "sự hợp nhất tự nhiên, ổn định, tự nhiên" với " hiệu suất siêu nhiên trên nhiều loại mảng được đặt hàng một phần (ít hơn so với lg (N!), Và chỉ bằng N-1)". Python tích hợp sẵnsort()
đã sử dụng thuật toán này một thời gian, rõ ràng có kết quả tốt. Nó được thiết kế đặc biệt để phát hiện và tận dụng các chuỗi được sắp xếp một phần trong đầu vào, thường xảy ra trong các bộ dữ liệu thực. Thông thường trong thế giới thực, việc so sánh đắt hơn nhiều so với việc hoán đổi các mục trong danh sách, vì người ta thường chỉ trao đổi con trỏ, điều này thường khiến cho bộ đếm thời gian là một lựa chọn tuyệt vời. Tuy nhiên, nếu bạn biết rằng các phép so sánh của bạn luôn rất rẻ (ví dụ, viết chương trình đồ chơi để sắp xếp các số nguyên 32 bit), các thuật toán khác tồn tại có khả năng hoạt động tốt hơn. Cách dễ nhất để tận dụng timsort tất nhiên là sử dụng Python, nhưng vì Python là nguồn mở nên bạn cũng có thể mượn mã. Thay phiên, mô tả ở trên chứa quá nhiều chi tiết để viết triển khai của riêng bạn.
lg(n!)
so với so sánh trên một mảng gần như được sắp xếp, tất cả đều đi xuống O(n)
! | @behrooz: Không có loại so sánh nào có thể có trường hợp trung bình tốt hơnO(n log n)
, và lg(n!)
là O(n log n)
. Vì vậy, trường hợp xấu nhất của timsort là không có triệu chứng không tệ hơn bất kỳ loại so sánh nào khác. Hơn nữa, trường hợp tốt nhất của nó là tốt hơn hoặc bằng bất kỳ loại so sánh nào khác.
Sắp xếp chèn với hành vi sau:
k
trong các khe 1..n
, trước tiên hãy kiểm tra xem el[k] >= el[k-1]
. Nếu vậy, đi đến yếu tố tiếp theo. (Rõ ràng bỏ qua yếu tố đầu tiên.)1..k-1
để xác định vị trí chèn, sau đó di chuyển các phần tử qua. (Bạn chỉ có thể làm điều này nếu giá trị ngưỡng k>T
ở đâu đó T
; với mức nhỏ k
này là quá mức cần thiết.)Phương pháp này làm cho số lượng so sánh ít nhất.
Hãy thử sắp xếp nội tâm. http://en.wikipedia.org/wiki/Introsort
Nó dựa trên quicksort, nhưng nó tránh được trường hợp xấu nhất mà quicksort có đối với các danh sách gần như được sắp xếp.
Thủ thuật là thuật toán sắp xếp này phát hiện các trường hợp quicksort chuyển sang chế độ trong trường hợp xấu nhất và chuyển sang sắp xếp heap hoặc hợp nhất. Các phân vùng gần được sắp xếp được phát hiện bởi một số phương pháp phân vùng không ngây thơ và các phân vùng nhỏ được xử lý bằng cách sử dụng sắp xếp chèn.
Bạn nhận được tốt nhất của tất cả các thuật toán sắp xếp chính cho chi phí của một mã nhiều hơn và phức tạp hơn.Và bạn có thể chắc chắn rằng bạn sẽ không bao giờ gặp phải trường hợp xấu nhất cho dù dữ liệu của bạn trông như thế nào.
Nếu bạn là lập trình viên C ++, hãy kiểm tra thuật toán std :: sort của bạn. Nó có thể đã sử dụng sắp xếp nội tâm.
Splaysort là một phương pháp sắp xếp tối nghĩa dựa trên cây splay , một loại cây nhị phân thích ứng. Splaysort không chỉ tốt cho dữ liệu được sắp xếp một phần, mà còn là dữ liệu được sắp xếp ngược một phần hoặc thực sự là bất kỳ dữ liệu nào có bất kỳ loại đơn đặt hàng nào trước đó. Đó là O (nlogn) trong trường hợp chung và O (n) trong trường hợp dữ liệu được sắp xếp theo một cách nào đó (chuyển tiếp, đảo ngược, ống nội tạng, v.v.).
Ưu điểm lớn của nó so với sắp xếp chèn là nó không hoàn nguyên về hành vi O (n ^ 2) khi dữ liệu hoàn toàn không được sắp xếp, vì vậy bạn không cần phải chắc chắn rằng dữ liệu được sắp xếp một phần trước khi sử dụng .
Nhược điểm của nó là không gian bên trên của cấu trúc cây splay mà nó cần, cũng như thời gian cần thiết để xây dựng và phá hủy cây splay. Nhưng tùy thuộc vào kích thước của dữ liệu và số lượng sắp xếp trước mà bạn mong đợi, chi phí có thể xứng đáng để tăng tốc độ.
Một bài báo về splaysort đã được xuất bản trong Phần mềm - Thực hành & Kinh nghiệm.
Smoothsort của Dijkstra là một loại tuyệt vời trên dữ liệu đã được sắp xếp. Đây là một biến thể heapsort chạy trong trường hợp xấu nhất O (n lg n) và trường hợp tốt nhất O (n). Tôi đã viết một phân tích về thuật toán, trong trường hợp bạn tò mò về cách thức hoạt động của nó.
Hợp nhất tự nhiên là một cách khác thực sự tốt cho điều này - đó là một biến thể hợp nhất từ dưới lên, hoạt động bằng cách coi đầu vào là nối của nhiều phạm vi được sắp xếp khác nhau, sau đó sử dụng thuật toán hợp nhất để nối chúng lại với nhau. Bạn lặp lại quá trình này cho đến khi tất cả các phạm vi đầu vào được sắp xếp. Điều này chạy trong thời gian O (n) nếu dữ liệu đã được sắp xếp và trường hợp xấu nhất O (n lg n). Nó rất thanh lịch, mặc dù trong thực tế, nó không tốt như một số loại thích nghi khác như Timsort hay smoothsort.
Sắp xếp chèn mất thời gian O (n + số lượng đảo ngược).
Một đảo ngược là một cặp (i, j)
như vậy i < j && a[i] > a[j]
. Đó là, một cặp không theo thứ tự.
Một biện pháp "gần như được sắp xếp" là số lần đảo ngược --- người ta có thể lấy "dữ liệu gần như đã sắp xếp" để có nghĩa là dữ liệu có vài lần đảo. Nếu ai đó biết số lượng nghịch đảo là tuyến tính (ví dụ: bạn vừa thêm các phần tử O (1) vào danh sách đã sắp xếp), sắp xếp chèn sẽ mất thời gian O (n).
Như mọi người khác đã nói, hãy cẩn thận với Quicksort ngây thơ - có thể có hiệu suất O (N ^ 2) trên dữ liệu được sắp xếp hoặc gần như sắp xếp. Tuy nhiên, với một thuật toán thích hợp để lựa chọn trục (có thể là ngẫu nhiên hoặc trung bình của ba - xem phần Chọn Xoay cho Quicksort ), Quicksort vẫn sẽ hoạt động bình thường.
Nói chung, khó khăn trong việc lựa chọn các thuật toán như sắp xếp chèn là quyết định khi nào dữ liệu không đủ thứ tự mà Quicksort thực sự sẽ nhanh hơn.
Tôi sẽ không giả vờ có tất cả các câu trả lời ở đây, bởi vì tôi nghĩ rằng để có được câu trả lời thực tế có thể yêu cầu mã hóa các thuật toán và cấu hình chúng theo các mẫu dữ liệu đại diện. Nhưng tôi đã suy nghĩ về câu hỏi này suốt buổi tối, và đây là những gì xảy ra với tôi cho đến nay, và một số dự đoán về những gì hoạt động tốt nhất ở đâu.
Gọi N là tổng số mục, M là số thứ tự.
Sắp xếp bong bóng sẽ phải làm một cái gì đó như 2 * M + 1 đi qua tất cả N vật phẩm. Nếu M rất nhỏ (0, 1, 2?), Tôi nghĩ rằng điều này sẽ rất khó để đánh bại.
Nếu M nhỏ (ít hơn log N), sắp xếp chèn sẽ có hiệu suất trung bình tuyệt vời. Tuy nhiên, trừ khi có một mẹo mà tôi không thấy, nó sẽ có hiệu suất trường hợp xấu nhất. (Phải không? Nếu mục cuối cùng theo thứ tự xuất hiện trước, thì bạn phải chèn từng mục duy nhất, theo như tôi có thể thấy, điều này sẽ giết chết hiệu suất.) Tôi đoán có một thuật toán sắp xếp đáng tin cậy hơn cho việc này trường hợp, nhưng tôi không biết nó là gì.
Nếu M lớn hơn (bằng hoặc lớn hơn log N), sắp xếp nội tâm gần như chắc chắn là tốt nhất.
Ngoại lệ cho tất cả những điều đó: Nếu bạn thực sự biết trước các yếu tố nào chưa được sắp xếp, thì cách tốt nhất của bạn sẽ là kéo các mục đó ra, sắp xếp chúng bằng cách sử dụng sắp xếp nội tâm và hợp nhất hai danh sách được sắp xếp thành một danh sách được sắp xếp. Nếu bạn có thể nhanh chóng tìm ra những mặt hàng không theo thứ tự, đây cũng sẽ là một giải pháp chung tốt - nhưng tôi đã không thể tìm ra một cách đơn giản để làm điều này.
Suy nghĩ thêm (qua đêm): Nếu M + 1 <N / M, thì bạn có thể quét danh sách đang tìm kiếm một N / M liên tiếp được sắp xếp, sau đó mở rộng chạy theo hướng đó để tìm ra ngoài Sắp xếp các mặt hàng. Điều đó sẽ mất nhiều nhất so sánh 2N. Sau đó, bạn có thể sắp xếp các mục chưa sắp xếp và thực hiện hợp nhất được sắp xếp trên hai danh sách. Tổng số so sánh nên ít hơn một cái gì đó như 4N + M log2 (M), sẽ đánh bại bất kỳ thói quen sắp xếp không chuyên biệt nào, tôi nghĩ. (Thậm chí còn nghĩ thêm: điều này khó hơn tôi nghĩ, nhưng tôi vẫn nghĩ nó hợp lý có thể.)
Một cách giải thích khác của câu hỏi là có thể có nhiều mặt hàng không theo thứ tự, nhưng chúng rất gần với nơi chúng nên có trong danh sách. (Hãy tưởng tượng bắt đầu với một danh sách được sắp xếp và hoán đổi mọi vật phẩm khác với danh sách đi sau nó.) Trong trường hợp đó tôi nghĩ rằng sắp xếp bong bóng hoạt động rất tốt - Tôi nghĩ rằng số lần chuyền sẽ tỷ lệ thuận với vị trí xa nhất của một vật phẩm Là. Sắp xếp chèn sẽ hoạt động kém, bởi vì mỗi mục ngoài thứ tự sẽ kích hoạt chèn. Tôi nghi ngờ sắp xếp nội tâm hoặc một cái gì đó như thế cũng sẽ hoạt động tốt.
Nếu bạn đang cần triển khai cụ thể để sắp xếp các thuật toán, cấu trúc dữ liệu hoặc bất cứ thứ gì có liên kết đến ở trên, tôi có thể giới thiệu cho bạn dự án "Cấu trúc dữ liệu và thuật toán" tuyệt vời trên CodePlex không?
Nó sẽ có mọi thứ bạn cần mà không cần phát minh lại bánh xe.
Chỉ là hạt muối nhỏ của tôi.
Bộ sưu tập tốt đẹp các thuật toán sắp xếp cho mục đích này trong các câu trả lời, dường như thiếu Gnome Sort , cũng sẽ phù hợp và có lẽ cần ít nỗ lực thực hiện nhất.
suy ngẫm Hãy thử Heap. Tôi tin rằng nó phù hợp nhất trong các loại O (n lg n).
Sắp xếp bong bóng (hoặc, an toàn hơn, sắp xếp bong bóng hai hướng) có thể lý tưởng cho các danh sách được sắp xếp chủ yếu, mặc dù tôi đặt cược một loại sắp xếp được điều chỉnh (với kích thước khoảng cách ban đầu thấp hơn nhiều) sẽ nhanh hơn một chút khi danh sách không ' t khá hoàn hảo như được sắp xếp. Kết hợp sắp xếp xuống cấp để sắp xếp bong bóng.
tốt, nó phụ thuộc vào trường hợp sử dụng. Nếu bạn biết những yếu tố nào được thay đổi, loại bỏ và chèn sẽ là trường hợp tốt nhất theo như tôi nghĩ.
Tránh xa QuickSort - nó rất không hiệu quả đối với dữ liệu được sắp xếp trước. Sắp xếp chèn xử lý gần như sắp xếp dữ liệu tốt bằng cách di chuyển càng ít giá trị càng tốt.