快速排序(quicksort)

本文详细介绍了快速排序算法,包括Lomuto分区方案和Hoare分区方案。Lomuto方案以尾元素为基准,而Hoare方案以首元素或中间元素为基准。文中通过代码实现和测试,探讨了不同基准选择对排序效率的影响,并指出在已排序或元素相等的情况下,两种方案的时间复杂度可能退化为O(n^2)。
摘要由CSDN通过智能技术生成

IT公司招人,无论笔试还是面试,快排基本上都会问到。

通常情况下,快排实现有两个函数:

  1. void quickSort(int arr[], int left, int right);
  2. int partition(int arr[], int left, int right)

快排采用divide-and-conquer策略:

  1. 选一个pivot value
  2. Partition
  3. Sort both parts(最后不需要去合)

根据自己的学习,今天采用两种思路来实现,要想看一下没中方式在实现排序的过程,把最后c++实现拷贝运行下就好了。

以下Lomuto partition scheme and Hoare partition scheme来自wiki quicksort,然后我将每种实现了一下。

  1. 在wiki上,Lomuto partition scheme是以尾元素为基准进行的排序;Hoare partition scheme是以首元素为基准进行的排序。最重要的是理解其中的思想。

  2. 在Lomuto partition scheme中,我以首/尾元素来实现了一下;在Hoare partition scheme中,我以中/首元素实现了一下。其实,在理解了两种快速排序的方式以后,在实现时注意的就是当选取不同不同位置元素为基准时,partition返回值以及quicksort边界问题。

  3. 用随机生成的数组来测试一下算法有没有问题,测试结果一并附上。

  4. 以后分析一下partition and time问题

Lomuto partition scheme

This scheme is attributed to Nico Lomuto and popularized by Bentley in his book Programming Pearls[13] and Cormen et al. in their book Introduction to Algorithms.[14] This scheme chooses a pivot which is typically the last element in the array. The algorithm maintains the index to put the pivot in variable i and each time it finds an element less than or equal to pivot, this index is incremented and that element would be placed before the pivot. As this scheme is more compact and easy to understand, it is frequently used in introductory material, although it is less efficient than Hoare’s original scheme.[15] This scheme degrades to O(n2) when the array is already sorted as well as when the array has all equal elements.[9] There have been various variants proposed to boost performance including various ways to select pivot, deal with equal elements, use other sorting algorithms such as Insertion sort for small arrays and so on. In pseudocode, a quicksort that sorts elements lo through hi (inclusive) of an array A. – wiki

尾元素为基准

这个算法,在《编程珠玑》和《算法导论》中都有介绍。

//lo = 0; hi = A.size();
void quicksort1(vector<int> &A, int lo, int hi) {
    hi -= 1;
    if (lo < hi) {
        int p = partition1(A, lo, hi);
        quicksort1(A, lo, p);
        quicksort1(A, p+1, hi+1);
    }
}
int partition1(vector<int> &A, int lo, int hi) {
    int pivot = A[hi]; //以尾元素为基准
    int i = lo-1;

    for (int j = lo; j < hi; ++j) {
        if (A[j] <= pivot) {
            swap(A[++i], A[j]);
        }
    }
    swap(A[++i], A[hi]);

    return i;
}

以首元素为基准

我自己改了一下,改成首元素为基准。

//lo = 0; hi = A.size();
void quicksort2(vector<int> &A, int lo, int hi) {
    hi -= 1;
    if (lo < hi) {
        int p = partition2(A, lo, hi);
        quicksort2(A, lo, p);
        quicksort2(A, p+1, hi+1);
    }
}
int partition2(vector<int> &A, int lo, int hi) {
    int pivot = A[lo]; //以首元素为基准
    int i = lo;
    for (int j = lo+1; j <= hi; ++j) {
        if (A[j] <= pivot) {
            swap(A[++i], A[j]);
        }
    }
    swap(A[lo], A[i]);

    return i;
}

Hoare partition scheme

The original partition scheme described by C.A.R. Hoare uses two indices that start at the ends of the array being partitioned, then move toward each other, until they detect an inversion: a pair of elements, one greater than the pivot, one smaller, that are in the wrong order relative to each other. The inverted elements are then swapped.[16] When the indices meet, the algorithm stops and returns the final index. There are many variants of this algorithm, for example, selecting pivot from A[hi] instead of A[lo]. Hoare’s scheme is more efficient than Lomuto’s partition scheme because it does three times fewer swaps on average, and it creates efficient partitions even when all values are equal.[9][self-published source?] Like Lomuto’s partition scheme, Hoare partitioning also causes Quicksort to degrade to O(n2) when the input array is already sorted; it also doesn’t produce a stable sort. Note that in this scheme, the pivo

快速排序QuickSort)是一种高效的排序算法,它基于分治策略。该算法首先选择一个元素作为基准值(pivot),然后将待排序数组按照基准值分成两个子数组,一边是所有小于基准值的元素,另一边是所有大于等于基准值的元素。然后对两个子数组分别递归地进行快速排序,最后将两个子数组合并起来即可得到完整的有序数组。 以下是使用C++实现快速排序的代码: ```cpp void quickSort(vector<int>& nums, int left, int right) { if (left >= right) return; // 递归终止条件 int pivot = nums[left]; // 选择第一个元素作为基准值 int i = left, j = right; while (i < j) { // 一趟快速排序 while (i < j && nums[j] >= pivot) j--; // 从右往左找到第一个小于基准值的元素 if (i < j) nums[i++] = nums[j]; // 将该元素放入左半部分 while (i < j && nums[i] < pivot) i++; // 从左往右找到第一个大于等于基准值的元素 if (i < j) nums[j--] = nums[i]; // 将该元素放入右半部分 } nums[i] = pivot; // 将基准值放入合适的位置 quickSort(nums, left, i - 1); // 递归地对左半部分进行快速排序 quickSort(nums, i + 1, right); // 递归地对右半部分进行快速排序 } ``` 其中,`nums`表示待排序数组,`left`和`right`表示当前子数组的左右边界(初始时应为0和`nums.size()-1`)。我们首先选择第一个元素作为基准值,然后使用双指针i和j在数组中进行一趟快速排序,将小于基准值的元素放入左半部分,将大于等于基准值的元素放入右半部分。最后将基准值放入合适的位置,并递归地对左右两个子数组进行快速排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值