快速排序

快速排序 正如它的名字一样,是一种效率较高的排序方法,面试中也经常出现,正常情况下时间复杂度为 O(n * logn)。但是快排是一种不稳定排序算法,排序过程中会打乱元素顺序。

快排的核心是partition算法,partition算法步骤:

  1. 选取一个元素作为pivot。
  2. 将小于pivot的元素放在其左边,大于pivot的元素放在其右边
  3. 分别对pivot的左右子序列进行递归进行1,2,3

所以partition效率高的快排效率自然高,在此介绍两种partition方法:

partition 1

选定一个基准之后,在数组首尾分别设置一个指针,使得小于基准的都在左边,大于基准的都在右边。

两种不同的写法,相同的效果:

int partition1(vector<int>& arr, int begin, int end) {
    int pivot = arr[begin];
    int l = begin, r = end + 1;
    while (l < r)
    {
        while (arr[--r] >= pivot && l < r);
        while (arr[++l] <= pivot && l < r);
        if (l >= r)break;
        swap(arr[l], arr[r]);
    }
    // 这里一定要注意,有时候l != r,所以swap(arr[begin], arr[r])和swap(arr[begin], arr[l]) 是不同的。
    swap(arr[begin], arr[r]); 
    return r;
}

int partition1(vector<int>& arr, int low, int high)
{
    int pivot = arr[low];//选第一个元素作为枢纽元
    while (low < high)
    {
        while (low < high && arr[high] >= pivot)high--;
        arr[low] = arr[high];//从后面开始找到第一个小于pivot的元素,放到low位置
        while (low < high && arr[low] <= pivot)low++;
        arr[high] = arr[low];//从前面开始找到第一个大于pivot的元素,放到high位置
    }
    arr[low] = pivot;//最后枢纽元放到low的位置
    return high;
}

partition 2

类似于冒泡排序的思想,小于基准的下沉,大于基准的上浮:

int partition2(vector<int>& nums, int i, int j)
{
    int pivot = nums[i];
    int location = i;
    for (int low = i + 1; low <= j; ++low)
    {
        if (nums[low] < pivot) {
            swap(nums[++location], nums[low]);
        }
    }
    swap(nums[location], nums[i]);
    return location;
}

快速排序

void quickSort(vector<int>& arr, int begin, int end) {
    if (begin < end) {
        int p = partition_my(arr, begin, end);
        // int p = partition2(arr, begin, end);
        quickSort(arr, begin, p - 1);
        quickSort(arr, p + 1, end);
    }
}
int main()
{
    vector<int> test{3,2,3,1,2,4,5,5,6};
    quickSort(test, 0, test.size() - 1);
    for (auto t : test) {
        cout << t << " " << endl;
    }
}

利用快排的partition思想解决问题:

leetCode链接:https://leetcode.com/problems/kth-largest-element-in-an-array/submissions/

代码:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        k = nums.size() - k;
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int p = partition_my(nums, left, right);
            if (p == k)break;
            if (p > k){
                right = p - 1;
            }
            if (p < k){
                left = p + 1;
            }
        }
        return nums[k];
    }
 
int partition_my(vector<int>& arr, int begin, int end) {
    int pivot = arr[begin];
    int l = begin, r = end + 1;
    while (l < r)
    {
        while (arr[--r] >= pivot && l < r);
        while (arr[++l] <= pivot && l < r);
        if (l >= r)break;
        swap(arr[l], arr[r]);
    }
    // 这里一定要注意,有时候l != r,所以swap(arr[begin], arr[r])和swap(arr[begin], arr[l]) 是不同的。
    swap(arr[begin], arr[r]); 
    return r;
}
    
    
int partition1(vector<int>&arr, int low, int high)
{
    int pivot = arr[low];//选第一个元素作为枢纽元
    while(low < high)
    {
        while(low < high && arr[high] >= pivot)high--;
        arr[low] = arr[high];//从后面开始找到第一个小于pivot的元素,放到low位置
        while(low < high && arr[low] <= pivot)low++;
        arr[high] = arr[low];//从前面开始找到第一个大于pivot的元素,放到high位置
    }
    arr[low] = pivot;//最后枢纽元放到low的位置
    return high;
}
    
int partition2(vector<int>& nums, int i, int j)
{   
    int pivot = nums[i];
    int location = i ;
    for (int low = i + 1; low <= j; ++low)
    {
        if(nums[low] < pivot){
            swap(nums[++location], nums[low]);
        }
    }
    swap(nums[location], nums[i]);
    return location;
}
};
原文地址:https://www.cnblogs.com/qiang-wei/p/12295005.html