两种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;
}
posted @ 2017-10-23 13:57  whensean  阅读(787)  评论(0)    收藏  举报