Thuật toán để hợp nhất hai mảng được sắp xếp với số lượng so sánh tối thiểu


24

Cho là hai mảng được sắp xếp a , b loại T với kích thước nm . Tôi đang tìm kiếm một thuật toán hợp nhất hai mảng thành một mảng mới (có kích thước tối đa n + m).

Nếu bạn có một hoạt động so sánh giá rẻ, điều này là khá đơn giản. Chỉ cần lấy từ mảng có phần tử đầu tiên thấp nhất cho đến khi một hoặc cả hai mảng được duyệt hoàn toàn, sau đó thêm các phần tử còn lại. Một cái gì đó như thế này /programming/5958169/how-to-merge-two-sort-arrays-into-a-sort-array

Tuy nhiên, tình huống thay đổi khi so sánh hai phần tử đắt hơn nhiều so với việc sao chép một phần tử từ mảng nguồn sang mảng đích . Ví dụ, bạn có thể có một dãy các số nguyên chính xác lớn hoặc các chuỗi, trong đó một phép so sánh có thể khá tốn kém. Chỉ cần giả định rằng việc tạo mảng và sao chép các phần tử là miễn phí, và điều duy nhất là chi phí là so sánh các phần tử.

Trong trường hợp này, bạn muốn hợp nhất hai mảng với số lượng so sánh phần tử tối thiểu . Dưới đây là một số ví dụ mà bạn sẽ có thể làm tốt hơn nhiều so với thuật toán hợp nhất đơn giản:

a = [1,2,3,4, ... 1000]
b = [1001,1002,1003,1004, ... 2000]

Hoặc là

a = [1,2,3,4, ... 1000]
b = [0,100,200, ... 1000]

Có một số trường hợp thuật toán hợp nhất đơn giản sẽ tối ưu, như

a = [1,3,5,7,9,....,999]
b = [2,4,6,8,10,....,1000]

Vì vậy, thuật toán nên suy giảm một cách duyên dáng và thực hiện tối đa các phép so sánh n + m-1 trong trường hợp các mảng được xen kẽ, hoặc ít nhất là không tệ hơn đáng kể.

Một điều nên làm khá tốt cho các danh sách có chênh lệch kích thước lớn là sử dụng tìm kiếm nhị phân để chèn các phần tử của mảng nhỏ hơn vào mảng lớn hơn. Nhưng điều đó sẽ không làm giảm một cách duyên dáng trong trường hợp cả hai danh sách có cùng kích thước và xen kẽ.

Điều duy nhất có sẵn cho các yếu tố là một hàm (tổng) thứ tự, do đó, bất kỳ sơ đồ nào làm cho việc so sánh rẻ hơn là không thể.

Có ý kiến ​​gì không?

Tôi đã nghĩ ra điều này ở Scala . Tôi tin rằng nó là tối ưu về số lượng so sánh, nhưng nó vượt quá khả năng của tôi để chứng minh điều đó. Ít nhất đó là nhiều đơn giản hơn những điều tôi đã tìm thấy trong các tài liệu.

Và kể từ khi đăng bài gốc, tôi đã viết một bài đăng trên blog về cách thức hoạt động của nó.


2
Không có cách nào để so sánh ít hơn trong "thuật toán hợp nhất đơn giản". Bạn có thể cố gắng xử lý các trường hợp cạnh như lần đầu tiên bạn đề cập, nhưng điều này sẽ làm xấu đi trường hợp trung bình.
Mephy

5
@Mephy: làm sáng tỏ chúng tôi và cho chúng tôi một bằng chứng chính thức, xin vui lòng. Hoặc nếu bạn không thể, hãy cân nhắc xóa (hoặc ít nhất là tinh chỉnh) bình luận của bạn.
Doc Brown

4
@DocBrown nếu tôi có bằng chứng chính thức, tôi sẽ đưa ra câu trả lời chứ không phải bình luận. Dù sao, đó là một vấn đề tuyến tính khá rõ ràng, bởi vì cố gắng tìm một giải pháp tốt hơn tuyến tính sẽ cần ít nhất là thời gian tuyến tính.
Mephy

4
@Mephy: Tôi khuyên bạn nên dành thời gian để đọc câu trả lời dưới đây và suy nghĩ kỹ về những gì bạn đã viết.
Doc Brown

4
@Mephy Hầu hết mọi thứ rõ ràng ("bạn không thể nhân số nhỏ hơn O (n ^ 2)", "nếu tôi thay đổi cửa nào tôi chọn, tôi sẽ không cải thiện cơ hội giành được giá" , "bạn có thể 't sắp xếp ít hơn O (n log n) ", ..) là sai. Ví dụ, sử dụng phương pháp tìm kiếm nhị phân trong danh sách ngắn hơn sẽ cải thiện đáng kể trường hợp trung bình.
Voo

Câu trả lời:


31

Thuật toán sắp xếp hợp nhất thông thường - bước hợp nhất với các phép so sánh n + m -1 thông thường, trong đó một danh sách có kích thước n và danh sách khác có kích thước m. Sử dụng thuật toán này là cách tiếp cận đơn giản nhất để kết hợp hai danh sách được sắp xếp.

Nếu các so sánh quá đắt, bạn có thể thực hiện hai điều - hoặc là bạn giảm thiểu số lượng so sánh hoặc bạn giảm thiểu chi phí so sánh.

Hãy tập trung vào việc giảm thiểu chi phí so sánh. Bạn và chỉ bạn mới có thể quyết định liệu dữ liệu bạn đang so sánh có thể được lượng tử hóa hay không. Nếu bạn có thể định lượng chúng, đây là một hình thức thực hiện phương thức băm, đó là giữ trật tự. Ví dụ: nếu Dữ liệu của bạn được so sánh theo Tên, thì tên đầu tiên, ... bạn có thể lấy đầu tiên cho Chars của tên "Klaehn, Ruediger" và giảm / định lượng phần tử dữ liệu của bạn thành "Kl.Ru", nếu bạn so sánh nó thành "Packer," bạn duy trì thứ tự "Pa.Th" - giờ đây bạn có thể áp dụng thuật toán so sánh rẻ hơn, so sánh các giá trị giảm. Nhưng nếu bạn tìm thấy một "Kl.Ru" khác, bây giờ bạn có một giá trị gần và bây giờ bạn có thể chuyển sang một cách tiếp cận đắt tiền hơn so sánh các yếu tố này.

Nếu bạn có thể trích xuất giá trị lượng tử này từ dữ liệu của mình, nhanh hơn so với việc so sánh nó, đây là điều đầu tiên bạn làm, trước tiên bạn so sánh giá trị được lượng tử hóa hoặc băm. Xin lưu ý rằng giá trị này chỉ cần được tính một lần, vì vậy bạn có thể tính toán nó khi tạo thành phần dữ liệu.

Tôi cũng đề cập đến một cách khác, để giảm thiểu so sánh của bạn.

Tôi đã xem cuốn sách kinh điển TAOCP- Tập 3 - Sắp xếp và tìm kiếm, (tr.197-207, phần 5.3.2) có đầy đủ 10 trang về chủ đề này. Tôi tìm thấy hai tài liệu tham khảo về các thuật toán nhanh hơn so với so sánh n + m-1.

Đầu tiên là thuật toán hợp nhất Hwang-Lin và lần thứ hai là sự cải tiến của Glenn K Manacher - cả hai đều được trích dẫn bởi TAOCP cũng như thuật toán của Christen, tiếp cận giới hạn thấp hơn của các so sánh cần thiết, trong các điều kiện đặc biệt về độ dài n và m của danh sách.

Thuật toán của Manacher đã được trình bày trên Tạp chí ACM Vol. 26 Số 3 trên trang 434-440: "Những cải tiến đáng kể cho thuật toán hợp nhất" Hwan-Lin ". danh sách với m mục và danh sách có n mục có thể có độ dài khác nhau, nhưng chúng cũng phải được đánh dấu bằng số phần tử mà chúng chứa m <= n

Thuật toán Hwang-Lin phá vỡ các danh sách để hợp nhất, ngoài các danh sách nhỏ hơn và sắp xếp các danh sách bằng cách so sánh phần tử đầu tiên của mỗi danh sách phụ và để quyết định xem một số phần tử trong danh sách phụ có cần được so sánh hay không. Nếu danh sách đầu tiên nhỏ hơn danh sách thứ hai, thì khả năng cao là các yếu tố liên tiếp của danh sách dài hơn có thể được chuyển vào danh sách kết quả mà không cần so sánh. Nếu phần tử đầu tiên của ist nhỏ lớn hơn phần tử đầu tiên của danh sách lớn hơn được chia tách, tất cả các phần tử phía trước danh sách con có thể được sao chép mà không cần so sánh.

Phân tích trường hợp trung bình của thuật toán hợp nhất của Hwang và Lin (Vega, Frieze, Santha) trong Phần 2, bạn có thể tìm thấy một mã giả của Thuật toán HL. Đó là tốt hơn rất nhiều so với mô tả của tôi. Và bạn có thể thấy tại sao có ít so sánh hơn - thuật toán sử dụng tìm kiếm nhị phân, để tìm chỉ mục, nơi chèn phần tử từ danh sách ngắn hơn.

Nếu các danh sách không được xen kẽ như trong ví dụ trước của bạn, bạn nên có một danh sách nhỏ hơn và một danh sách lớn hơn còn lại trong hầu hết các trường hợp. Đây là khi thuật toán HL bắt đầu hoạt động tốt hơn.


Cảm ơn bạn, vì nhận xét của bạn về điều này - Tôi đã kiểm tra câu trả lời của mình và thấy rằng Knuth dành trọn 10 trang cho chủ đề này. Và sau đó tôi lấy The JACM từ m bookshelf và nhìn ở đó nhiều hơn. Tôi sẽ cải thiện câu trả lời của tôi. - Không cần hạ cấp. Thuật toán băm (lượng tử hóa) là một ý tưởng đơn giản, có thể được áp dụng trên nhiều bộ dữ liệu - nhưng chỉ có Guy hỏi, là người duy nhất quyết định liệu nó có áp dụng được cho dữ liệu của mình hay không.
thepacker

4
Sau khi bạn cải thiện câu trả lời của mình, tất cả những người đánh giá thấp bạn sẽ có cơ hội nâng cao bạn một lần nữa ;-)
Doc Brown

+1 để lưu ý rằng nếu kích thước rất khác nhau thì hợp nhất tiêu chuẩn là không tối ưu.
Florian F

1

Giả sử hai mảng có các phần tử N và M, N ≥ M và tất cả các phần tử đều khác nhau.

Nếu mảng được sắp xếp chứa một phần tử x của N theo sau là một phần tử y của M hoặc ngược lại thì x và y phải được so sánh, nếu không chúng ta sẽ không biết chúng thuộc về thứ tự nào. (Không thể có một chuỗi các phần tử khác nói a, b, c trong đó chúng ta biết rằng x <a <b <c <y, chẳng hạn, vì không có phần tử nào giữa x và y. Vì vậy, x và y phải được so sánh trực tiếp

Nếu N> M thì có thể có một mảng trong đó mỗi phần tử của M đều có trước và theo sau là một phần tử của N, có nghĩa là cần ít nhất 2M so sánh - ngay cả khi bạn sử dụng thuật toán sắp xếp không xác định có thể thực hiện một dự đoán hoàn hảo những con số để so sánh. (Điều đó có nghĩa là: Giả sử bạn có N lớn, M = 1. Tìm kiếm nhị phân thực hiện các bước O (log2 N); thuật toán không xác định sẽ đoán giữa hai phần tử của một phần tử của mảng thứ hai và thực hiện hai phép so sánh với xác nhận dự đoán).

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.