Phương pháp Quicksort trong C và Java: Hướng dẫn đầy đủ

Cập nhật lần cuối: 6 tháng 2026
  • Quicksort là một thuật toán sắp xếp hiệu quả dựa trên phương pháp chia để trị, với hiệu năng trung bình O(n log n) và trường hợp xấu nhất là O(n^2).
  • Chọn một phần tử chốt và phân chia các phần tử nhỏ hơn và lớn hơn để sắp xếp bằng phương pháp đệ quy; việc lựa chọn phần tử chốt ảnh hưởng đến hiệu suất.
  • Có thể lập trình bằng C và Java; tồn tại các phiên bản lặp, nhưng nó không ổn định và các phần tử lặp lại có thể làm giảm hiệu quả.
Phương pháp sắp xếp nhanh

Trong thế giới lập trình, các thuật toán sắp xếp đóng vai trò vô cùng quan trọng. Trong số những thuật toán hiệu quả và được sử dụng rộng rãi nhất là Quicksort. Thuật toán này, nổi tiếng với tốc độ và hiệu quả trong việc sắp xếp các phần tử, có thể được triển khai trong nhiều ngôn ngữ lập trình, bao gồm C và Java. Trong hướng dẫn toàn diện này, chúng ta sẽ cùng khám phá chi tiết thuật toán Quicksort trong C và Java, phân tích hoạt động, cách triển khai và các tính năng chính của nó. Hãy cùng chúng tôi tham gia hành trình thú vị này khám phá thuật toán Quicksort và tìm hiểu cách bạn có thể áp dụng nó vào các dự án lập trình của riêng mình.

Phương pháp Quicksort là gì?

Thuật toán Quicksort, hay còn gọi là quicksort, là một thuật toán sắp xếp hiệu quả sử dụng kỹ thuật chia để trị. Thuật toán này được nhà khoa học máy tính người Anh Sir Tony Hoare phát triển vào năm 1959 và kể từ đó đã trở thành một trong những thuật toán sắp xếp được sử dụng và nghiên cứu rộng rãi nhất trong lập trình.

Thuật toán Quicksort dựa trên nguyên tắc chọn một phần tử chốt (pivot) từ danh sách cần sắp xếp và chia các phần tử còn lại thành hai nhóm: những phần tử nhỏ hơn hoặc bằng phần tử chốt, và những phần tử lớn hơn phần tử chốt. Sau đó, quy trình tương tự được áp dụng đệ quy cho từng nhóm đã tạo ra, cho đến khi tất cả các phần tử được sắp xếp.

Phương pháp Quicksort trong C

Ngôn ngữ lập trình C được sử dụng rộng rãi để triển khai các thuật toán nhờ hiệu quả và khả năng điều khiển phần cứng ở cấp độ thấp. Dưới đây, chúng ta sẽ trình bày từng bước triển khai phương pháp Quicksort trong ngôn ngữ C:

Bước 1: Chọn trục

Đầu tiên, phải chọn mục trục từ danh sách. Có nhiều cách khác nhau để chọn điểm xoay, nhưng cách phổ biến nhất là chọn mục đầu tiên trong danh sách.

Bước 2: Phân vùng

Sau khi chọn điểm trục, danh sách phải được phân vùng thành hai nhóm: các phần tử nhỏ hơn hoặc bằng điểm trục và các phần tử lớn hơn điểm trục. Để thực hiện điều này, một con trỏ trái và một con trỏ phải được sử dụng để di chuyển về phía giữa danh sách cho đến khi tìm thấy các phần tử cần hoán đổi.

  Bucketsort: Sắp xếp dữ liệu nhanh chóng

Bước 3: Đệ quy

Sau khi phân vùng được thực hiện, quy trình tương tự được áp dụng đệ quy cho từng nhóm đã tạo. Nghĩa là, một trục mới được chọn trong mỗi nhóm và phân vùng được thực hiện lại cho đến khi tất cả các phần tử được sắp xếp.

Bước 4: Kết hợp

Cuối cùng, các nhóm được kết hợp thành một sắp xếp có thứ tự duy nhất. Tại thời điểm này, tất cả các phần tử nhỏ hơn hoặc bằng trục sẽ nằm ở bên trái của trục, trong khi tất cả các phần tử lớn hơn trục sẽ nằm ở bên phải của trục.

Dưới đây là một ví dụ về cách triển khai phương pháp Quicksort trong C:

#include <stdio.h>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int arr[], int low, int high) {
    int pivot = arr[low];
    int i = low + 1;
    int j = high;

    while (1) {
        while (arr[i] < pivot && i <= j)
            i++;

        while (arr[j] > pivot)
            j--;

        if (i >= j)
            break;

        swap(&arr[i], &arr[j]);
    }

    swap(&arr[low], &arr[j]);

    return j;
}

void quicksort(int arr[], int low, int high) {
    if (low < high) {
        int pivot = partition(arr, low, high);
        quicksort(arr, low, pivot - 1);
        quicksort(arr, pivot + 1, high);
    }
}

int main() {
    int arr[] = {5, 2, 9, 1, 7, 6, 8, 3, 4};
    int n = sizeof(arr) / sizeof(arr[0]);

    quicksort(arr, 0, n - 1);

    printf("Arreglo ordenado: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}

Mã này triển khai phương pháp Quicksort trong C bằng cách sử dụng kỹ thuật đệ quy. Khi bạn chạy chương trình, mảng đầu vào sẽ được sắp xếp và kết quả sẽ được in ra.

Phương pháp Quicksort trong Java

Java là một ngôn ngữ lập trình được sử dụng rộng rãi khác và cũng phù hợp để triển khai phương pháp Quicksort một cách hiệu quả. Tiếp theo, chúng tôi sẽ trình bày từng bước triển khai phương pháp Quicksort trong Java:

Bước 1: Chọn trục

Giống như trong phần triển khai C, trong Java chúng ta cũng cần chọn một phần tử trục từ danh sách. Chúng ta có thể chọn phần tử đầu tiên, phần tử cuối cùng hoặc thậm chí là một phần tử ngẫu nhiên làm điểm xoay.

Bước 2: Phân vùng

Sau khi chọn trục, danh sách phải được phân vùng thành hai nhóm, giống như trong triển khai C. Chúng ta sẽ sử dụng hai chỉ mục, một bắt đầu từ đầu danh sách và một ở cuối danh sách, và di chuyển chúng về phía trung tâm cho đến khi tìm thấy các phần tử cần hoán đổi.

  Phương pháp tìm kiếm Hash: Hướng dẫn đầy đủ

Bước 3: Đệ quy

Sau khi phân vùng được thực hiện, quy trình tương tự được áp dụng đệ quy cho từng nhóm đã tạo. Điều này được thực hiện bằng cách gọi lại phương thức Quicksort cho mỗi nhóm cho đến khi tất cả các phần tử được sắp xếp.

Bước 4: Kết hợp

Cuối cùng, các nhóm được kết hợp thành một mảng được sắp xếp duy nhất, giống như trong phần triển khai C.

Dưới đây là một ví dụ về cách triển khai phương pháp Quicksort trong Java:

public class Quicksort {
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static int partition(int[] arr, int low, int high) {
        int pivot = arr[low];
        int i = low + 1;
        int j = high;

        while (true) {
            while (i <= j && arr[i] < pivot)
                i++;

            while (arr[j] > pivot)
                j--;

            if (i >= j)
                break;

            swap(arr, i, j);
        }

        swap(arr, low, j);

        return j;
    }

    public static void quicksort(int[] arr, int low, int high) {
        if (low < high) {
            int pivot = partition(arr, low, high);
            quicksort(arr, low, pivot - 1);
            quicksort(arr, pivot + 1, high);
        }
    }

    public static void main(String[] args) {
        int[] arr = {5, 2, 9, 1, 7, 6, 8, 3, 4};
        int n = arr.length;

        quicksort(arr, 0, n - 1);

        System.out.print("Arreglo ordenado: ");
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

Tương tự như phần triển khai C, đoạn mã này triển khai phương thức Quicksort trong Java bằng cách sử dụng đệ quy. Khi bạn chạy chương trình, mảng đầu vào sẽ được sắp xếp và kết quả sẽ được in ra.

Câu hỏi thường gặp

1. Độ phức tạp của phương pháp Quicksort là gì? Phương pháp Quicksort có độ phức tạp trung bình là O(n log n) trong trường hợp trung bình và O(n^2) trong trường hợp xấu nhất, trong đó "n" là kích thước của mảng cần sắp xếp. Tuy nhiên, do tính hiệu quả và hiệu suất tốt trong hầu hết các trường hợp, Quicksort vẫn được sử dụng rộng rãi.

2. Làm thế nào để chọn phần tử chốt (pivot) tốt nhất trong phương pháp Quicksort? Việc lựa chọn phần tử chốt có thể ảnh hưởng đến hiệu suất của thuật toán. Một chiến lược phổ biến là chọn phần tử ở giữa của mảng làm phần tử chốt để phân bổ các phần tử đồng đều hơn. Một lựa chọn khác là chọn ba phần tử và sử dụng giá trị trung vị của chúng làm phần tử chốt.

3. Khi nào nên sử dụng Quicksort thay vì các thuật toán sắp xếp khác? Quicksort là một lựa chọn tuyệt vời khi bạn muốn một thuật toán sắp xếp hiệu quả và có đủ bộ nhớ. Tuy nhiên, nếu bộ nhớ bị hạn chế hoặc nếu bạn cần một thuật toán ổn định (một thuật toán giữ nguyên thứ tự tương đối của các phần tử giống nhau), bạn có thể xem xét các thuật toán khác như mergesort.

  Tất cả về thuật toán của Shor: Chức năng, tác động và thách thức

4. Điều gì xảy ra nếu mảng cần sắp xếp chứa các phần tử lặp lại? Phương pháp Quicksort có thể xử lý các mảng có phần tử lặp lại mà không gặp vấn đề. Tuy nhiên, trong trường hợp xấu nhất, khi tất cả các phần tử đều giống nhau, việc phân vùng có thể không công bằng và điều này có thể ảnh hưởng đến hiệu suất của thuật toán.

5. Liệu có thể triển khai phương pháp Quicksort bằng cách lặp thay vì đệ quy không? Có, hoàn toàn có thể triển khai phương pháp Quicksort bằng cách lặp sử dụng cấu trúc dữ liệu gọi là ngăn xếp. Phiên bản đệ quy được sử dụng phổ biến hơn, nhưng phiên bản lặp có thể được ưu tiên trong một số trường hợp nhất định khi bạn muốn tránh chi phí phát sinh của đệ quy.

6. Phương pháp Quicksort có ổn định không? Không, phương pháp Quicksort không ổn định, nghĩa là nó không nhất thiết giữ nguyên thứ tự tương đối của các phần tử giống nhau. Nếu cần một thuật toán ổn định, nên xem xét các lựa chọn khác như mergesort.

Kết luận

Tóm lại, Quicksort là một thuật toán sắp xếp hiệu quả và được sử dụng rộng rãi trong lập trình. Xuyên suốt hướng dẫn này, chúng ta đã tìm hiểu chi tiết cách thức hoạt động và cách triển khai nó trong ngôn ngữ lập trình C và Java. Quicksort sử dụng kỹ thuật chia để trị, chọn một phần tử chốt (pivot) và chia các phần tử còn lại thành hai nhóm. Thông qua đệ quy, các nhóm được sắp xếp cho đến khi thu được mảng đã được sắp xếp cuối cùng.

Điều quan trọng là phải lưu ý các tính năng và cân nhắc của Quicksort, chẳng hạn như lựa chọn trục và xử lý các phần tử lặp lại. Ngoài ra, các tùy chọn thuật toán sắp xếp khác cũng cần được đánh giá dựa trên nhu cầu cụ thể của dự án.

Chúng tôi hy vọng hướng dẫn toàn diện này về phương pháp Quicksort trong C và Java đã giúp bạn hiểu rõ và truyền cảm hứng để bạn áp dụng thuật toán hiệu quả này vào các dự án lập trình của riêng mình!