快速排序(快排)

快排

以下是本人的看完下面这一视频后的心得体会,该文章内容大致分为:快排的核心以及视频的快排与408课本上的快排的区别.如果看不懂的地方可以先看下面这位大佬的视频,再回过头来看该文章。若有错误的地方忘各位友友指出!!!🥳🥳🥳
  1. 思路:本质上通过每次递归选取任意一个元素作为枢轴来进行划分(408以第一个元素作为枢轴),将比枢轴小的元素放到枢轴的左边,大的元素放在枢轴的右边(注意!!!左右元素的顺序无所谓,只关心大的在枢轴的右边,小的在枢轴的左边)。因此,每次递归都能确定一个元素在表中的绝对位置,通过递归每次选取一个元素,每次将该元素放在表中的绝对位置,这样就能达到完全排序的效果。

  2. 代码分为两部分

  • void QuickSort(ElemType A[], int low, int high)——对数组进行排序,即主要作用是对枢轴的左右两边的元素进行排序
  • int Partition(ElemType A[], int low, int high)——对数组随机划分,即主要作用是获取枢轴,并将小于枢轴的元素放枢轴左边,大于枢轴的元素放枢轴右边

在这里插入图片描述

在这里插入图片描述

  1. QuickSort明明只是递归调用自身和Partition,为什么能达到对枢轴左右两边的元素进行排序呢?

Partition并没有对元素进行排序的效果,只能达到划分(左,枢轴,右)的区间效果,但QuickSort函数妙就妙其在每次枢轴的左边和右边调用Partition,每次获取一个元素的绝对位置,获取到枢轴左右两边所有元素的绝对位置,等效于对元素进行排序的效果

  1. 递归的过程区间的划分
  • 蓝色部分:小于枢轴
  • 红色部分:大于枢轴
  • 灰色部分:还未比较的元素
  • 黄色部分:枢轴

在408大纲里,用int pivot另存枢轴,数组从外向里缩,这就意味着:数组的左半部分对应于上述的蓝色部分(小于枢轴);中部分对应下面的灰色部分(未比较的元素);数组的右半部分对应于上述的红色部分(大于枢轴);pivot对应于黄色部分。

在这里插入图片描述

  1. pivot与i(对应于408的low)位置互换,再返回枢轴的下标位置

在这里插入图片描述

  1. 视频上的代码是这样的:

    这个代码思路是直接拿最后一个元素当枢轴,Partition返回的i刚好是大于枢轴的第一个元素(右半部分并还未排序),所有Swap不会影响;但如果直接拿第一个元素当枢轴,那么返回的应该是i - 1

//分区:return:枢轴下标。   将小于枢轴的元素放在枢轴左半部,大于放在右半部,无需关系左半部和右半部的排序
int Partition(int A[], int l, int r){
    int pivot_index = r;                    //将表中的最后一个元素认作枢轴
    //该行可交换也可不交换
    int i = l;                          //i作为分割线的下标,也就是比右半部分第一个下标
    for(int j = l; j < r; j++){
        if(A[j] <= A[pivot_index]){         //当元素小于枢轴对应的元素,交换i和j的值,并且i和j一起向前移
            Swap(A[i], A[j]);               
            i++;
        }
    }
    Swap(A[i], A[pivot_index]);              //最后将枢轴与i对应的值进行交换
    return i;                               //返回枢轴下标
}

//快排:对枢轴左右元素进行排序
void QuickSort(int A[], int l, int r){
    if(l >= r)return;   //当表里只有一个元素或者没有元素时,无需排序
    int pivot_index = Partition(A, l, r);   //获取枢轴下标
    QuickSort(A, l, pivot_index - 1);       //对枢轴左半部分进行排序
    QuickSort(A, pivot_index + 1, r);       //对枢轴右半部分进行排序
}
  1. 408代码是这样的

    这个代码思路与上面不同的地方是:其左边是小于枢轴的部分,右边是大于枢轴的部分,中间是未排序的部分,特地用int pivot来保存枢轴;而上面的代码时保存pivot的下标,其左边也是小于枢轴的部分,中间分两部分:一、大于枢轴的部分。二、未排序的部分,最右边第一个是枢轴。

//分区:return:枢轴下标。   将小于枢轴的元素放在枢轴左半部,大于放在右半部,无需关系左半部和右半部的排序
int Partition(int A[], int l, int r){
    int pivot = A[l];           //把表中的第一个元素作为枢轴
    while(l < r){
        while(l < r && A[r] >= pivot)r--;       //在右半部分找到比枢轴小的元素
        A[l] = A[r];                            //将该元素赋值到左边
        while(l < r && A[l] <= pivot)l++;       //在左半部分找到比枢轴大的元素
        A[r] = A[l];                            //将该元素赋值到右边
    }
    A[l] = pivot;                               //l对应的值刚好是大于pivot的右半部分第一个元素
    return l;                                   //返回pivot所在的位置
}

//快排:对枢轴左右元素进行排序
void QuickSort(int A[], int l, int r){
    if(l < r){                                  //表中的元素大于1个才排序
        int pivot_index = Partition(A, l, r);   //获取pivot所在的位置
        QuickSort(A, l, pivot_index - 1);       //对pivot左半部分进行排序
        QuickSort(A, pivot_index + 1, r);       //对pivot右半部分进行排序
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值