快速排序–概述
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