Explain in detail the principle, time complexity and optimization method of C++ to realize quick sort

Quick sort is an efficient sorting algorithm, and its time complexity is Θ(n log n). The core idea of ​​quick sorting is the divide and conquer method, which realizes sorting by decomposing a large problem into multiple small problems. Let's introduce how to use C++ to implement quick sort.

1. The principle of quick sort

The basic idea of ​​quick sorting is: select a reference element (usually the first element) from the sequence to be sorted, and then divide the sequence into two subsequences, one subsequence with all elements less than or equal to the reference element, and the other subsequence All elements of the sequence are greater than the reference element, and finally the two subsequences are sorted recursively. The sort is complete when there is only one element in the subsequence.

Two, C++ implements quick sort

The following is the code to implement quick sort in C++:

void quickSort(int arr[], int left, int right) {
    int i = left, j = right;
    int pivot = arr[(left + right) / 2];
    
    while (i <= j) {
        while (arr[i] < pivot)
            i++;
        while (arr[j] > pivot)
            j--;
        if (i <= j) {
            swap(arr[i], arr[j]);
            i++;
            j--;
        }
    }
    
    if (left < j)
        quickSort(arr, left, j);
    if (i < right)
        quickSort(arr, i, right);
}

3. How quick sort works

The core of quicksort is the partition function, which divides the sequence into two subsequences. In the above implementation, we use the left and right pointers i and j to point to the left and right ends of the sequence respectively, and then scan the sequence from both ends, if the element pointed by the left pointer is smaller than the reference element, move the left pointer to the right; if the right pointer points to If the element pointed to by the left pointer is greater than or equal to the base element and the element pointed to by the right pointer is less than or equal to the base element, the two elements are exchanged and moved to the middle at the same time.

In the above code, we use arr[(left + right) / 2] as the reference element, and we can also choose other elements as the reference element, such as the first, last or middle element.

Fourth, the time complexity of quick sort

In the worst case, the time complexity of quick sorting is Θ(n^2), that is, when the sequence is already ordered or close to ordered, the divide and conquer method will fail. At this time, n-1 comparisons are required, and the sorting The time complexity degenerates to O(n^2). On average, the time complexity of quicksort is Θ(n log n). In the best case, where each pivot is exactly the median, the time complexity is O(n log n).

5. Optimization of quick sort

To improve the performance of quicksort, we can optimize it in the following ways:

  • Random selection of reference elements: the worst case can be avoided;
  • The method of taking the middle of three numbers: take a number in the three positions of left, mid and right as the reference element, which can reduce the occurrence of the worst case;
  • Insertion sorting: When the sequence length is less than a certain threshold, insertion sorting can be used instead of quick sorting;
  • Tail recursion elimination: The recursive process can be optimized to avoid the risk of stack overflow.

Optimizing quicksort can improve its performance. Here is an optimized quicksort implementation:

// 三数取中法选择基准元素
int median3(int arr[], int left, int right) {
    int center = (left + right) / 2;
    if (arr[left] > arr[center])
        swap(arr[left], arr[center]);
    if (arr[left] > arr[right])
        swap(arr[left], arr[right]);
    if (arr[center] > arr[right])
        swap(arr[center], arr[right]);
    swap(arr[center], arr[right - 1]); // 将基准元素放到倒数第二个位置
    return arr[right - 1];
}

// 插入排序
void insertionSort(int arr[], int left, int right) {
    for (int i = left + 1; i <= right; i++) {
        int temp = arr[i];
        int j = i - 1;
        while (j >= left && arr[j] > temp) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = temp;
    }
}

// 递归快速排序
void quickSort(int arr[], int left, int right) {
    const int THRESHOLD = 10; // 阈值
    if (right - left >= THRESHOLD) {
        int pivot = median3(arr, left, right); // 选择基准元素
        int i = left, j = right - 1;
        while (true) {
            while (arr[++i] < pivot) {}
            while (arr[--j] > pivot) {}
            if (i < j)
                swap(arr[i], arr[j]);
            else
                break;
        }
        swap(arr[i], arr[right - 1]); // 将基准元素放到正确的位置
        quickSort(arr, left, i - 1); // 递归排序左子序列
        quickSort(arr, i + 1, right); // 递归排序右子序列
    } else {
        insertionSort(arr, left, right); // 使用插入排序对小序列排序
    }
}

In the above code, we use the method of taking the middle of three numbers to select the reference element. After selecting the reference element, we put it in the penultimate position, which is for the convenience of handling the right boundary. Before recursively sorting the left and right subsequences, we first judge whether the sequence length is less than a threshold (set to 10 here), and if it is less than or equal to the threshold, use insertion sort instead of quick sort. Through the above optimization, the performance of quick sort has been improved.

6. Summary

Quicksort is an efficient sorting algorithm with a time complexity of Θ(n log n). When implementing quick sorting, it is necessary to pay attention to selecting the appropriate reference element, and randomize it or take the middle of three numbers to avoid the worst case. At the same time, optimization methods such as insertion sort can be used to improve sorting performance.

Guess you like

Origin blog.csdn.net/m0_62338174/article/details/130458786