Thuật toán C/C++

Sắp xếp nhanh (quick 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 nhanh bằng cách phân hoạch mảng quanh một phần tử chốt (pivot).

Giới thiệu

Sắp xếp nhanh chọn một phần tử làm chốt (pivot), sau đó sắp xếp lại mảng sao cho các phần tử nhỏ hơn pivot nằm bên trái, còn lại nằm bên phải. Khi đó pivot đã ở đúng vị trí cuối cùng của nó, và thuật toán tiếp tục sắp xếp hai phần hai bên bằng đệ quy.

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 nhanh (quick sort) trong C, C++

O(n log 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>

void swap(int *left, int *right) {
    int temporary = *left;
    *left = *right;
    *right = temporary;
}

int partition(int *values, int low, int high) {
    int pivot = values[high];
    int boundary = low;
    for (int scan = low; scan < high; ++scan) {
        if (values[scan] < pivot) {
            swap(&values[boundary++], &values[scan]);
        }
    }
    swap(&values[boundary], &values[high]);
    return boundary;
}

void quick_sort(int *values, int low, int high) {
    if (low >= high) return;
    int pivot = partition(values, low, high);
    quick_sort(values, low, pivot - 1);
    quick_sort(values, pivot + 1, high);
}

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

template<class Iterator>
void quick_sort(Iterator first, Iterator last) {
    if (last - first < 2) return;
    auto pivot = *(last - 1);
    auto middle = std::partition(first, last - 1,
        [pivot](int value) { return value < pivot; });
    std::iter_swap(middle, last - 1);
    quick_sort(first, middle);
    quick_sort(middle + 1, last);
}

int main() {
    std::vector values{9, 4, 7, 3, 10, 5};
    quick_sort(values.begin(), values.end());
    for (int value : values) {
        std::cout << value << ' ';
    }
}
Kết quả khi chạy
3 4 5 7 9 10

So sánh C và C++

Hàm partition trong C chọn phần tử cuối làm pivot và dùng biến boundary đánh dấu ranh giới của vùng các phần tử nhỏ hơn pivot. Cuối cùng pivot được đổi chỗ vào đúng vị trí boundary. Phiên bản C++ dùng std::partition để biểu diễn bước phân hoạch ngắn gọn hơn. Độ phức tạp trung bình là O(n log n), nhưng nếu pivot được chọn không tốt có thể chậm đến O(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