Kích thước sư phạm
Do tính đơn giản của nó, phương pháp phân vùng của Lomuto có thể dễ thực hiện hơn. Có một giai thoại hay trong Lập trình viên ngọc của Jon Bentley về Sắp xếp:
Hầu hết các cuộc thảo luận về Quicksort đều sử dụng sơ đồ phân vùng dựa trên hai chỉ số tiếp cận [...] [tức là Hoare]. Mặc dù ý tưởng cơ bản của sơ đồ đó rất đơn giản, tôi luôn thấy các chi tiết khó hiểu - tôi đã từng dành phần tốt hơn trong hai ngày để theo đuổi một lỗi ẩn trong một vòng lặp phân vùng ngắn. Một độc giả của một bản thảo sơ bộ đã phàn nàn rằng phương pháp hai chỉ số trên thực tế đơn giản hơn Lomuto và đã phác thảo một số mã để đưa ra quan điểm của mình; Tôi đã ngừng tìm kiếm sau khi tôi tìm thấy hai lỗi.
Kích thước hiệu suất
Để sử dụng thực tế, dễ thực hiện có thể được hy sinh vì hiệu quả. Trên cơ sở lý thuyết, chúng ta có thể xác định số lượng so sánh phần tử và hoán đổi để so sánh hiệu suất. Ngoài ra, thời gian chạy thực tế sẽ bị ảnh hưởng bởi các yếu tố khác, chẳng hạn như hiệu suất bộ đệm và các dự đoán sai chi nhánh.
Như được hiển thị bên dưới, các thuật toán hoạt động rất giống nhau trên các hoán vị ngẫu nhiên ngoại trừ số lượng giao dịch hoán đổi . Có Lomuto cần ba lần nhiều như Hoare!
Số lượng so sánh
Cả hai phương pháp có thể được thực hiện bằng cách sử dụng so sánh để phân vùng một mảng có độ dài . Điều này về cơ bản là tối ưu, vì chúng ta cần so sánh mọi yếu tố với trục để quyết định nơi đặt nó.n−1n
Số lần hoán đổi
Số lượng giao dịch hoán đổi là ngẫu nhiên cho cả hai thuật toán, tùy thuộc vào các yếu tố trong mảng. Nếu chúng ta giả sử hoán vị ngẫu nhiên , tức là tất cả các yếu tố là khác biệt và mọi hoán vị của các yếu tố đều có khả năng như nhau, chúng ta có thể phân tích số lượng giao dịch hoán đổi dự kiến .
Khi chỉ tính thứ tự tương đối, chúng tôi giả sử rằng các phần tử là các số . Điều đó làm cho cuộc thảo luận dưới đây dễ dàng hơn vì thứ hạng của một yếu tố và giá trị của nó trùng khớp.1,…,n
Phương pháp của Lomuto
Biến chỉ số quét toàn bộ mảng và bất cứ khi nào chúng ta tìm thấy một phần tử nhỏ hơn p , chúng ta thực hiện trao đổi. Trong số các phần tử , chính xác là các phần tử nhỏ hơn , vì vậy chúng tôi nhận được hoán đổi nếu trục là .jA[j]x1,…,nx−1xx−1x
Các kỳ vọng tổng thể sau đó kết quả bằng cách tính trung bình trên tất cả các trục. Mỗi giá trị trong đều có khả năng trở thành trục chính (cụ thể là với đầu . ), vì vậy chúng tôi có{1,…,n}1n
1n∑x=1n(x−1)=n2−12.
trung bình hoán đổi để phân vùng một mảng có độ dài bằng phương thức của Lomuto.n
Phương pháp của Hoare
Ở đây, phân tích phức tạp hơn một chút: Ngay cả khi sửa trục , số lần hoán đổi vẫn là ngẫu nhiên.x
Chính xác hơn: Các chỉ số và chạy về phía nhau cho đến khi chúng giao nhau, điều này luôn xảy ra ở (theo tính chính xác của thuật toán phân vùng của Hoare!). Điều này có hiệu quả phân chia mảng thành hai phần: Một phần bên trái được quét bởi và một phần bên phải được quét bởi .ijxij
Bây giờ, việc hoán đổi được thực hiện chính xác cho mọi cặp yếu tố của người đặt nhầm vị trí, tức là một phần tử lớn (lớn hơn , do đó nằm trong phân vùng bên phải) hiện nằm ở phần bên trái và một phần tử nhỏ nằm ở phần bên phải. Lưu ý rằng cặp hình thành này luôn hoạt động, tức là có số lượng phần tử nhỏ ban đầu ở phần bên phải bằng với số phần tử lớn ở phần bên trái.x
Người ta có thể chỉ ra rằng số lượng các cặp này là hypergeometrically phân phối: Đối với các phần tử lớn chúng ta vẽ ngẫu nhiên các vị trí của chúng trong mảng và có vị trí trong phần còn lại. Theo đó, số lượng cặp dự kiến là với điều kiện là trục là .Hyp(n−1,n−x,x−1)n−xx−1(n−x)(x−1)/(n−1)x
Cuối cùng, chúng tôi trung bình một lần nữa trên tất cả các giá trị trục để có được tổng số lần hoán đổi dự kiến cho phân vùng của Hoare:
1n∑x=1n(n−x)(x−1)n−1=n6−13.
(Một mô tả chi tiết hơn có thể được tìm thấy trong luận án thạc sĩ của tôi , trang 29.)
Mẫu truy cập bộ nhớ
Cả hai thuật toán sử dụng hai con trỏ vào mảng quét nó tuần tự . Do đó, cả hai hành xử gần như tối ưu bộ nhớ đệm wrt.
Các yếu tố bằng nhau và danh sách đã được sắp xếp
Như đã đề cập bởi Wandering Logic, hiệu suất của các thuật toán khác nhau mạnh hơn đối với các danh sách không phải là hoán vị ngẫu nhiên.
Trên một mảng đã được sắp xếp, phương thức của Hoare không bao giờ hoán đổi, vì không có cặp nào bị đặt sai (xem ở trên), trong khi phương thức của Lomuto vẫn thực hiện khoảng hoán đổi!n/2
Sự hiện diện của các yếu tố bằng nhau đòi hỏi sự chăm sóc đặc biệt trong Quicksort. (Tôi đã tự mình bước vào cái bẫy này; xem luận án thạc sĩ của tôi , trang 36, để biết một câu chuyện về Tối ưu hóa sớm) Hãy xem xét như một ví dụ cực đoan về một mảng chứa s. Trên một mảng như vậy, phương thức của Hoare thực hiện hoán đổi cho mọi cặp phần tử - đó là trường hợp xấu nhất cho phân vùng của Hoare - nhưng và luôn gặp nhau ở giữa mảng. Do đó, chúng tôi có phân vùng tối ưu và tổng thời gian chạy vẫn còn trong .i j O ( n log n )0ijO(nlogn)
Phương pháp của Lomuto hành xử ngu ngốc hơn nhiều trên tất cả mảng: So sánh sẽ luôn đúng, vì vậy chúng tôi thực hiện hoán đổi cho mọi yếu tố ! Nhưng thậm chí còn tệ hơn: Sau vòng lặp, chúng tôi luôn có , vì vậy chúng tôi quan sát phân vùng trường hợp xấu nhất, làm cho hiệu suất tổng thể giảm xuống còn !i = n Θ ( n 2 )0A[j] <= x
i=nΘ(n2)
Phần kết luận
Phương pháp của Lomuto đơn giản và dễ thực hiện hơn, nhưng không nên được sử dụng để thực hiện phương pháp sắp xếp thư viện.
A[i+1] <= x
. Trong một mảng được sắp xếp (và được đưa ra các pivots được lựa chọn hợp lý) Hoare gần như không hoán đổi và Lomuto thực hiện một tấn (một khi j đủ nhỏ thì tất cảA[j] <= x
.) Tôi còn thiếu gì?