partition算法有着非常重要的应用,这个算法的思想虽然简单,但具体实现的细节却比较多,今天我重点复习了这个算法,本文记录我对这个算法的理解。
Partition算法解析
二分Partition
快速排序作为非常著名的排序算法,其思想却很简单:每次从数组中选一个数作为pivot,然后将数组划分为2部分,小于等于pivot数的在其左边,大于等于pivot的数在其右边,然后分别对pivot的左边和右边进行递归。
二分partition的实现用到了双指针,left寻找一个比pivot大的数,right寻找一个比pivot小的数,然后交换它们,循环这一过程直到left == right
,将pivot放到这个位置。
注意: 如果pivot选的是最左的元素,则要先移动right;如果pivot选的是最右的元素,则要先移动left。
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[left], base = left;
while (left < right) {
while (left < right && nums[right] >= pivot) right--;
while (left < right && nums[left] <= pivot) left++;
swap(nums[left], nums[right]);
}
nums[base] = nums[left];
nums[left] = pivot;
return left;
}
三分Partition
三分partition自然就是把数组划分成3部分,小于pivot的在左边,等于pivot的在中间,大于pivot的在右边。
由于三分partition要保证中间的那部分,所以像二分partition那么划分是肯定不行的。为了解决这个问题,我们需要先定义循环不变量:
[0, zero)
内的元素都等于0[zero, curr)
内的元素都等于1[curr, two]
内的元素还未被检查(two, len - 1]
内的元素都等于2
我们用curr
来遍历数组,遍历的范围是[0, two]
。在整个遍历过程中,始终要保证循环不变