两种Partition算法
两种Partition算法
Partition算法
partition区间[lo, hi] 前后都是闭区间。 设这个算法返回了下标j, 表示a[lo, j-1] <=a [j], a[j+1, hi] >= a[j] 与a[j]值相同的元素仍然可能遍布整个a[lo, hi]。
如果题目求解只要求特定位置的值,比如求数组中第k大,parti()是没有问题的。 但是遇到要求相同元素连续排列的时候,parti()就不满足要求了。
int parti(std::vector<int> &a, int lo, int hi) {
int i = lo;
int j = hi+1;
int v = a[lo];
while (true) {
while (a[++i]<v)
if (i==hi) break;
while (v<a[--j])
if (j==lo) break;
if (i>=j) break;
swap(a[i], a[j]);
}
swap(a[lo], a[j]);
return j;
}
使用parti()的quicksort,注意这里使用的是[lo, hi], 即前后都是闭区间形式。
void quicksort(std::vector<int> &a, int lo, int hi) {
if (hi<=lo) return;
int j = parti(a, lo, hi);
quicksort(a, lo, j-1);
quicksort(a, j+1, hi);
}
使用parti()的quickselect(使用更简单Partition算法的quickselect在Select 选择算法 - 编程珠玑(续) 笔记中有介绍):
int quickselect(std::vector<int> &a, int k) {
if (k<0 || k>=a.size()) return -1; //并不是好的设计
int lo = 0, hi = a.size()-1;
while (lo < hi) {
swap(a[lo], a[rand()%(hi-lo+1)+lo]);
int i = parti(a, lo, hi);
if (i>k) hi = i - 1;
else if (i<k) lo = i + 1;
else return a[k];
}
return a[k];
}
3-way-partition算法
经过3-way-partition之后,我们以中值val作为划分, 那么最终形成的将是[lo, lt), [lt, gt], (gt, hi]三个划分区间, [lo, lt)区间的元素严格小于val, [lt, gt]区间的元素严格等于val, (gt, hi]区间的元素严格大于val. 所以parti3way()结果中的lo, lt, gt, hi都是有价值的.
quickselect, quicksort算法中可以使用到他们来做判别。 所以,在quicksort3way()和quickselect3way()中, 都没有将parti3way算法单独提取出来。
注意 这里的parti3way返回值是中间划分元素的值。
int parti3way(std::vector<int> &a, int lo, int hi) {
if (hi <= lo) return -1; //并不是好的设计
int lt = lo, gt = hi;
int v = a[lo];
int i = lo;
while (i <= gt) {
if (a[i] < v) swap(a[lt++], a[i++]);
else if (a[i] > v) swap(a[i], a[gt--]);
else i++;
}
return a[i];
}
使用3-way-partition的quickselect
int quickselect3way(std::vector<int> &a, int k) {
if (k<0 || k>=a.size()) return -1; //并不是好的设计
int lo = 0, hi = a.size()-1;
while (lo < hi) {
swap(a[lo], a[rand()%(hi-lo+1)+lo]);
int lt = lo, gt = hi;
int v = a[lo];
int i = lo;
while (i <= gt) {
if (a[i] < v) swap(a[lt++], a[i++]);
else if (a[i] > v) swap(a[i], a[gt--]);
else i++;
}
if (lt>k) hi = lt - 1;
else if (k>gt) lo = gt + 1;
else return a[k];
}
return a[k];
}
使用3-way-partition的quicksort
void quicksort3way(std::vector<int> &a, int lo, int hi) {
if (hi<=lo) return;
int lt = lo, gt = hi;
int v = a[lo];
int i = lo;
while (i <= gt) {
if (a[i] < v) swap(a[lt++], a[i++]);
else if (a[i] > v) swap(a[i], a[gt--]);
else i++;
}
quicksort3way(lo, lt-1);
quicksort3way(gt+1, hi);
return;
}

浙公网安备 33010602011771号