Điều gì làm cho một trường hợp xấu để sắp xếp nhanh chóng?


10

Tôi đang tìm hiểu về quicksort và muốn minh họa các mảng khác nhau mà quicksort sẽ có một thời gian khó khăn. Quicksort tôi có trong tâm trí không có sự xáo trộn ngẫu nhiên ban đầu, có 2 phân vùng và không tính toán trung vị.

Tôi đã nghĩ đến ba ví dụ cho đến nay:

[1,2,3,4,5,6,7,8,9,10] - when the array is sorted
[10,9,8,7,6,5,4,3,2,1] - when the array is reversed
[1,1,1,1,1,1,1,1,1,1] - when the array is the same values
[1,1,1,2,2,2,3,3,3,3] - when there are few and unique keys

Chẳng hạn, tôi không chắc lắm về điều này:

[1,3,5,7,9,10,8,6,4,2]

Vậy điều gì làm cho một mảng mà quicksort gặp khó khăn so với một mảng mà nó gần như là lý tưởng?


2
Trục được chọn như thế nào? Bạn đã nêu hai cách nó không được chọn, nhưng không phải cách nó được chọn.
Winston Ewert

Vui lòng đưa ra trường hợp xấu nhất cho QuickSort - khi nào nó có thể xảy ra? trên StackOverflow đọc. Tôi cũng tìm thấy sorting.at là một hình ảnh đẹp của các thuật toán sắp xếp.

@WinstonEwert Pivot được chọn bởi phần tử đầu tiên.
mrQWERTY

@ Renren29 Tôi đã sửa đổi câu hỏi một chút khi cố gắng di chuyển nó để tập trung vào lý do tại sao quicksort sẽ gặp khó khăn với một mảng nhất định thay vì tìm kiếm các mảng ví dụ (Tôi không phải là người đưa ra câu trả lời cho bạn [2,1,2,1,2,1,2,1]và đó là toàn bộ câu trả lời). Mục tiêu của câu hỏi, lý tưởng nhất là trở thành nơi người khác có thể đến và tìm hiểu thêm về lý do tại sao (có câu trả lời) thay vì ví dụ (trong đó có vô số).

Bạn đang chạy quicksort xuống khối 2 yếu tố? Bởi vì việc triển khai trong thế giới thực có xu hướng sử dụng các loại đơn giản hơn cho các khối nhỏ. Ví dụ, so sánh và trao đổi đơn giản hơn rất nhiều so với quicksort cho N = 2.
MSalters

Câu trả lời:


8

Mọi thuật toán sắp xếp đều có trường hợp xấu nhất, và trong nhiều trường hợp trường hợp xấu nhất thực sự tồi tệ nên rất đáng để thử nghiệm cho nó. Vấn đề là, không có trường hợp xấu nhất nào chỉ vì bạn biết thuật toán cơ bản.

Các trường hợp xấu nhất thường gặp bao gồm: đã được sắp xếp; sắp xếp theo chiều ngược lại; gần sắp xếp, một trong số các yếu tố thứ tự; tất cả các giá trị như nhau; tất cả giống nhau ngoại trừ đầu tiên (hoặc cuối cùng) là cao hơn (hoặc thấp hơn). Chúng ta đã từng có một trường hợp trong đó trường hợp xấu nhất là một mô hình răng cưa cụ thể, rất khó dự đoán nhưng khá phổ biến trong thực tế.

Trường hợp xấu nhất đối với quicksort là một trường hợp khiến nó luôn chọn trục xoay xấu nhất có thể, để một trong các phân vùng chỉ có một phần tử duy nhất. Nếu trục là phần tử đầu tiên (lựa chọn xấu) thì dữ liệu đã được sắp xếp hoặc nghịch đảo là trường hợp xấu nhất. Đối với một dữ liệu trung bình của ba trục, tất cả đều giống nhau hoặc chỉ là dữ liệu đầu tiên hoặc cuối cùng là khác nhau.


Đối với quicksort, độ phức tạp trung bình là nlogn và trường hợp xấu nhất là n ^ 2. Lý do đáng để kích hoạt hành vi trường hợp xấu nhất là vì đây cũng là trường hợp tạo ra độ sâu đệ quy lớn nhất. Đối với việc triển khai ngây thơ, độ sâu đệ quy có thể là n, có thể kích hoạt tràn ngăn xếp. Thử nghiệm các tình huống cực đoan khác (bao gồm cả trường hợp tốt nhất) có thể đáng giá vì những lý do tương tự.


Tôi thấy, vì vậy độ lệch chuẩn so với giá trị trung bình thực sự quyết định kết quả phân vùng.
mrQWERTY

"... và trong hầu hết mọi trường hợp, trường hợp xấu nhất thực sự tồi tệ nên rất đáng để thử nghiệm cho nó." . Đó là tranh cãi. Khi tôi nhìn vào bảng này: en.wikipedia.org/wiki/ nam Tôi kết luận rằng đối với hầu hết các thuật toán sắp xếp "tốt" (nghĩa là có O(NlogN)hiệu suất trung bình hoặc tốt hơn), các trường hợp xấu nhất và trung bình có cùng độ phức tạp. Điều đó cho thấy rằng thường KHÔNG đáng để thử nghiệm cho trường hợp xấu nhất. (Cho rằng bài kiểm tra có thể O(N)... hoặc tệ hơn.)
Stephen C

@ Renren29: Trung vị của 3 trục sẽ là đầu tiên hoặc cuối cùng chỉ khi 2 hoặc 3 giá trị giống nhau. SD không đi vào nó.
david.pfx

@StephenC: Nhiều thuật toán 'tốt' bao gồm quicksort có n ^ 2 trường hợp phức tạp nhất. Nhưng xem chỉnh sửa.
david.pfx

@ david.pfx - "Một số" ... CÓ. "Hầu như mọi" ... KHÔNG.
Stephen C

0

Một thuật toán thoát khỏi hầu hết các trường hợp xấu bằng cách sử dụng một trục ngẫu nhiên, loại trừ các phần tử liên tục bằng với một trục khỏi phân vùng và tìm kiếm không đối xứng. Nó tìm kiếm chuyển tiếp một phần tử lớn hơn hoặc bằng với một trục và tìm kiếm ngược một phần tử nhỏ hơn một trục.
Tôi cảm ơn MichaelT, tìm kiếm không đối xứng được đưa ra để giải quyết [2,1,2,1,2,1,2,1].

Kết quả sau đây được tạo bởi hàm qsort_random () của tôi. N = 100.000

usec    call   compare   copy    pattern
80132   62946  1971278   877143  random
47326   57578  1606067   215155  sorted : 0,1,2,3,...,n-1
49927   63578  1628883   338715  sorted in reverse : n-1,n-2,...,2,1,0
55619   63781  1596934   377330  nearly reverse : n-2,n-1,n-4,n-3,...,2,3,0,1
54714   66667  1611454   290392  median-3-killer : n-1,0,1,2,...,n-2
1491    1      99999     4       all values the same : n,n,n,...
1577    1      99999     4       first is higher : n,1,1,1,...
2778    2      156159    10      last is lower : n,n,n,...,n,1
2994    3      199996    100009  a few data : n,...,n,1,...,1
3196    3      199996    50012   zigzag : n,1,n,1,...,n,1
917796  56284  67721985  673356  valley(sawtooth?) : n-1,n-3,...,0,...,n-4,n-2

Hầu hết các trường hợp nhanh hơn một mô hình ngẫu nhiên. Mô hình thung lũng là một trường hợp xấu cho hầu hết các lựa chọn trục.

qsort(3)       usec = 14523   call = 0      compare = 884463    copy = 0
qsort_head()   usec = 138609  call = 99999  compare = 8120991   copy = 1214397
qsort_middle() usec = 664325  call = 99999  compare = 52928111  copy = 1036047
qsort_trad()   usec = 118122  call = 99999  compare = 6476025   copy = 1337523
qsort_random() usec = 295699  call = 58806  compare = 19439952  copy = 732962
qsort_log2()   usec = 66411   call = 63987  compare = 1597455   copy = 944821

qsort_log2 () thoát khỏi trường hợp xấu bằng cách chọn một trục trong các phần tử log2 (N).
qsort (3) sử dụng thư viện GNU là một loại sắp xếp chỉ mục hợp nhất.
qsort_trad () chọn một trục trong các phần tử đầu tiên, giữa và cuối cùng.
qsort_random () và qsort_log2 () không sử dụng trao đổi.
Các chương trình và tập lệnh nguồn C được đăng trong github .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.