快速排序

快速排序–概述

Quick Sort

哨兵:Pivot

在这里插入图片描述
比他小扔左边,比他大的扔右边

在这个数组里面就地的分成两个类别

快速排序的第一个要求–做一个分类

我们第一个做的一个19,跟那个去比?

我选的元素就是一个很好的元素吗?
为什么时候Pivot选的不好会到O(N^2)
(2)Pivot飞来飞去

在这里插入图片描述

我们有一个点可以确定的,不管原始的三个数是一个怎么样的大小关系,但是中间的数一定是确定的,我们喜欢的是所某一个固定的位置开始排,这样的算法比较好实现,这样Pivot这个位置在中间36,这个位置不一定是一个合适的位置,因为我们并不知道有几个数比他小,有几个数比他大,怎么办呢,那肯定是要往边上放一放,要注意目前中间这些数字还没有经过排序,两个数交换,没有影响无所谓,所以换到最右边往前一个的位置,所以轴已经到了第三个图的地方,我们不想让轴飞,既然是三个数里面选的中位数,而且经过排序,左边19和右边61就可以不用经过划分了,所以我们只需要关注么有标颜色的点。

在这里插入图片描述

为了解决轴飞来飞去,让下标i指向没有分类的24的位置,j指向没有分类的最右边的位置,所以如果i比轴小,所以不用动,让i向右扫描,当扫到42时比36大,看右边,看95,88比轴大,看7比轴小,分别让两边搜索,不需要与轴换,让两个i,j进行交换,换过就满足比轴小,比轴大的位置,i再一加,j再减,之后换到了之后再i,j,循环应该是到了意外停止,但这个交换是一个常规的操作,应该让i继续向右找,i指向了70这个元素,j找到了8这个元素,这是i进入了右边的位置,j进入了左边的位置,这时候轴的位置就有问题了,所以这时候,i刚刚进入了j的领域就停了,所以目前i指向的位置就是比轴大的元素区域的第一个位置,所以把这两个位置进行一个交换,所以刚刚处在小的和大的中间,快排还要进行什么?左边再进行快排,右边再进行快排



在这里插入图片描述

怎样实现快速排序

首先快速排序给外面的接口应该保持一致
保持一致就是说吧mergeSort改为quickSort
所以我们要写一个quickSort可以把array数组里面的一共11个元素做一次快排
quickSort应该怎么写呢?因为mergeSort也是一个递归,所以我们提供了一个对外的接口,内部去做递归,所以quickSort也是这样去做,也是先提供一个quickSort的接口,承接的参量是*array数组,还有Int size大小
然后它内部去递归

跟归并排序不一样,归并排序需要申请一个临时空间用于归并空间用于归并,而快排不需要,不需要额外的数组进行存储,递归的快速排序,不使用qsort,这个qsort库里面有,我们就使用QSort,这是我们自己定义的一个快速排序,应该怎么排,应该吧array,起始位置是0,结束位置是size-1;

这个递归函数写完,所以我们就要写QSort应该怎么写

QSort(int *a,int left,int right)
a数组里面下标从left开始到right结束包括right的位置进行定义
首先选一个轴元素 int pivot
轴元素还要换到一个合适的位置
最好是写一个函数去实现这个pivot
pivot=medianPivot(a,left,right)选一个中位数的,还要把a数组里面的左中右做一个处理
int medianPivot(int *a,int left,int right)
int mid=(left+right)/2;
要把左中右排个序
left,mid,right排个序
if(a[left]>a[mid>)如果a的left大于mid
所以交换,swap
然后再看,如果左边跟右边的顺序不变,换aleft和aright
经过两个比较,左边的比中间小,左边的比右边小
如果中间的大于tight,进行交换
三个判断,三次交换,就是我们比较典型的把三个数的顺序做一个排序,中间这个数是中位数了
下面

把中位数这个轴换到右边紧挨的位置
swap(a[mid],换到a[right-1]
还完之后返回a[right-1]

写完找轴,我们看QSort来写
如果数比较小的时候,使用插入排序,比较多的时候才使用递归的QSort
在C语言中取宏,在这用一个const,一个常量,叫做cutoff切断,到了什么量之后我们不使用快排,而使用插入
const int cutoff=3

在QSort中,我们找这个数
if(right-left<cutoff)就不用快排,就可以使用插入排序,插入排序是给一个数组和数组大小,但现在我们给定的是left,到right的范围,在InsertionSort(a+left,right-lef+1)

pivot=medianPivot(array,left,right);
pivot找到中位数,并摆放到一个合适的地方
我们从中间区域划分即可,我们这时候需要一个循环变量了,i=left+1,j=pivot-2;
看是不是左边连续比轴小,右边连续比轴大
while(1){
	//左边是不是连续比轴小
	while(a[i]<pivot)i++//这个循环如果退出就是找到左边第一个比轴大的位置
	while(a[j]>pivot)j--;//第一个比轴小的位置
	两个都出来就要交换吗?
	不一定,最后的情况是划分已经完成了,i,j各自列入对方已经扫过的位置,这个时候就不要去交换了,交换的前提*i<j
	if(i<j) swap[a[i],a[j]
	else break;//这时候循环就结束了-》交换
没有-》推出

如果循环条件前置,不好写,

这个循环出来之后就是两个人擦身而过
swap(a[i],a[right-1])交换a[i]和a[right-1]的位置,
之后递归的去写QSOrt
从left开始,到i-1结束
右边的
从i+1开始,到right结束

我们分析一下这样的写法会不会有问题
i,j的初值会不会有问题
当left,和right有问题的时候有问题
所以首先从i==j

}

判断可不可以不用insertionSort
得出的结论:
至少是三个数才使用快排
当left和right小于时要用直接排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上Claire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值