improved partition in quick sort

original solution

参考算法导论实现的分组算法

int partition(vector<int>& nums, int p, int r) {
    int x = nums[r];
    int s = p - 1;  // the last smaller
    for (int k = p; k < r; ++k) {
        if (nums[k] <= x){
            ++s;
            swap(nums[s], nums[k]);
        }
    }
    ++s;
    swap(nums[r], nums[s]);
    return s;
}

输入
5 2 4 7 5 1 5 9 5 10 5
分组结果
7
5 2 4 5 1 5 5 5 7 10 9

输入
5 5 5 5 5
分组结果
4
5 5 5 5 5

可以看到,第二组输入的分组结果很不均衡,这在会影响快排算法的性能。


improved solution1

在做分组的时候,同时区分大于和小于pivot值的元素。小于pivot值的元素就往左边放,大于pivot值的元素就往右边放,等于pivot的元素放中间。partition结束之后,返回等于pivot值的元素的中间位置。

int partition(vector<int>& nums, int p, int r) {
    int x = nums[r];
    int s = p - 1;  // the last smaller
    int cnt = 0;  // count # number equals to pivot
    for (int k = p; k < r; ++k) {
        if (nums[k] < x){
            swap(nums[s+cnt+1], nums[k]);
            swap(nums[s+cnt+1], nums[s+1]);
            ++s;
        } else if (nums[k] == x) {
            swap(nums[s+cnt+1], nums[k]);
            swap(nums[s+cnt+1], nums[s+1]);
            ++cnt;
        }
    }
    swap(nums[r], nums[s+cnt+1]);
    return s+1+cnt/2;
}

输入
5 2 4 7 5 1 5 9 5 10 5
分组结果
5
2 4 1 5 5 5 5 5 7 10 9

输入
5 5 5 5 5
分组结果
2
5 5 5 5 5

改进的代码的均衡性就好多了。


improved solution2

把较小的数往左边放,较大的数放右边。

// partition array, return the index of pivot
int partition(vector<int>& nums, int p, int r) {
    int x = nums[r];
    int s = p - 1;  // the last smaller
    int l = r;  // the first larger
    for (int k = p; k < l; ++k) {
        if (nums[k] > x) {
            --l;
            swap(nums[l], nums[k]);
            --k;  // nums[k] is new, should do again
        } else if (nums[k] < x){
            ++s;
            swap(nums[s], nums[k]);
        }
    }
    swap(nums[r], nums[l]);
    return (s+1+l)/2;
}

测试输入
5 2 4 7 5 1 5 9 5 10 5
分组结果
5
2 4 1 5 5 5 5 5 10 7 9

测试输入
5 5 5 5 5
分组结果
2
5 5 5 5 5

你可能感兴趣的:(algorithm)