Thuật toán C/C++

Sắp xếp trộn (merge sort) trong C, C++

Trong bài học này, bạn sẽ cài đặt thuật toán sắp xếp trộn theo chiến lược chia để trị, luôn đạt thời gian O(n log n).

Giới thiệu

Sắp xếp trộn chia mảng thành hai nửa, sắp xếp từng nửa bằng cách gọi đệ quy, rồi trộn hai nửa đã sắp xếp thành một dãy có thứ tự. Ưu điểm lớn của thuật toán này là thời gian chạy luôn ổn định ở mức O(n log n), bất kể dữ liệu đầu vào ra sao.

Những điểm quan trọng

  • Kiểm thử với dữ liệu rỗng, chỉ có một phần tử, có giá trị trùng và đã được sắp xếp.
  • Viết cho đúng trước, tối ưu sau.
  • Trong code thực tế, ưu tiên dùng các hàm có sẵn của thư viện chuẩn.

Mô phỏng Sắp xếp trộn (merge sort) trong C, C++

O(n)

Nhấn Phát hoặc Từng bước để theo dõi từng phép so sánh và thay đổi dữ liệu.

Code ví dụ bằng C và C++

C
Chạy code →
main.c
#include <stdio.h>
#include <stdlib.h>

void merge_sort(int *values, int *temporary, int left, int right) {
    if (right - left < 2) return;
    int middle = (left + right) / 2;
    merge_sort(values, temporary, left, middle);
    merge_sort(values, temporary, middle, right);

    int first = left;
    int second = middle;
    int output = left;
    while (first < middle && second < right) {
        temporary[output++] = values[first] < values[second]
            ? values[first++] : values[second++];
    }
    while (first < middle) temporary[output++] = values[first++];
    while (second < right) temporary[output++] = values[second++];
    for (int index = left; index < right; ++index) {
        values[index] = temporary[index];
    }
}

int main(void) {
    int values[] = {8, 3, 6, 2, 7};
    int temporary[5];
    merge_sort(values, temporary, 0, 5);
    for (int index = 0; index < 5; ++index) {
        printf("%d ", values[index]);
    }
}
Kết quả khi chạy
2 3 6 7 8
C++
Chạy code →
main.cpp
#include <algorithm>
#include <iostream>
#include <vector>

void merge_sort(std::vector<int>& values) {
    if (values.size() < 2) return;
    auto middle = values.begin() + values.size() / 2;
    std::vector<int> left(values.begin(), middle);
    std::vector<int> right(middle, values.end());
    merge_sort(left);
    merge_sort(right);
    std::merge(left.begin(), left.end(), right.begin(), right.end(),
               values.begin());
}

int main() {
    std::vector values{8, 3, 6, 2, 7};
    merge_sort(values);
    for (int value : values) {
        std::cout << value << ' ';
    }
}
Kết quả khi chạy
2 3 6 7 8

So sánh C và C++

Hàm merge_sort trong C dừng khi đoạn chỉ còn dưới 2 phần tử. Sau khi sắp xếp hai nửa, vòng lặp while lần lượt chọn phần tử nhỏ hơn ở đầu mỗi nửa và chép vào mảng tạm temporary, rồi chép phần còn lại. Cả hai phiên bản đều cần thêm O(n) bộ nhớ. Phiên bản C tự quản lý mảng tạm, còn phiên bản C++ dùng vector và các thuật toán chuẩn để code rõ ràng hơn.

C

Vòng lặp, con trỏ, độ dài và vùng nhớ tạm đều được viết tường minh.

C++

Iterator và các thuật toán chuẩn tách thao tác xử lý khỏi cách dữ liệu được lưu trữ.

Bài tập mở rộng

Hãy chạy cả hai phiên bản, sau đó thử thay đổi code để quan sát sự khác biệt về mức độ an toàn mà mỗi ngôn ngữ mang lại.

  • Tự mô phỏng từng phép so sánh trên giấy.
  • Thử với giá trị trùng lặp và các giá trị cực lớn, cực nhỏ.
  • Đo thời gian chạy của code tự viết và so sánh với thư viện chuẩn.

Luyện tập với thử thách

Áp dụng kiến thức của bài học này để giải một bài toán thực tế. Mỗi thử thách chạy ngay trên trình duyệt, có kiểm thử tức thì và AI nhận xét.

Tất cả thử thách