快速排序
快速排序 正如它的名字一样,是一种效率较高的排序方法,面试中也经常出现,正常情况下时间复杂度为 O(n * logn)。但是快排是一种不稳定排序算法,排序过程中会打乱元素顺序。
快排的核心是partition算法,partition算法步骤:
- 选取一个元素作为pivot。
- 将小于pivot的元素放在其左边,大于pivot的元素放在其右边
- 分别对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; } };