Merge Sort — Sức mạnh của Chia để Trị
Với những mảng nhỏ (vài chục phần tử), Insertion Sort làm việc rất tốt. Nhưng khi dữ liệu phình to lên hàng triệu bản ghi (ví dụ: Log hệ thống, Danh sách khách hàng), các thuật toán sơ cấp O(n^2) sẽ khiến CPU phải chạy hàng ngàn tỉ phép tính — máy chủ sẽ sập!
Để phá vỡ giới hạn tốc độ O(n^2), chúng ta phải thay đổi hoàn toàn tư duy. Không cày bừa từ đầu đến cuối mảng nữa. Chào mừng bạn đến với chiến lược đỉnh cao trong Khoa học máy tính: Divide and Conquer (Chia để Trị). Và đại diện xuất sắc nhất của nó: Merge Sort.
📋 Agenda
Thời gian đọc ước tính: ~8 phút
Sau bài này, bạn sẽ:
- ✅ Hiểu được triết lý Divide and Conquer là gì.
- ✅ Nhận diện được một sự thật hiển nhiên: Mảng 0 hoặc 1 phần tử luôn luôn là mảng Đã được sắp xếp.
- ✅ Tự tay viết hàm Gộp mảng (Merge) và hàm Cắt mảng (Merge Sort) bằng Đệ quy.
- ✅ Giải thích được sức mạnh của độ phức tạp thời gian
O(n log n). - ✅ Chỉ ra được điểm yếu chí mạng về bộ nhớ (Space Complexity) của thuật toán này.
Yêu cầu đầu vào:
- 🔹 Có kiến thức cơ bản về Đệ quy (Recursion) trong TypeScript.
❓ Làm sao để phá vỡ giới hạn O(n²)?
Vấn đề (Problem Statement): Bạn đang đối mặt với một m ảng khổng lồ 1.000.000 phần tử. Nếu dùng O(n²), số phép tính là 1.000.000 * 1.000.000 = 1 nghìn tỷ bước. Quá kinh khủng.
Giải pháp (Solution): Triết lý Chia để Trị. Thay vì cố gắng sắp xếp 1 triệu phần tử, tôi "Cắt đôi" mảng đó ra thành 2 mảng 500k phần tử. Tôi giao cho 2 đệ tử xử lý. Đệ tử lại cắt đôi tiếp thành mảng 250k... Cứ cắt mãi cho đến khi mảng chỉ còn đúng 1 phần tử. (Một mảng có 1 phần tử thì hiển nhiên là nó Đã Được Sắp Xếp!). Việc cuối cùng là ghép (Merge) hai mảng 1 phần tử đã xếp đó lại thành mảng 2 phần tử được sắp xếp, rồi ghép dần lên thành 1 triệu phần tử.
📖 Trực quan hóa "Chia và Gộp"
Định nghĩa: Merge Sort là thuật toán sắp xếp dựa trên Đệ quy. Nó liên tục chia mảng làm đôi cho đến khi các mảng con chỉ còn 0 hoặc 1 phần tử. Sau đó, nó gộp (Merge) các mảng con này lại với nhau sao cho kết quả gộp luôn được sắp xếp.