快速排序的划分方法(5种)

快速排序的划分方法(5种)

自己做的笔记,来自看过的博客和刷题的时候的发现。

划分的方法

对于元素进行比较,只有三种结果 >/=/<

所以我们可以假设<pivot的元素是蓝色,==是白色,>是红色

 

数组划分完之后应该是 蓝/蓝白+pivot+红/红白

1、单指针从左向右扫描跳过 蓝白
    最终划分结果: 蓝白混合+pivot+红

    int partition(vector<int>& arr, int l, int r) {
            int pivot = arr[l];  //最左元素 选为pivot
            int pivot_pos = l;//先记录位置
            while (l <= r) // 当左右指针交错时退出循环
            {  
                    if (arr[l] <= pivot) 
                            ++l;//遇到>pivot的元素(红色),就停下
                    else 
                    {
                            swap(arr[l], arr[r]);  // 否则左右指针内容交换
                            --r;  // 右指针--
                    }
            }
            swap(arr[pivot_pos], arr[r]);  // 退出循环时最后把pivot与r交换,此时l与r交错,l指向右部分第一元素,r指向左部分最后元素
            return r;//返回当前pivot位置
    }
    void quickSort(vector<int>& arr, int begin, int end) {
            if (end > begin) //递归终止条件,即只有一个元素,或 end<begin(<0,无元素)时退出
            {
                    int pos = partition(arr, begin, end);
                    quickSort(arr, begin, pos - 1);//继续划左部分
                    quickSort(arr, pos + 1, end);//继续划分右部分
            }
    }


    注:也可以试试只跳过蓝 最终结果会是:蓝+pivot+红白混合
2、单指针从左向右扫描跳过 红白 (第一种变种)
    最终划分结果:蓝+pivot+红白混合

    int partition(vector<int>& arr, int l, int r) {
            int& pivot = arr[r];  //最右元素 选为pivot
            int i = l - 1;//i指向蓝色部分最后一个元素,初始化为l-1表示刚开始蓝色部分元素0个
            while (l <= r) //l用于遍历从最左遍历到最有
            {  
                    if(arr[l] < pivot || l==r)//遇到<pivot的元素(蓝色) 或遍历到pivot,就停下
                    {
                            ++i;//暂时进入红色部分,因为此时l指向蓝色元素
                            swap(arr[i], arr[l]);  //互换,此时i指向蓝色部分最后一个元素
                    }
                    ++l;
            }
            return i;//返回当前pivot位置
    }
    void quickSort(vector<int>& arr, int begin, int end) {
            if (end > begin) //递归终止条件,即只有一个元素,或 end<begin(<0,无元素)时退出
            {
                    int pos = partition(arr, begin, end);
                    quickSort(arr, begin, pos - 1);//继续划左部分
                    quickSort(arr, pos + 1, end);//继续划分右部分
            }
    }


    注:也可以试试只跳过红,碰到蓝白停下 最终结果会是:蓝白混合+pivot+红
3、双指针 互换
    最终划分结果:蓝白混合+pivot+红白混合

    int partition(vector<int> &arr, int l, int r) //进入这个函数必须要至少要2个元素
    {
            int pivot = arr[l];  //最左元素选做pivot
            int pivot_pos = l;
            ++l;
            while (l <= r) {  // 当左右指针交错时退出循环
                    //交错的检测要先放在前面
                    //因为如果l==r且此时指向数组最后一个元素,执行了++l后超出了数组边界
                    //此时l>r可以通过检测停下循环,防止arr[l] <= pivot这个条件访问数组越界
                    while (l <= r && arr[l] <= pivot) ++l;  //两指针交错 或者 找到红色元素 ,就停下
                    while (l <= r &&arr[r] > pivot ) --r;  //两指针交错 或者 找到蓝色元素  ,就停下
                    if (l < r) {  // 如果满足交换条件则交换左右元素
                            swap(arr[l], arr[r]);
                    }
            }
            swap(arr[r], arr[pivot_pos]);  // 最后把主元与右指针的元素交换
            return r;
    }
    
    void quickSort(vector<int>& arr, int begin, int end)
    {
            if (end > begin) {
                    int pos = partition(arr, begin, end);
                    quickSort(arr, begin, pos - 1);
                    quickSort(arr, pos + 1, end);
            }
    }


    注:可以试试  【蓝白混合+pivot+红】  或【蓝+pivot+红白混合】
4、抽位填充(双指针变种)
    最终划分结果: 蓝白混合+pivot+红白混合

    int quickSort(vector<int> &arr, int l, int r) {
            int temp = arr[l];//l位置元素抽出来,做标兵,l位置可当作空位随意填入
            while (l < r) {
                    while (l < r && arr[r] >= temp) r--;//找到<的元素(蓝),就停下
                    arr[l] = arr[r];//填入l之后,r当前位置作新的空位
                    while (l < r && arr[l] <= temp) l++;//找到>的元素(红),就停下
                    arr[r] = arr[l];//填入r之后,l当前位置作新的空位
            }
            arr[l] = temp;
            return l;
    }
    


可以试试  【蓝白混合+pivot+红】  或【蓝+pivot+红白混合】
5、三指针(唯一一个 蓝白红三段分明)
    最终划分结果: 蓝+白+红
    注:白色部分含pivot,位置随意,因为函数不需要返回pivot,只需返回白色部分的第一个和最后一个元素

    void partition(vector<int>& arr, int l, int r, int &equal_begin, int &equal_end) //注意不需要返回pivot位置了
    {
            int pivot = arr[l];  // 最左元素选为pivot
            int equal = l;  // equal是“等于”指针,指向白色部分的第一个元素,因为pivot等于自身,所以equal初始化指向pivot
            while (l <= r) {  // 当左右指针相等时退出循环
                    if (arr[l] == pivot) //若等于pivot,则跳过
                    {
                            ++l;   
                    }
                    else if (arr[l] < pivot) {  // 若小于主元
                            swap(arr[equal], arr[l]);  // 将“等于”指针与左指针的元素交换
                            ++equal;  // “等于”指针++
                            ++l;  // 左指针++
                    }
                    else {  // 若大于主元
                            swap(arr[l], arr[r]);  // 将左指针与右指针的元素交换
                            --r;  // 右指针--
                    }
            }
            //退出循环后l指向 由于l跳过白色元素,所以l会指向白色部分最后一个元素的下一个,即红色部分第一个
            //r与l交错,指向白色部分最后一个
            //equal指向白色部分第一个
            equal_begin = equal;  // equal 指向 白色部分第一个元素
            equal_end = l-1;  // r/l-1 指向 白色部分最后一个元素
    }
    
    void quickSort(vector<int>&arr, int begin, int end) {
            if (end > begin) {
                    int pos1;
                    int pos2;
                    partition(arr, begin, end, pos1, pos2);
                    quickSort(arr, begin, pos1 - 1);
                    quickSort(arr, pos2 + 1, end);
            }
    }

 


    

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值