Menu
CoddyTech

Merge sort (sắp xếp trộn)

Cập nhật lần cuối

Merge sort (sắp xếp trộn) là một thuật toán chia để trị (divide and conquer). Thuật toán chia đôi mảng một cách đệ quy cho đến khi mỗi phần chỉ còn một phần tử (hiển nhiên đã được sắp xếp), rồi trộn các phần lại với nhau theo đúng thứ tự. Bước trộn duyệt hai mảng con đã sắp xếp bằng hai con trỏ, mỗi lần chép phần tử đầu nhỏ hơn sang tiếp. Nhấn Phát ở trên để xem mảng được dựng lại qua từng lần trộn.

Vì luôn chia đôi, merge sort chạy trong thời gian O(n log n) ở mọi trường hợp: trường hợp xấu nhất cũng tốt như trường hợp tốt nhất. Cái giá phải trả là O(n) bộ nhớ phụ cho vùng đệm trộn tạm thời.

Độ phức tạp thời gian và không gian

Trường hợpĐộ phức tạpGhi chú
Tốt nhấtO(n log n)Luôn chia đôi dữ liệu đầu vào
Trung bìnhO(n log n)Thứ tự ngẫu nhiên
Xấu nhấtO(n log n)Được bảo đảm, không có đầu vào xấu
Không gianO(n)Vùng đệm tạm để trộn
Ổn địnhCóKhi bằng nhau, lấy phần tử bên trái trước lúc trộn

Từng bước

BướcĐiều gì xảy ra
1Nếu đoạn có 0 hoặc 1 phần tử, nó đã được sắp xếp.
2Chia đoạn thành hai nửa.
3Gọi đệ quy merge sort cho nửa trái.
4Gọi đệ quy merge sort cho nửa phải.
5Trộn hai nửa đã sắp xếp bằng hai con trỏ.

Ví dụ minh họa

Sắp xếp [5, 2, 4, 1]:

LượtMảngThao tác
Chia[5, 2] | [4, 1]Chia mảng thành hai nửa
Chia[5] [2] | [4] [1]Tiếp tục chia cho đến khi mỗi phần chỉ còn một phần tử
Trộn[2, 5] | [1, 4]Trộn [5],[2] thành [2, 5] và [4],[1] thành [1, 4]
Trộn[1, 2, 4, 5]Trộn [2, 5] và [1, 4]: lấy 1, rồi 2, rồi 4, rồi 5
Xong[1, 2, 4, 5]Mảng đã được sắp xếp hoàn toàn

Khi nào nên dùng merge sort

Nên dùng khiTránh dùng khi
Bạn cần bảo đảm trường hợp xấu nhất là O(n log n)Bộ nhớ hạn hẹp và không chấp nhận được O(n) bộ nhớ phụ
Tính ổn định quan trọng (các khóa bằng nhau giữ nguyên thứ tự)Bạn sắp xếp mảng nhỏ, khi đó insertion sort nhanh hơn
Bạn sắp xếp một danh sách liên kếtBắt buộc phải sắp xếp tại chỗ
Dữ liệu quá lớn so với RAM (sắp xếp ngoài)Tính cục bộ của cache là yếu tố chính và các lượt tại chỗ của quicksort thắng thế

Code Merge Sort

Một cách cài đặt Merge Sort gọn gàng, chạy được ngay bằng Python, JavaScript, Java, C++, C, Pseudocode. Chọn một ngôn ngữ, sao chép code hoặc mở sẵn trong Coddy Playground.

Code Merge Sort bằng Python

Python
1def merge_sort(a):2    if len(a) <= 1:3        return a4    mid = len(a) // 25    left = merge_sort(a[:mid])6    right = merge_sort(a[mid:])7    return merge(left, right)8
9
10def merge(left, right):11    out = []12    i = j = 013    while i < len(left) and j < len(right):14        if left[i] <= right[j]:15            out.append(left[i])16            i += 117        else:18            out.append(right[j])19            j += 120    out.extend(left[i:])21    out.extend(right[j:])22    return out23
24
25nums = [38, 27, 43, 3, 9, 82, 10]26print("Before:", nums)27print("After: ", merge_sort(nums))
Chạy code này trong Playground Python

Câu hỏi thường gặp về merge sort

Độ phức tạp thời gian của merge sort là bao nhiêu?
Merge sort tốn O(n log n) trong trường hợp tốt nhất, trung bình và xấu nhất, vì nó luôn chia đôi mảng. Thuật toán dùng O(n) bộ nhớ phụ cho vùng đệm trộn.
Merge sort có ổn định không?

Có, khi bước trộn xử lý các phần tử bằng nhau bằng cách lấy từ nửa trái trước. Cách này giữ các phần tử bằng nhau theo đúng thứ tự tương đối ban đầu, vì vậy merge sort là lựa chọn phổ biến khi cần sắp xếp ổn định.

Tại sao chọn merge sort thay vì quicksort?
Merge sort bảo đảm O(n log n) kể cả với đầu vào bất lợi và có tính ổn định, trong khi quicksort có thể suy giảm thành O(n²). Merge sort cũng được ưu tiên cho danh sách liên kết và sắp xếp ngoài. Nhược điểm là nó tốn thêm O(n) bộ nhớ.
Merge sort và quicksort khác nhau như thế nào?
Cả hai đều là thuật toán sắp xếp chia để trị, nhưng quicksort phân hoạch quanh một phần tử chốt (pivot) và sắp xếp tại chỗ với O(log n) bộ nhớ ngăn xếp, còn merge sort chia đôi một cách máy móc và trộn bằng vùng đệm O(n). Trong thực tế quicksort thường nhanh hơn nhờ tính cục bộ của cache, nhưng merge sort bảo đảm trường hợp xấu nhất O(n log n) và có tính ổn định.
Khi nào nên dùng merge sort trong thực tế?
Hãy dùng merge sort khi bạn cần một thuật toán sắp xếp ổn định với cận O(n log n) được bảo đảm, khi sắp xếp danh sách liên kết (nơi nó không cần truy cập ngẫu nhiên), hoặc khi sắp xếp ngoài với dữ liệu quá lớn so với bộ nhớ. Tránh dùng khi bộ nhớ khan hiếm, vì nó cần thêm O(n) bộ nhớ.
Merge sort có sắp xếp tại chỗ không?
Không. Merge sort tiêu chuẩn cấp phát một vùng đệm tạm O(n) để trộn hai nửa, nên nó không sắp xếp tại chỗ. Có những biến thể trộn tại chỗ nhưng chúng phức tạp và hoặc chậm hơn, hoặc mất tính ổn định, nên phiên bản dùng vùng đệm là lựa chọn phổ biến.
Hình minh họa các ngôn ngữ lập trình của Coddy

Thành thạo thuật toán cùng Coddy

Bắt đầu