关于快排的优化问题

文章探讨了快速排序算法的常规实现及其存在的问题,对比了两种不同的快排写法。针对基本有序和元素基本一致的场景,提出了随机选取主元和调整指针移动的优化方案,以提高排序效率。还介绍了基于C++的数据结构优化方法,并提供了相关测试建议。
摘要由CSDN通过智能技术生成

在昨天做过“数组中第K个最大元素”的题目时,也就是上一篇博客中,我写到了关于快排的一点思考,今天再次对快排的一些存在问题进行一些优化

首先呢,先写一下最常规朴素的快排代码:

void quick_sort(int *q, int l, int r) {
    if (l >= r) return;
    int x = q[l], i = l, j = r;
    while (i < j) {
        while (i < j && q[j] >= x) j--;
        q[i] = q[j];
        while (i < j && q[i] <= x) i++;
        q[j] = q[i];
    }
    q[i] = x;
    quick_sort(q, l, i - 1);
    quick_sort(q, i + 1, r);
}

这里的代码与上一篇的均有所不同,但又有一些的微小的差异,相比较而言,这种风格形式的代码,在选取哨兵主元后,移动指针的顺序是固定的,否则出现错误

然后需要提一下,上一篇博客的两种写法:
第一种:
这种类型的写法,与上面是相似的,都是最终指针会相遇到一个位置而不是交错开来,更方便对排序的位置进行获取,同时这种写法也无需在意哨兵主元的选取和指针移动的顺序,但是,该写法在后续优化过程中并不适合

void Quick_Sort(vector<int>& arr, int begin, int end){
    if(begin == end) return ;
    int tmp = arr[begin];
    int i = begin;
    int j = end;
    while(i != j){
        while(arr[j--] <= tmp && j > i)
        while(arr[i++] >= tmp && j > i)
        if(j > i){
            swap(arr[i],arr[j]);
        }
    }
    arr[begin] = arr[i];
    arr[i] = tmp;
    Quick_Sort(arr, begin, i-1);
    Quick_Sort(arr, i+1, end);
}

第二种:
结束条件的状态为指针的交错状态,不易辨别具体的元素的位置,但是可以解决,数组元素基本一致的情况

void Quick_Sort2(int *arr, int begin, int end) {
    if (begin >= end) return;
    int x = arr[begin], i = begin, j = end;  //定义初始化分界点和左右指针
    while (i < j) {
        while (arr[j] > x) j--;
        while (arr[i] < x) i++;    //移动左右指针
        if (i < j) swap(arr[i], arr[j]);
    }
    Quick_Sort2(arr, begin, j);      //递归处理左右两段
    Quick_Sort2(arr, j + 1, end);
}

接下来,关于快排的优化,众所周知,快排在解决两种情况的时候会很乏力,一种是基本有序,另一种是基本一致,基于这两种情况,对快排的代码进行优化改进(可以直接记下来当做模板)

void quicker_sort(int *q, int l, int r) {
    if (l >= r) return;
    // 将主元选取的位置更改为随机选取,可以有效解决数组元素基本一致的情况
    int flag = rand() % (r - l + 1) + l;
    swap(q[l], q[flag]);

    int x = q[l], i = l, j = r;
    while (i < j) {
        while (i < j && q[j] > x) j--; // 去掉等号
        if (i < j) { // 增加交换频率,加速排序速度
            q[i] = q[j];
            i++;
        }
        while (i < j && q[i] < x) i++;// 去掉等号
        if (i < j) {
            q[j] = q[i];
            j--;
        }
    }
    q[i] = x;
    quick_sort(q, l, i - 1);
    quick_sort(q, i + 1, r);
}

当然,也可以使用数据结构书上的关于快排的基于C语言的代码逻辑改进,但是,由于不太符合我的代码书写习惯,因此,大多数情况下并不喜欢使用

class Solution {
    int partition(vector<int>& nums, int l, int r) {
        int pivot = nums[r];
        int i = l - 1;
        for (int j = l; j <= r - 1; ++j) {
            if (nums[j] <= pivot) {
                i = i + 1;
                swap(nums[i], nums[j]);
            }
        }
        swap(nums[i + 1], nums[r]);
        return i + 1;
    }
    int randomized_partition(vector<int>& nums, int l, int r) {
        int i = rand() % (r - l + 1) + l; // 随机选一个作为我们的主元
        swap(nums[r], nums[i]);
        return partition(nums, l, r);
    }
    void randomized_quicksort(vector<int>& nums, int l, int r) {
        if (l < r) {
            int pos = randomized_partition(nums, l, r);
            randomized_quicksort(nums, l, pos - 1);
            randomized_quicksort(nums, pos + 1, r);
        }
    }
public:
    vector<int> sortArray(vector<int>& nums) {
        srand((unsigned)time(NULL));
        randomized_quicksort(nums, 0, (int)nums.size() - 1);
        return nums;
    }
};

最后,关于排序算法的相关测试,可以用排序数组这道题测试一下你习惯的排序写法速度上是否合格

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值